diff --git a/.gitignore b/.gitignore index b15c864..d2133c1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,6 @@ dist/ .env.local .DS_Store coverage/ +.astro/ +.vercel/ +package-lock.json diff --git a/packages/widget/src/dom/panel.ts b/packages/widget/src/dom/panel.ts index fbb9d2e..749a2e6 100644 --- a/packages/widget/src/dom/panel.ts +++ b/packages/widget/src/dom/panel.ts @@ -6,6 +6,7 @@ const CLOSE_ICON = ` export interface PanelOptions { position: 'bottom-right' | 'bottom-left'; + inline?: boolean; branding: { name: string; avatar?: string; @@ -25,6 +26,9 @@ export class Panel { constructor(root: ShadowRoot, options: PanelOptions) { this.el = document.createElement('div'); this.el.className = 'cc-panel'; + if (options.inline) { + this.el.classList.add('cc-inline'); + } if (options.position === 'bottom-left') { this.el.classList.add('cc-left'); } @@ -51,12 +55,14 @@ export class Panel { info.innerHTML = `
${this.escapeHtml(options.branding.name)}
${this.escapeHtml(options.branding.subtitle)}
`; header.appendChild(info); - const closeBtn = document.createElement('button'); - closeBtn.className = 'cc-header-close'; - closeBtn.setAttribute('aria-label', 'Close chat'); - closeBtn.innerHTML = CLOSE_ICON; - closeBtn.addEventListener('click', options.onClose); - header.appendChild(closeBtn); + if (!options.inline) { + const closeBtn = document.createElement('button'); + closeBtn.className = 'cc-header-close'; + closeBtn.setAttribute('aria-label', 'Close chat'); + closeBtn.innerHTML = CLOSE_ICON; + closeBtn.addEventListener('click', options.onClose); + header.appendChild(closeBtn); + } this.el.appendChild(header); diff --git a/packages/widget/src/dom/shadow.ts b/packages/widget/src/dom/shadow.ts index b5e1046..30688b7 100644 --- a/packages/widget/src/dom/shadow.ts +++ b/packages/widget/src/dom/shadow.ts @@ -1,9 +1,14 @@ import widgetStyles from '../styles/widget.css?inline'; -export function createShadowRoot(): ShadowRoot { +export function createShadowRoot(container?: HTMLElement): ShadowRoot { const host = document.createElement('div'); host.id = 'chatcops-root'; - document.body.appendChild(host); + + if (container) { + container.appendChild(host); + } else { + document.body.appendChild(host); + } const shadow = host.attachShadow({ mode: 'open' }); @@ -14,7 +19,8 @@ export function createShadowRoot(): ShadowRoot { return shadow; } -export function destroyShadowRoot(): void { - const host = document.getElementById('chatcops-root'); +export function destroyShadowRoot(container?: HTMLElement): void { + const searchRoot = container ?? document.body; + const host = searchRoot.querySelector('#chatcops-root') ?? document.getElementById('chatcops-root'); if (host) host.remove(); } diff --git a/packages/widget/src/index.ts b/packages/widget/src/index.ts index ef22384..ca6b34e 100644 --- a/packages/widget/src/index.ts +++ b/packages/widget/src/index.ts @@ -1,6 +1,6 @@ import { Widget, type WidgetConfig } from './widget.js'; -export type { WidgetConfig } from './widget.js'; +export { Widget, type WidgetConfig } from './widget.js'; let instance: Widget | null = null; @@ -44,8 +44,13 @@ function autoInit(): void { const apiUrl = script.dataset.apiUrl; if (!apiUrl) return; + const mode = script.dataset.mode as 'popup' | 'inline' | undefined; + const container = script.dataset.container; + ChatCops.init({ apiUrl, + mode: mode || undefined, + container: container || undefined, theme: { accent: script.dataset.accent, textColor: script.dataset.textColor, @@ -66,6 +71,11 @@ function autoInit(): void { delay: script.dataset.welcomeBubbleDelay ? parseInt(script.dataset.welcomeBubbleDelay, 10) : undefined, } : undefined, + autoOpen: script.dataset.autoOpen !== undefined + ? (script.dataset.autoOpen === '' || script.dataset.autoOpen === 'true' + ? true + : parseInt(script.dataset.autoOpen, 10) || true) + : undefined, placeholder: script.dataset.placeholder, locale: script.dataset.locale, }); diff --git a/packages/widget/src/styles/widget.css b/packages/widget/src/styles/widget.css index ce2d242..7f54bb6 100644 --- a/packages/widget/src/styles/widget.css +++ b/packages/widget/src/styles/widget.css @@ -131,6 +131,26 @@ left: 20px; } +/* Inline mode */ +.cc-panel.cc-inline { + position: relative; + bottom: auto; + right: auto; + left: auto; + width: 100%; + height: 100%; + max-height: 100%; + z-index: auto; + opacity: 1; + transform: none; + pointer-events: auto; + transition: none; +} + +.cc-panel.cc-inline.cc-visible { + transform: none; +} + /* Panel header */ .cc-header { display: flex; @@ -451,7 +471,7 @@ /* Mobile */ @media (max-width: 768px) { - .cc-panel { + .cc-panel:not(.cc-inline) { width: 100%; height: 100%; max-height: 100%; @@ -462,7 +482,7 @@ border: none; } - .cc-panel.cc-left { + .cc-panel.cc-left:not(.cc-inline) { left: 0; } diff --git a/packages/widget/src/widget.ts b/packages/widget/src/widget.ts index b0d9c0c..7e563b9 100644 --- a/packages/widget/src/widget.ts +++ b/packages/widget/src/widget.ts @@ -10,6 +10,8 @@ import type { MessageData } from './dom/messages.js'; export interface WidgetConfig { apiUrl: string; + mode?: 'popup' | 'inline'; + container?: string | HTMLElement; theme?: { accent?: string; textColor?: string; @@ -33,6 +35,7 @@ export interface WidgetConfig { persistHistory?: boolean; maxMessages?: number; pageContext?: boolean; + autoOpen?: boolean | number; locale?: string; strings?: Partial; onOpen?: () => void; @@ -47,7 +50,7 @@ type WidgetEventHandler = (...args: unknown[]) => void; export class Widget { private config: WidgetConfig; private shadow!: ShadowRoot; - private fab!: FAB; + private fab?: FAB; private panel!: Panel; private bubble?: WelcomeBubble; private client: ChatClient; @@ -57,6 +60,11 @@ export class Widget { private messages: MessageData[] = []; private isStreaming = false; private eventHandlers = new Map>(); + private containerEl?: HTMLElement; + + get isInline(): boolean { + return this.config.mode === 'inline'; + } constructor(config: WidgetConfig) { this.config = config; @@ -66,8 +74,27 @@ export class Widget { this.conversationId = this.storage.getSessionId(); } + private resolveContainer(): HTMLElement { + if (!this.config.container) { + throw new Error('ChatCops: "container" is required when mode is "inline"'); + } + if (typeof this.config.container === 'string') { + const el = document.querySelector(this.config.container); + if (!el) { + throw new Error(`ChatCops: container element not found: ${this.config.container}`); + } + return el as HTMLElement; + } + return this.config.container; + } + init(): void { - this.shadow = createShadowRoot(); + if (this.isInline) { + this.containerEl = this.resolveContainer(); + this.shadow = createShadowRoot(this.containerEl); + } else { + this.shadow = createShadowRoot(); + } if (this.config.theme) { applyTheme(this.shadow, this.config.theme); @@ -75,13 +102,17 @@ export class Widget { const position = this.config.theme?.position ?? 'bottom-right'; - this.fab = new FAB(this.shadow, { - position, - onClick: () => this.toggle(), - }); + // FAB — popup mode only + if (!this.isInline) { + this.fab = new FAB(this.shadow, { + position, + onClick: () => this.toggle(), + }); + } this.panel = new Panel(this.shadow, { position, + inline: this.isInline, branding: { name: this.config.branding?.name ?? 'AI Assistant', avatar: this.config.branding?.avatar, @@ -117,8 +148,8 @@ export class Widget { this.panel.addMessage(welcomeMsg); } - // Welcome bubble - if (this.config.welcomeBubble) { + // Welcome bubble — popup mode only + if (!this.isInline && this.config.welcomeBubble) { this.bubble = new WelcomeBubble(this.shadow, { text: this.config.welcomeBubble.text, delay: this.config.welcomeBubble.delay, @@ -127,20 +158,35 @@ export class Widget { onClick: () => this.open(), }); } + + // Inline mode — show panel immediately + if (this.isInline) { + this.panel.show(); + } + + // Auto-open — popup mode only + if (!this.isInline && this.config.autoOpen !== undefined && this.config.autoOpen !== false) { + const delay = typeof this.config.autoOpen === 'number' ? this.config.autoOpen : 0; + setTimeout(() => this.open(), delay); + } } open(): void { this.panel.show(); - this.fab.setOpen(true); - this.fab.hideBadge(); - this.bubble?.hide(); + if (!this.isInline) { + this.fab?.setOpen(true); + this.fab?.hideBadge(); + this.bubble?.hide(); + } this.config.onOpen?.(); this.emit('open'); } close(): void { this.panel.hide(); - this.fab.setOpen(false); + if (!this.isInline) { + this.fab?.setOpen(false); + } this.config.onClose?.(); this.emit('close'); } @@ -156,8 +202,8 @@ export class Widget { destroy(): void { this.bubble?.destroy(); this.panel.destroy(); - this.fab.destroy(); - destroyShadowRoot(); + this.fab?.destroy(); + destroyShadowRoot(this.containerEl); this.eventHandlers.clear(); this.messages = []; } @@ -242,8 +288,8 @@ export class Widget { this.config.onMessage?.(assistantMsg); this.emit('message', assistantMsg); - if (!this.panel.isVisible) { - this.fab.showBadge(); + if (!this.isInline && !this.panel.isVisible) { + this.fab?.showBadge(); } } } catch (err) { diff --git a/packages/widget/vite.config.ts b/packages/widget/vite.config.ts index 54a420a..65f06cc 100644 --- a/packages/widget/vite.config.ts +++ b/packages/widget/vite.config.ts @@ -14,6 +14,7 @@ export default defineConfig({ rollupOptions: { output: { inlineDynamicImports: true, + exports: 'named', }, }, }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4eeda17..07860bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,13 +87,25 @@ importers: version: 4.4.2(@types/node@25.3.3)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(jiti@2.6.1)(lightningcss@1.31.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(terser@5.46.0)(yaml@2.8.2) '@astrojs/starlight': specifier: ^0.34.0 - version: 0.34.8(astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) + version: 0.34.8(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) + '@astrojs/vercel': + specifier: ^9.0.4 + version: 9.0.4(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))(react@19.2.4)(rollup@4.59.0) + '@chatcops/core': + specifier: ^0.2.0 + version: 0.2.0 + '@chatcops/server': + specifier: ^0.2.0 + version: 0.2.0(express@5.2.1) + '@chatcops/widget': + specifier: workspace:^ + version: link:../packages/widget '@tailwindcss/vite': specifier: ^4.2.1 version: 4.2.1(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(yaml@2.8.2)) astro: specifier: ^5.7.0 - version: 5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + version: 5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) motion: specifier: ^12.35.0 version: 12.35.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -174,6 +186,11 @@ packages: resolution: {integrity: sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==} engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0} + '@astrojs/vercel@9.0.4': + resolution: {integrity: sha512-Nn5c0CODcx69FnNUhAcAhlDQ/Je2lLrlPmbMMI77ZvLMfyZI5NZyKD7MiKEeaYK/VTnx6fNI5rFHm6seqEPRtQ==} + peerDependencies: + astro: ^5.0.0 + '@babel/code-frame@7.29.0': resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} @@ -320,6 +337,17 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@chatcops/core@0.2.0': + resolution: {integrity: sha512-+kcCOtq9JZKtT4kH+/L6yFkpSij3D7gxo0sbvITvKOSonPJhk/Eop5AU0pOOAukF7wCiyZIfq6Vta6tFWTTYhg==} + + '@chatcops/server@0.2.0': + resolution: {integrity: sha512-uaHehVQ9r0fuUaQKllh9nQbkjjbeVPaxqUOesK1DW0X7cteclgBOFsY68K4B3xBpCKVws8MxLmQkotvtUX0WtQ==} + peerDependencies: + express: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + express: + optional: true + '@ctrl/tinycolor@4.2.0': resolution: {integrity: sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==} engines: {node: '>=14'} @@ -915,6 +943,14 @@ packages: '@types/node': optional: true + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -940,6 +976,11 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} + '@mapbox/node-pre-gyp@2.0.3': + resolution: {integrity: sha512-uwPAhccfFJlsfCxMYTwOdVfOz3xqyj8xYL3zJj8f0pb30tLohnnFPhLuqp4/qoEz8sNxe4SESZedcBojRefIzg==} + engines: {node: '>=18'} + hasBin: true + '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} @@ -991,6 +1032,10 @@ packages: cpu: [x64] os: [win32] + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + '@rolldown/pluginutils@1.0.0-beta.27': resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} @@ -1346,6 +1391,53 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@vercel/analytics@1.6.1': + resolution: {integrity: sha512-oH9He/bEM+6oKlv3chWuOOcp8Y6fo6/PSro8hEkgCW3pu9/OiCXiUpRUogDh3Fs3LH2sosDrx8CxeOLBEE+afg==} + peerDependencies: + '@remix-run/react': ^2 + '@sveltejs/kit': ^1 || ^2 + next: '>= 13' + react: ^18 || ^19 || ^19.0.0-rc + svelte: '>= 4' + vue: ^3 + vue-router: ^4 + peerDependenciesMeta: + '@remix-run/react': + optional: true + '@sveltejs/kit': + optional: true + next: + optional: true + react: + optional: true + svelte: + optional: true + vue: + optional: true + vue-router: + optional: true + + '@vercel/functions@2.2.13': + resolution: {integrity: sha512-14ArBSIIcOBx9nrEgaJb4Bw+en1gl6eSoJWh8qjifLl5G3E4dRXCFOT8HP+w66vb9Wqyd1lAQBrmRhRwOj9X9A==} + engines: {node: '>= 18'} + peerDependencies: + '@aws-sdk/credential-provider-web-identity': '*' + peerDependenciesMeta: + '@aws-sdk/credential-provider-web-identity': + optional: true + + '@vercel/nft@0.30.4': + resolution: {integrity: sha512-wE6eAGSXScra60N2l6jWvNtVK0m+sh873CpfZW4KI2v8EHuUQp+mSEi4T+IcdPCSEDgCdAS/7bizbhQlkjzrSA==} + engines: {node: '>=18'} + hasBin: true + + '@vercel/oidc@2.0.2': + resolution: {integrity: sha512-59PBFx3T+k5hLTEWa3ggiMpGRz1OVvl9eN8SUai+A43IsqiOuAe7qPBf+cray/Fj6mkgnxm/D7IAtjc8zSHi7g==} + engines: {node: '>= 18'} + + '@vercel/routing-utils@5.3.3': + resolution: {integrity: sha512-KYm2sLNUD48gDScv8ob4ejc3Gww2jcJyW80hTdYlenAPz/5BQar1Gyh38xrUuZ532TUwSb5mV1uRbAuiykq0EQ==} + '@vitejs/plugin-react@4.7.0': resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} engines: {node: ^14.18.0 || >=16.0.0} @@ -1381,6 +1473,10 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + abort-controller@3.0.0: resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} engines: {node: '>=6.5'} @@ -1389,6 +1485,11 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1399,10 +1500,17 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + agentkeepalive@4.6.0: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -1418,6 +1526,10 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -1464,6 +1576,9 @@ packages: engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true + async-sema@3.1.1: + resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1474,6 +1589,9 @@ packages: bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + base-64@1.0.0: resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} @@ -1492,6 +1610,9 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -1503,6 +1624,9 @@ packages: resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} engines: {node: '>=18'} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1572,6 +1696,10 @@ packages: resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} engines: {node: '>= 20.19.0'} + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + ci-info@4.4.0: resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} @@ -1618,6 +1746,10 @@ packages: common-ancestor-path@1.0.1: resolution: {integrity: sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + content-disposition@1.0.1: resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} engines: {node: '>=18'} @@ -1769,6 +1901,9 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -1781,6 +1916,9 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} @@ -1904,10 +2042,16 @@ packages: extendable-error@0.1.7: resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-glob@3.3.3: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -1920,6 +2064,9 @@ packages: picomatch: optional: true + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -1943,6 +2090,10 @@ packages: resolution: {integrity: sha512-piJxbLnkD9Xcyi7dWJRnqszEURixe7CrF/efBfbffe2DPyabmuIuqraruY8cXTs19QoM8VJzx47BDRVNXETM7Q==} engines: {node: '>=20'} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + form-data-encoder@1.7.2: resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} @@ -2015,6 +2166,11 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -2121,6 +2277,10 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + human-id@4.1.3: resolution: {integrity: sha512-tsYlhAYpjCKa//8rXZ9DqKEawhPoSytweBC2eNvcaDK+57RZLHGqNs3PZTQO6yekLFSuvA6AlnAfrw1uBvtb+Q==} hasBin: true @@ -2218,6 +2378,9 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -2241,6 +2404,9 @@ packages: engines: {node: '>=6'} hasBin: true + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} @@ -2340,6 +2506,9 @@ packages: loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + lru-cache@11.2.6: resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} engines: {node: 20 || >=22} @@ -2564,6 +2733,18 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + motion-dom@12.35.0: resolution: {integrity: sha512-FFMLEnIejK/zDABn+vqGVAUN4T0+3fw+cVAY8MMT65yR+j5uMuvWdd4npACWhh94OVWQs79CrBBuwOwGRZAQiA==} @@ -2628,12 +2809,21 @@ packages: encoding: optional: true + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-mock-http@1.0.4: resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} node-releases@2.0.36: resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} + nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -2711,6 +2901,9 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@0.2.11: resolution: {integrity: sha512-BEnLolu+yuz22S56CU1SUKq3XC3PkwD5wv4ikR4MfGvnRVcmzXR9DwSlW2fEamyTPyXHomBJRzgapeuBvRNzJQ==} @@ -2742,6 +2935,16 @@ packages: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-to-regexp@6.1.0: + resolution: {integrity: sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==} + + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} + path-to-regexp@8.3.0: resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} @@ -2808,6 +3011,10 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + qs@6.15.0: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} @@ -3080,6 +3287,10 @@ packages: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -3120,6 +3331,10 @@ packages: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tar@7.5.10: + resolution: {integrity: sha512-8mOPs1//5q/rlkNSPcCegA6hiHJYDmSLEI8aMH/CdSQJNWztHC9WHNam5zdQlfpTwB9Xp7IBEsHfV5LKMJGVAw==} + engines: {node: '>=18'} + term-size@2.2.1: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} @@ -3328,6 +3543,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -3464,6 +3682,14 @@ packages: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + wrap-ansi@9.0.2: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} @@ -3477,6 +3703,10 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -3559,12 +3789,12 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/mdx@4.3.13(astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))': + '@astrojs/mdx@4.3.13(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))': dependencies: '@astrojs/markdown-remark': 6.3.10 '@mdx-js/mdx': 3.1.1 acorn: 8.16.0 - astro: 5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + astro: 5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) es-module-lexer: 1.7.0 estree-util-visit: 2.0.0 hast-util-to-html: 9.0.5 @@ -3611,17 +3841,17 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.25.76 - '@astrojs/starlight@0.34.8(astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))': + '@astrojs/starlight@0.34.8(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))': dependencies: '@astrojs/markdown-remark': 6.3.10 - '@astrojs/mdx': 4.3.13(astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) + '@astrojs/mdx': 4.3.13(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) '@astrojs/sitemap': 3.7.0 '@pagefind/default-ui': 1.4.0 '@types/hast': 3.0.4 '@types/js-yaml': 4.0.9 '@types/mdast': 4.0.4 - astro: 5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) - astro-expressive-code: 0.41.7(astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) + astro: 5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + astro-expressive-code: 0.41.7(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)) bcp-47: 2.1.0 hast-util-from-html: 2.0.3 hast-util-select: 6.0.4 @@ -3656,6 +3886,29 @@ snapshots: transitivePeerDependencies: - supports-color + '@astrojs/vercel@9.0.4(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2))(react@19.2.4)(rollup@4.59.0)': + dependencies: + '@astrojs/internal-helpers': 0.7.5 + '@vercel/analytics': 1.6.1(react@19.2.4) + '@vercel/functions': 2.2.13 + '@vercel/nft': 0.30.4(rollup@4.59.0) + '@vercel/routing-utils': 5.3.3 + astro: 5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + esbuild: 0.25.12 + tinyglobby: 0.2.15 + transitivePeerDependencies: + - '@aws-sdk/credential-provider-web-identity' + - '@remix-run/react' + - '@sveltejs/kit' + - encoding + - next + - react + - rollup + - supports-color + - svelte + - vue + - vue-router + '@babel/code-frame@7.29.0': dependencies: '@babel/helper-validator-identifier': 7.28.5 @@ -3917,6 +4170,23 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@chatcops/core@0.2.0': + dependencies: + '@anthropic-ai/sdk': 0.39.0 + '@google/generative-ai': 0.21.0 + openai: 4.104.0(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - encoding + - ws + + '@chatcops/server@0.2.0(express@5.2.1)': + dependencies: + '@chatcops/core': link:packages/core + zod: 3.25.76 + optionalDependencies: + express: 5.2.1 + '@ctrl/tinycolor@4.2.0': {} '@emnapi/runtime@1.8.1': @@ -4292,6 +4562,19 @@ snapshots: optionalDependencies: '@types/node': 25.3.3 + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4332,6 +4615,19 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 + '@mapbox/node-pre-gyp@2.0.3': + dependencies: + consola: 3.4.2 + detect-libc: 2.1.2 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.4 + tar: 7.5.10 + transitivePeerDependencies: + - encoding + - supports-color + '@mdx-js/mdx@3.1.1': dependencies: '@types/estree': 1.0.8 @@ -4396,6 +4692,9 @@ snapshots: '@pagefind/windows-x64@1.4.0': optional: true + '@pkgjs/parseargs@0.11.0': + optional: true + '@rolldown/pluginutils@1.0.0-beta.27': {} '@rollup/pluginutils@5.3.0(rollup@4.59.0)': @@ -4710,6 +5009,45 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@vercel/analytics@1.6.1(react@19.2.4)': + optionalDependencies: + react: 19.2.4 + + '@vercel/functions@2.2.13': + dependencies: + '@vercel/oidc': 2.0.2 + + '@vercel/nft@0.30.4(rollup@4.59.0)': + dependencies: + '@mapbox/node-pre-gyp': 2.0.3 + '@rollup/pluginutils': 5.3.0(rollup@4.59.0) + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + async-sema: 3.1.1 + bindings: 1.5.0 + estree-walker: 2.0.2 + glob: 10.5.0 + graceful-fs: 4.2.11 + node-gyp-build: 4.8.4 + picomatch: 4.0.3 + resolve-from: 5.0.0 + transitivePeerDependencies: + - encoding + - rollup + - supports-color + + '@vercel/oidc@2.0.2': + dependencies: + '@types/ms': 2.1.0 + ms: 2.1.3 + + '@vercel/routing-utils@5.3.3': + dependencies: + path-to-regexp: 6.1.0 + path-to-regexp-updated: path-to-regexp@6.3.0 + optionalDependencies: + ajv: 6.14.0 + '@vitejs/plugin-react@4.7.0(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.29.0 @@ -4764,6 +5102,8 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 + abbrev@3.0.1: {} + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -4773,16 +5113,30 @@ snapshots: mime-types: 3.0.2 negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 acorn@8.16.0: {} + agent-base@7.1.4: {} + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + optional: true + ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -4793,6 +5147,10 @@ snapshots: ansi-regex@6.2.2: {} + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + ansi-styles@6.2.3: {} anymatch@3.1.3: @@ -4818,12 +5176,12 @@ snapshots: astring@1.9.0: {} - astro-expressive-code@0.41.7(astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)): + astro-expressive-code@0.41.7(astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2)): dependencies: - astro: 5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) + astro: 5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2) rehype-expressive-code: 0.41.7 - astro@5.18.0(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2): + astro@5.18.0(@types/node@25.3.3)(@vercel/functions@2.2.13)(jiti@2.6.1)(lightningcss@1.31.1)(rollup@4.59.0)(terser@5.46.0)(typescript@5.9.3)(yaml@2.8.2): dependencies: '@astrojs/compiler': 2.13.1 '@astrojs/internal-helpers': 0.7.5 @@ -4878,7 +5236,7 @@ snapshots: ultrahtml: 1.6.0 unifont: 0.7.4 unist-util-visit: 5.1.0 - unstorage: 1.17.4 + unstorage: 1.17.4(@vercel/functions@2.2.13) vfile: 6.0.3 vite: 6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(yaml@2.8.2) vitefu: 1.1.2(vite@6.4.1(@types/node@25.3.3)(jiti@2.6.1)(lightningcss@1.31.1)(terser@5.46.0)(yaml@2.8.2)) @@ -4925,12 +5283,16 @@ snapshots: - uploadthing - yaml + async-sema@3.1.1: {} + asynckit@0.4.0: {} axobject-query@4.1.0: {} bail@2.0.2: {} + balanced-match@1.0.2: {} + base-64@1.0.0: {} baseline-browser-mapping@2.10.0: {} @@ -4947,6 +5309,10 @@ snapshots: dependencies: is-windows: 1.0.2 + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -4974,6 +5340,10 @@ snapshots: widest-line: 5.0.0 wrap-ansi: 9.0.2 + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -5034,6 +5404,8 @@ snapshots: dependencies: readdirp: 5.0.0 + chownr@3.0.0: {} + ci-info@4.4.0: {} cli-boxes@3.0.0: {} @@ -5070,6 +5442,8 @@ snapshots: common-ancestor-path@1.0.1: {} + consola@3.4.2: {} + content-disposition@1.0.1: {} content-type@1.0.5: {} @@ -5194,6 +5568,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + eastasianwidth@0.2.0: {} + ee-first@1.1.1: {} electron-to-chromium@1.5.307: {} @@ -5202,6 +5578,8 @@ snapshots: emoji-regex@8.0.0: {} + emoji-regex@9.2.2: {} + encodeurl@2.0.0: {} enhanced-resolve@5.20.0: @@ -5402,6 +5780,9 @@ snapshots: extendable-error@0.1.7: {} + fast-deep-equal@3.1.3: + optional: true + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 @@ -5410,6 +5791,9 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 + fast-json-stable-stringify@2.1.0: + optional: true + fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -5418,6 +5802,8 @@ snapshots: optionalDependencies: picomatch: 4.0.3 + file-uri-to-path@1.0.0: {} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -5448,6 +5834,11 @@ snapshots: dependencies: tiny-inflate: 1.0.3 + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + form-data-encoder@1.7.2: {} form-data@4.0.5: @@ -5521,6 +5912,15 @@ snapshots: dependencies: is-glob: 4.0.3 + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + globby@11.1.0: dependencies: array-union: 2.1.0 @@ -5766,6 +6166,13 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + human-id@4.1.3: {} humanize-ms@1.2.1: @@ -5837,6 +6244,12 @@ snapshots: isexe@2.0.0: {} + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + jiti@2.6.1: {} js-tokens@4.0.0: {} @@ -5854,6 +6267,9 @@ snapshots: jsesc@3.1.0: {} + json-schema-traverse@0.4.1: + optional: true + json5@2.2.3: {} jsonfile@4.0.0: @@ -5923,6 +6339,8 @@ snapshots: loupe@3.2.1: {} + lru-cache@10.4.3: {} + lru-cache@11.2.6: {} lru-cache@5.1.1: @@ -6429,6 +6847,16 @@ snapshots: dependencies: mime-db: 1.54.0 + minimatch@9.0.9: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + motion-dom@12.35.0: dependencies: motion-utils: 12.29.2 @@ -6467,10 +6895,16 @@ snapshots: dependencies: whatwg-url: 5.0.0 + node-gyp-build@4.8.4: {} + node-mock-http@1.0.4: {} node-releases@2.0.36: {} + nopt@8.1.0: + dependencies: + abbrev: 3.0.1 + normalize-path@3.0.0: {} nth-check@2.1.1: @@ -6546,6 +6980,8 @@ snapshots: p-try@2.2.0: {} + package-json-from-dist@1.0.1: {} + package-manager-detector@0.2.11: dependencies: quansync: 0.2.11 @@ -6590,6 +7026,15 @@ snapshots: path-key@3.1.1: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-to-regexp@6.1.0: {} + + path-to-regexp@6.3.0: {} + path-to-regexp@8.3.0: {} path-type@4.0.0: {} @@ -6640,6 +7085,9 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + punycode@2.3.1: + optional: true + qs@6.15.0: dependencies: side-channel: 1.1.0 @@ -7084,6 +7532,12 @@ snapshots: is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + string-width@7.2.0: dependencies: emoji-regex: 10.6.0 @@ -7131,6 +7585,14 @@ snapshots: tapable@2.3.0: {} + tar@7.5.10: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + term-size@2.2.1: {} terser@5.46.0: @@ -7263,7 +7725,7 @@ snapshots: unpipe@1.0.0: {} - unstorage@1.17.4: + unstorage@1.17.4(@vercel/functions@2.2.13): dependencies: anymatch: 3.1.3 chokidar: 5.0.0 @@ -7273,6 +7735,8 @@ snapshots: node-fetch-native: 1.6.7 ofetch: 1.5.1 ufo: 1.6.3 + optionalDependencies: + '@vercel/functions': 2.2.13 update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: @@ -7280,6 +7744,11 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + optional: true + util-deprecate@1.0.2: {} vary@1.1.2: {} @@ -7413,6 +7882,18 @@ snapshots: dependencies: string-width: 7.2.0 + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 @@ -7425,6 +7906,8 @@ snapshots: yallist@3.1.1: {} + yallist@5.0.0: {} + yaml@2.8.2: optional: true diff --git a/vercel.json b/vercel.json new file mode 100644 index 0000000..8d2591a --- /dev/null +++ b/vercel.json @@ -0,0 +1,5 @@ +{ + "installCommand": "corepack enable && pnpm install", + "buildCommand": "pnpm -r build", + "outputDirectory": "website/.vercel/output" +} diff --git a/website/.astro/content-modules.mjs b/website/.astro/content-modules.mjs deleted file mode 100644 index 771e0a3..0000000 --- a/website/.astro/content-modules.mjs +++ /dev/null @@ -1,22 +0,0 @@ - -export default new Map([ -["src/content/docs/index.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Findex.mdx&astroContentModuleFlag=true")], -["src/content/docs/core/analytics.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcore%2Fanalytics.mdx&astroContentModuleFlag=true")], -["src/content/docs/core/knowledge-base.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcore%2Fknowledge-base.mdx&astroContentModuleFlag=true")], -["src/content/docs/core/providers.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcore%2Fproviders.mdx&astroContentModuleFlag=true")], -["src/content/docs/getting-started/quick-start.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Fquick-start.mdx&astroContentModuleFlag=true")], -["src/content/docs/getting-started/installation.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fgetting-started%2Finstallation.mdx&astroContentModuleFlag=true")], -["src/content/docs/core/tools.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fcore%2Ftools.mdx&astroContentModuleFlag=true")], -["src/content/docs/examples/express-full.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fexamples%2Fexpress-full.mdx&astroContentModuleFlag=true")], -["src/content/docs/examples/cloudflare-full.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fexamples%2Fcloudflare-full.mdx&astroContentModuleFlag=true")], -["src/content/docs/examples/vercel-full.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fexamples%2Fvercel-full.mdx&astroContentModuleFlag=true")], -["src/content/docs/server/express.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fserver%2Fexpress.mdx&astroContentModuleFlag=true")], -["src/content/docs/server/cloudflare.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fserver%2Fcloudflare.mdx&astroContentModuleFlag=true")], -["src/content/docs/server/setup.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fserver%2Fsetup.mdx&astroContentModuleFlag=true")], -["src/content/docs/server/vercel.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fserver%2Fvercel.mdx&astroContentModuleFlag=true")], -["src/content/docs/widget/api.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fwidget%2Fapi.mdx&astroContentModuleFlag=true")], -["src/content/docs/widget/configuration.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fwidget%2Fconfiguration.mdx&astroContentModuleFlag=true")], -["src/content/docs/widget/events.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fwidget%2Fevents.mdx&astroContentModuleFlag=true")], -["src/content/docs/widget/i18n.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fwidget%2Fi18n.mdx&astroContentModuleFlag=true")], -["src/content/docs/widget/theming.mdx", () => import("astro:content-layer-deferred-module?astro%3Acontent-layer-deferred-module=&fileName=src%2Fcontent%2Fdocs%2Fwidget%2Ftheming.mdx&astroContentModuleFlag=true")]]); - \ No newline at end of file diff --git a/website/.astro/data-store.json b/website/.astro/data-store.json deleted file mode 100644 index 67b5ef3..0000000 --- a/website/.astro/data-store.json +++ /dev/null @@ -1 +0,0 @@ -[["Map",1,2,9,10],"meta::meta",["Map",3,4,5,6,7,8],"astro-version","5.18.0","content-config-digest","28e7bc87492477d9","astro-config-digest","{\"root\":{},\"srcDir\":{},\"publicDir\":{},\"outDir\":{},\"cacheDir\":{},\"site\":\"https://chatcops.codercops.com\",\"compressHTML\":true,\"base\":\"/\",\"trailingSlash\":\"ignore\",\"output\":\"static\",\"scopedStyleStrategy\":\"where\",\"build\":{\"format\":\"directory\",\"client\":{},\"server\":{},\"assets\":\"_astro\",\"serverEntry\":\"entry.mjs\",\"redirects\":true,\"inlineStylesheets\":\"auto\",\"concurrency\":1},\"server\":{\"open\":false,\"host\":false,\"port\":4321,\"streaming\":true,\"allowedHosts\":[]},\"redirects\":{},\"image\":{\"endpoint\":{\"route\":\"/_image\"},\"service\":{\"entrypoint\":\"astro/assets/services/sharp\",\"config\":{}},\"domains\":[],\"remotePatterns\":[],\"responsiveStyles\":false},\"devToolbar\":{\"enabled\":true},\"markdown\":{\"syntaxHighlight\":false,\"shikiConfig\":{\"langs\":[],\"langAlias\":{},\"theme\":\"github-dark\",\"themes\":{},\"wrap\":false,\"transformers\":[]},\"remarkPlugins\":[null,null,null],\"rehypePlugins\":[null,[null,{\"experimentalHeadingIdCompat\":false}],null,[null,{\"themes\":[{\"name\":\"Night Owl No Italics\",\"type\":\"dark\",\"colors\":{\"focusBorder\":\"#122d42\",\"foreground\":\"#d6deeb\",\"disabledForeground\":\"#cccccc80\",\"descriptionForeground\":\"#d6deebb3\",\"errorForeground\":\"#ef5350\",\"icon.foreground\":\"#c5c5c5\",\"contrastActiveBorder\":null,\"contrastBorder\":\"#122d42\",\"textBlockQuote.background\":\"#7f7f7f1a\",\"textBlockQuote.border\":\"#007acc80\",\"textCodeBlock.background\":\"#4f4f4f\",\"textLink.activeForeground\":\"#3794ff\",\"textLink.foreground\":\"#3794ff\",\"textPreformat.foreground\":\"#d7ba7d\",\"textSeparator.foreground\":\"#ffffff2e\",\"editor.background\":\"#23262f\",\"editor.foreground\":\"#d6deeb\",\"editorLineNumber.foreground\":\"#4b6479\",\"editorLineNumber.activeForeground\":\"#c5e4fd\",\"editorActiveLineNumber.foreground\":\"#c6c6c6\",\"editor.selectionBackground\":\"#1d3b53\",\"editor.inactiveSelectionBackground\":\"#7e57c25a\",\"editor.selectionHighlightBackground\":\"#5f7e9779\",\"editorError.foreground\":\"#ef5350\",\"editorWarning.foreground\":\"#b39554\",\"editorInfo.foreground\":\"#3794ff\",\"editorHint.foreground\":\"#eeeeeeb2\",\"problemsErrorIcon.foreground\":\"#ef5350\",\"problemsWarningIcon.foreground\":\"#b39554\",\"problemsInfoIcon.foreground\":\"#3794ff\",\"editor.findMatchBackground\":\"#5f7e9779\",\"editor.findMatchHighlightBackground\":\"#1085bb5d\",\"editor.findRangeHighlightBackground\":\"#3a3d4166\",\"editorLink.activeForeground\":\"#4e94ce\",\"editorLightBulb.foreground\":\"#ffcc00\",\"editorLightBulbAutoFix.foreground\":\"#75beff\",\"diffEditor.insertedTextBackground\":\"#99b76d23\",\"diffEditor.insertedTextBorder\":\"#c5e47833\",\"diffEditor.removedTextBackground\":\"#ef535033\",\"diffEditor.removedTextBorder\":\"#ef53504d\",\"diffEditor.insertedLineBackground\":\"#9bb95533\",\"diffEditor.removedLineBackground\":\"#ff000033\",\"editorStickyScroll.background\":\"#011627\",\"editorStickyScrollHover.background\":\"#2a2d2e\",\"editorInlayHint.background\":\"#5f7e97cc\",\"editorInlayHint.foreground\":\"#ffffff\",\"editorInlayHint.typeBackground\":\"#5f7e97cc\",\"editorInlayHint.typeForeground\":\"#ffffff\",\"editorInlayHint.parameterBackground\":\"#5f7e97cc\",\"editorInlayHint.parameterForeground\":\"#ffffff\",\"editorPane.background\":\"#011627\",\"editorGroup.emptyBackground\":\"#011627\",\"editorGroup.focusedEmptyBorder\":null,\"editorGroupHeader.tabsBackground\":\"var(--sl-color-black)\",\"editorGroupHeader.tabsBorder\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"editorGroupHeader.noTabsBackground\":\"#011627\",\"editorGroupHeader.border\":null,\"editorGroup.border\":\"#011627\",\"editorGroup.dropBackground\":\"#7e57c273\",\"editorGroup.dropIntoPromptForeground\":\"#d6deeb\",\"editorGroup.dropIntoPromptBackground\":\"#021320\",\"editorGroup.dropIntoPromptBorder\":null,\"sideBySideEditor.horizontalBorder\":\"#011627\",\"sideBySideEditor.verticalBorder\":\"#011627\",\"scrollbar.shadow\":\"#010b14\",\"scrollbarSlider.background\":\"#ffffff17\",\"scrollbarSlider.hoverBackground\":\"#ffffff40\",\"scrollbarSlider.activeBackground\":\"#084d8180\",\"panel.background\":\"#011627\",\"panel.border\":\"#5f7e97\",\"panelTitle.activeBorder\":\"#5f7e97\",\"panelTitle.activeForeground\":\"#ffffffcc\",\"panelTitle.inactiveForeground\":\"#d6deeb80\",\"panelSectionHeader.background\":\"#80808051\",\"terminal.background\":\"#011627\",\"widget.shadow\":\"#011627\",\"editorWidget.background\":\"#021320\",\"editorWidget.foreground\":\"#d6deeb\",\"editorWidget.border\":\"#5f7e97\",\"quickInput.background\":\"#021320\",\"quickInput.foreground\":\"#d6deeb\",\"quickInputTitle.background\":\"#ffffff1a\",\"pickerGroup.foreground\":\"#d1aaff\",\"pickerGroup.border\":\"#011627\",\"editor.hoverHighlightBackground\":\"#7e57c25a\",\"editorHoverWidget.background\":\"#011627\",\"editorHoverWidget.foreground\":\"#d6deeb\",\"editorHoverWidget.border\":\"#5f7e97\",\"editorHoverWidget.statusBarBackground\":\"#011a2f\",\"titleBar.activeBackground\":\"var(--sl-color-black)\",\"titleBar.activeForeground\":\"var(--sl-color-text)\",\"titleBar.inactiveBackground\":\"#010e1a\",\"titleBar.inactiveForeground\":\"#eeefff99\",\"titleBar.border\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"toolbar.hoverBackground\":\"#5a5d5e50\",\"toolbar.activeBackground\":\"#63666750\",\"tab.activeBackground\":\"#0b2942\",\"tab.unfocusedActiveBackground\":\"#0b2942\",\"tab.inactiveBackground\":\"#01111d\",\"tab.unfocusedInactiveBackground\":\"#01111d\",\"tab.activeForeground\":\"var(--sl-color-text)\",\"tab.inactiveForeground\":\"#5f7e97\",\"tab.unfocusedActiveForeground\":\"#5f7e97\",\"tab.unfocusedInactiveForeground\":\"#5f7e97\",\"tab.hoverBackground\":null,\"tab.unfocusedHoverBackground\":null,\"tab.hoverForeground\":null,\"tab.unfocusedHoverForeground\":null,\"tab.border\":\"#272b3b\",\"tab.lastPinnedBorder\":\"#585858\",\"tab.activeBorder\":\"transparent\",\"tab.unfocusedActiveBorder\":\"#262a39\",\"tab.activeBorderTop\":\"var(--sl-color-accent-high)\",\"tab.unfocusedActiveBorderTop\":null,\"tab.hoverBorder\":null,\"tab.unfocusedHoverBorder\":null,\"tab.activeModifiedBorder\":\"#3399cc\",\"tab.inactiveModifiedBorder\":\"#3399cc80\",\"tab.unfocusedActiveModifiedBorder\":\"#3399cc80\",\"tab.unfocusedInactiveModifiedBorder\":\"#3399cc40\",\"badge.background\":\"#5f7e97\",\"badge.foreground\":\"#ffffff\",\"button.background\":\"#7e57c2cc\",\"button.foreground\":\"#ffffffcc\",\"button.border\":\"#122d42\",\"button.separator\":\"#ffffff52\",\"button.hoverBackground\":\"#7e57c2\",\"button.secondaryBackground\":\"#3a3d41\",\"button.secondaryForeground\":\"#ffffff\",\"button.secondaryHoverBackground\":\"#46494e\",\"dropdown.background\":\"#011627\",\"dropdown.foreground\":\"#ffffffcc\",\"dropdown.border\":\"#5f7e97\",\"list.activeSelectionBackground\":\"#234d708c\",\"list.activeSelectionForeground\":\"#ffffff\",\"tree.indentGuidesStroke\":\"#585858\",\"input.background\":\"#0b253a\",\"input.foreground\":\"#ffffffcc\",\"input.placeholderForeground\":\"#5f7e97\",\"inputOption.activeBorder\":\"#ffffffcc\",\"inputOption.hoverBackground\":\"#5a5d5e80\",\"inputOption.activeBackground\":\"#122d4266\",\"inputOption.activeForeground\":\"#ffffff\",\"inputValidation.infoBackground\":\"#00589ef2\",\"inputValidation.infoBorder\":\"#64b5f6\",\"inputValidation.warningBackground\":\"#675700f2\",\"inputValidation.warningBorder\":\"#ffca28\",\"inputValidation.errorBackground\":\"#ab0300f2\",\"inputValidation.errorBorder\":\"#ef5350\",\"keybindingLabel.background\":\"#8080802b\",\"keybindingLabel.foreground\":\"#cccccc\",\"keybindingLabel.border\":\"#33333399\",\"keybindingLabel.bottomBorder\":\"#44444499\",\"menu.foreground\":\"#ffffffcc\",\"menu.background\":\"#011627\",\"menu.selectionForeground\":\"#ffffff\",\"menu.selectionBackground\":\"#234d708c\",\"menu.separatorBackground\":\"#606060\",\"editor.snippetTabstopHighlightBackground\":\"#7c7c74c\",\"editor.snippetFinalTabstopHighlightBorder\":\"#525252\",\"terminal.ansiBlack\":\"#011627\",\"terminal.ansiRed\":\"#ef5350\",\"terminal.ansiGreen\":\"#22da6e\",\"terminal.ansiYellow\":\"#c5e478\",\"terminal.ansiBlue\":\"#82aaff\",\"terminal.ansiMagenta\":\"#c792ea\",\"terminal.ansiCyan\":\"#21c7a8\",\"terminal.ansiWhite\":\"#ffffff\",\"terminal.ansiBrightBlack\":\"#575656\",\"terminal.ansiBrightRed\":\"#ef5350\",\"terminal.ansiBrightGreen\":\"#22da6e\",\"terminal.ansiBrightYellow\":\"#ffeb95\",\"terminal.ansiBrightBlue\":\"#82aaff\",\"terminal.ansiBrightMagenta\":\"#c792ea\",\"terminal.ansiBrightCyan\":\"#7fdbca\",\"terminal.ansiBrightWhite\":\"#ffffff\",\"selection.background\":\"#4373c2\",\"input.border\":\"#5f7e97\",\"punctuation.definition.generic.begin.html\":\"#ef5350f2\",\"progress.background\":\"#7e57c2\",\"breadcrumb.foreground\":\"#a599e9\",\"breadcrumb.focusForeground\":\"#ffffff\",\"breadcrumb.activeSelectionForeground\":\"#ffffff\",\"breadcrumbPicker.background\":\"#001122\",\"list.invalidItemForeground\":\"#975f94\",\"list.dropBackground\":\"#011627\",\"list.focusBackground\":\"#010d18\",\"list.focusForeground\":\"#ffffff\",\"list.highlightForeground\":\"#ffffff\",\"list.hoverBackground\":\"#011627\",\"list.hoverForeground\":\"#ffffff\",\"list.inactiveSelectionBackground\":\"#0e293f\",\"list.inactiveSelectionForeground\":\"#5f7e97\",\"activityBar.background\":\"#011627\",\"activityBar.dropBackground\":\"#5f7e97\",\"activityBar.foreground\":\"#5f7e97\",\"activityBar.border\":\"#011627\",\"activityBarBadge.background\":\"#44596b\",\"activityBarBadge.foreground\":\"#ffffff\",\"sideBar.background\":\"#011627\",\"sideBar.foreground\":\"#89a4bb\",\"sideBar.border\":\"#011627\",\"sideBarTitle.foreground\":\"#5f7e97\",\"sideBarSectionHeader.background\":\"#011627\",\"sideBarSectionHeader.foreground\":\"#5f7e97\",\"editorCursor.foreground\":\"#80a4c2\",\"editor.wordHighlightBackground\":\"#f6bbe533\",\"editor.wordHighlightStrongBackground\":\"#e2a2f433\",\"editor.lineHighlightBackground\":\"#0003\",\"editor.rangeHighlightBackground\":\"#7e57c25a\",\"editorIndentGuide.background\":\"#5e81ce52\",\"editorIndentGuide.activeBackground\":\"#7e97ac\",\"editorRuler.foreground\":\"#5e81ce52\",\"editorCodeLens.foreground\":\"#5e82ceb4\",\"editorBracketMatch.background\":\"#5f7e974d\",\"editorOverviewRuler.currentContentForeground\":\"#7e57c2\",\"editorOverviewRuler.incomingContentForeground\":\"#7e57c2\",\"editorOverviewRuler.commonContentForeground\":\"#7e57c2\",\"editorGutter.background\":\"#011627\",\"editorGutter.modifiedBackground\":\"#e2b93d\",\"editorGutter.addedBackground\":\"#9ccc65\",\"editorGutter.deletedBackground\":\"#ef5350\",\"editorSuggestWidget.background\":\"#2c3043\",\"editorSuggestWidget.border\":\"#2b2f40\",\"editorSuggestWidget.foreground\":\"#d6deeb\",\"editorSuggestWidget.highlightForeground\":\"#ffffff\",\"editorSuggestWidget.selectedBackground\":\"#5f7e97\",\"debugExceptionWidget.background\":\"#011627\",\"debugExceptionWidget.border\":\"#5f7e97\",\"editorMarkerNavigation.background\":\"#0b2942\",\"editorMarkerNavigationError.background\":\"#ef5350\",\"editorMarkerNavigationWarning.background\":\"#ffca28\",\"peekView.border\":\"#5f7e97\",\"peekViewEditor.background\":\"#011627\",\"peekViewEditor.matchHighlightBackground\":\"#7e57c25a\",\"peekViewResult.background\":\"#011627\",\"peekViewResult.fileForeground\":\"#5f7e97\",\"peekViewResult.lineForeground\":\"#5f7e97\",\"peekViewResult.matchHighlightBackground\":\"#ffffffcc\",\"peekViewResult.selectionBackground\":\"#2e3250\",\"peekViewResult.selectionForeground\":\"#5f7e97\",\"peekViewTitle.background\":\"#011627\",\"peekViewTitleDescription.foreground\":\"#697098\",\"peekViewTitleLabel.foreground\":\"#5f7e97\",\"merge.currentHeaderBackground\":\"#5f7e97\",\"merge.incomingHeaderBackground\":\"#7e57c25a\",\"statusBar.background\":\"#011627\",\"statusBar.foreground\":\"#5f7e97\",\"statusBar.border\":\"#262a39\",\"statusBar.debuggingBackground\":\"#202431\",\"statusBar.debuggingBorder\":\"#1f2330\",\"statusBar.noFolderBackground\":\"#011627\",\"statusBar.noFolderBorder\":\"#25293a\",\"statusBarItem.activeBackground\":\"#202431\",\"statusBarItem.hoverBackground\":\"#202431\",\"statusBarItem.prominentBackground\":\"#202431\",\"statusBarItem.prominentHoverBackground\":\"#202431\",\"notifications.background\":\"#01111d\",\"notifications.border\":\"#262a39\",\"notificationCenter.border\":\"#262a39\",\"notificationToast.border\":\"#262a39\",\"notifications.foreground\":\"#ffffffcc\",\"notificationLink.foreground\":\"#80cbc4\",\"extensionButton.prominentForeground\":\"#ffffffcc\",\"extensionButton.prominentBackground\":\"#7e57c2cc\",\"extensionButton.prominentHoverBackground\":\"#7e57c2\",\"terminal.selectionBackground\":\"#1b90dd4d\",\"terminalCursor.background\":\"#234d70\",\"debugToolBar.background\":\"#011627\",\"welcomePage.buttonBackground\":\"#011627\",\"welcomePage.buttonHoverBackground\":\"#011627\",\"walkThrough.embeddedEditorBackground\":\"#011627\",\"gitDecoration.modifiedResourceForeground\":\"#a2bffc\",\"gitDecoration.deletedResourceForeground\":\"#ef535090\",\"gitDecoration.untrackedResourceForeground\":\"#c5e478ff\",\"gitDecoration.ignoredResourceForeground\":\"#395a75\",\"gitDecoration.conflictingResourceForeground\":\"#ffeb95cc\",\"source.elm\":\"#5f7e97\",\"string.quoted.single.js\":\"#ffffff\",\"meta.objectliteral.js\":\"#82aaff\"},\"fg\":\"#d6deeb\",\"bg\":\"#23262f\",\"semanticHighlighting\":false,\"settings\":[{\"name\":\"Changed\",\"scope\":[\"markup.changed\",\"meta.diff.header.git\",\"meta.diff.header.from-file\",\"meta.diff.header.to-file\"],\"settings\":{\"foreground\":\"#a2bffc\"}},{\"name\":\"Deleted\",\"scope\":[\"markup.deleted.diff\"],\"settings\":{\"foreground\":\"#f27775fe\"}},{\"name\":\"Inserted\",\"scope\":[\"markup.inserted.diff\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Global settings\",\"settings\":{\"background\":\"#011627\",\"foreground\":\"#d6deeb\"}},{\"name\":\"Comment\",\"scope\":[\"comment\"],\"settings\":{\"foreground\":\"#919f9f\",\"fontStyle\":\"\"}},{\"name\":\"String\",\"scope\":[\"string\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"String Quoted\",\"scope\":[\"string.quoted\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"Support Constant Math\",\"scope\":[\"support.constant.math\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Number\",\"scope\":[\"constant.numeric\",\"constant.character.numeric\"],\"settings\":{\"foreground\":\"#f78c6c\",\"fontStyle\":\"\"}},{\"name\":\"Built-in constant\",\"scope\":[\"constant.language\",\"punctuation.definition.constant\",\"variable.other.constant\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"User-defined constant\",\"scope\":[\"constant.character\",\"constant.other\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Constant Character Escape\",\"scope\":[\"constant.character.escape\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"RegExp String\",\"scope\":[\"string.regexp\",\"string.regexp keyword.other\"],\"settings\":{\"foreground\":\"#5ca7e4\"}},{\"name\":\"Comma in functions\",\"scope\":[\"meta.function punctuation.separator.comma\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"Variable\",\"scope\":[\"variable\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Keyword\",\"scope\":[\"punctuation.accessor\",\"keyword\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Storage\",\"scope\":[\"storage\",\"meta.var.expr\",\"meta.class meta.method.declaration meta.var.expr storage.type.js\",\"storage.type.property.js\",\"storage.type.property.ts\",\"storage.type.property.tsx\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type.function.arrow.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Class name\",\"scope\":[\"entity.name.class\",\"meta.class entity.name.type.class\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Inherited class\",\"scope\":[\"entity.other.inherited-class\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Function name\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Meta Tag\",\"scope\":[\"punctuation.definition.tag\",\"meta.tag\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"HTML Tag names\",\"scope\":[\"entity.name.tag\",\"meta.tag.other.html\",\"meta.tag.other.js\",\"meta.tag.other.tsx\",\"entity.name.tag.tsx\",\"entity.name.tag.js\",\"entity.name.tag\",\"meta.tag.js\",\"meta.tag.tsx\",\"meta.tag.html\"],\"settings\":{\"foreground\":\"#caece6\",\"fontStyle\":\"\"}},{\"name\":\"Tag attribute\",\"scope\":[\"entity.other.attribute-name\"],\"settings\":{\"fontStyle\":\"\",\"foreground\":\"#c5e478\"}},{\"name\":\"Entity Name Tag Custom\",\"scope\":[\"entity.name.tag.custom\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Library (function & constant)\",\"scope\":[\"support.function\",\"support.constant\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Support Constant Property Value meta\",\"scope\":[\"support.constant.meta.property-value\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Library class/type\",\"scope\":[\"support.type\",\"support.class\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Support Variable DOM\",\"scope\":[\"support.variable.dom\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Invalid\",\"scope\":[\"invalid\"],\"settings\":{\"background\":\"#ff2c83\",\"foreground\":\"#ffffff\"}},{\"name\":\"Invalid deprecated\",\"scope\":[\"invalid.deprecated\"],\"settings\":{\"foreground\":\"#ffffff\",\"background\":\"#d3423e\"}},{\"name\":\"Keyword Operator\",\"scope\":[\"keyword.operator\"],\"settings\":{\"foreground\":\"#7fdbca\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Relational\",\"scope\":[\"keyword.operator.relational\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Assignment\",\"scope\":[\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Arithmetic\",\"scope\":[\"keyword.operator.arithmetic\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Bitwise\",\"scope\":[\"keyword.operator.bitwise\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Increment\",\"scope\":[\"keyword.operator.increment\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Keyword Operator Ternary\",\"scope\":[\"keyword.operator.ternary\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Double-Slashed Comment\",\"scope\":[\"comment.line.double-slash\"],\"settings\":{\"foreground\":\"#919f9f\"}},{\"name\":\"Object\",\"scope\":[\"object\"],\"settings\":{\"foreground\":\"#cdebf7\"}},{\"name\":\"Null\",\"scope\":[\"constant.language.null\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Meta Brace\",\"scope\":[\"meta.brace\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Meta Delimiter Period\",\"scope\":[\"meta.delimiter.period\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Punctuation Definition String\",\"scope\":[\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Punctuation Definition String Markdown\",\"scope\":[\"punctuation.definition.string.begin.markdown\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Boolean\",\"scope\":[\"constant.language.boolean\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Object Comma\",\"scope\":[\"object.comma\"],\"settings\":{\"foreground\":\"#ffffff\"}},{\"name\":\"Variable Parameter Function\",\"scope\":[\"variable.parameter.function\"],\"settings\":{\"foreground\":\"#7fdbca\",\"fontStyle\":\"\"}},{\"name\":\"Support Type Property Name & entity name tags\",\"scope\":[\"support.type.vendor.property-name\",\"support.constant.vendor.property-value\",\"support.type.property-name\",\"meta.property-list entity.name.tag\"],\"settings\":{\"foreground\":\"#80cbc4\",\"fontStyle\":\"\"}},{\"name\":\"Entity Name tag reference in stylesheets\",\"scope\":[\"meta.property-list entity.name.tag.reference\"],\"settings\":{\"foreground\":\"#57eaf1\"}},{\"name\":\"Constant Other Color RGB Value Punctuation Definition Constant\",\"scope\":[\"constant.other.color.rgb-value punctuation.definition.constant\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Constant Other Color\",\"scope\":[\"constant.other.color\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Keyword Other Unit\",\"scope\":[\"keyword.other.unit\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Meta Selector\",\"scope\":[\"meta.selector\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Entity Other Attribute Name Id\",\"scope\":[\"entity.other.attribute-name.id\"],\"settings\":{\"foreground\":\"#fad430\"}},{\"name\":\"Meta Property Name\",\"scope\":[\"meta.property-name\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Doctypes\",\"scope\":[\"entity.name.tag.doctype\",\"meta.tag.sgml.doctype\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Punctuation Definition Parameters\",\"scope\":[\"punctuation.definition.parameters\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Keyword Control Operator\",\"scope\":[\"keyword.control.operator\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Keyword Operator Logical\",\"scope\":[\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Variable Instances\",\"scope\":[\"variable.instance\",\"variable.other.instance\",\"variable.readwrite.instance\",\"variable.other.readwrite.instance\",\"variable.other.property\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Variable Property Other object property\",\"scope\":[\"variable.other.object.property\"],\"settings\":{\"foreground\":\"#faf39f\",\"fontStyle\":\"\"}},{\"name\":\"Variable Property Other object\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Entity Name Function\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#82aaff\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Comparison, returns, imports, and Keyword Operator Ruby\",\"scope\":[\"keyword.control.conditional.js\",\"keyword.operator.comparison\",\"keyword.control.flow.js\",\"keyword.control.flow.ts\",\"keyword.control.flow.tsx\",\"keyword.control.ruby\",\"keyword.control.def.ruby\",\"keyword.control.loop.js\",\"keyword.control.loop.ts\",\"keyword.control.import.js\",\"keyword.control.import.ts\",\"keyword.control.import.tsx\",\"keyword.control.from.js\",\"keyword.control.from.ts\",\"keyword.control.from.tsx\",\"keyword.control.conditional.js\",\"keyword.control.conditional.ts\",\"keyword.control.switch.js\",\"keyword.control.switch.ts\",\"keyword.operator.instanceof.js\",\"keyword.operator.expression.instanceof.ts\",\"keyword.operator.expression.instanceof.tsx\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Support Constant, `new` keyword, Special Method Keyword, `debugger`, other keywords\",\"scope\":[\"support.constant\",\"keyword.other.special-method\",\"keyword.other.new\",\"keyword.other.debugger\",\"keyword.control\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Support Function\",\"scope\":[\"support.function\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Invalid Broken\",\"scope\":[\"invalid.broken\"],\"settings\":{\"foreground\":\"#989da0\",\"background\":\"#F78C6C\"}},{\"name\":\"Invalid Unimplemented\",\"scope\":[\"invalid.unimplemented\"],\"settings\":{\"background\":\"#8BD649\",\"foreground\":\"#ffffff\"}},{\"name\":\"Invalid Illegal\",\"scope\":[\"invalid.illegal\"],\"settings\":{\"foreground\":\"#ffffff\",\"background\":\"#ec5f67\"}},{\"name\":\"Language Variable\",\"scope\":[\"variable.language\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Support Variable Property\",\"scope\":[\"support.variable.property\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Variable Function\",\"scope\":[\"variable.function\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Variable Interpolation\",\"scope\":[\"variable.interpolation\"],\"settings\":{\"foreground\":\"#ef787f\"}},{\"name\":\"Meta Function Call\",\"scope\":[\"meta.function-call\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Punctuation Section Embedded\",\"scope\":[\"punctuation.section.embedded\"],\"settings\":{\"foreground\":\"#e2817f\"}},{\"name\":\"Punctuation Tweaks\",\"scope\":[\"punctuation.terminator.expression\",\"punctuation.definition.arguments\",\"punctuation.definition.array\",\"punctuation.section.array\",\"meta.array\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"More Punctuation Tweaks\",\"scope\":[\"punctuation.definition.list.begin\",\"punctuation.definition.list.end\",\"punctuation.separator.arguments\",\"punctuation.definition.list\"],\"settings\":{\"foreground\":\"#d9f5dd\"}},{\"name\":\"Template Strings\",\"scope\":[\"string.template meta.template.expression\"],\"settings\":{\"foreground\":\"#e2817f\"}},{\"name\":\"Backtics(``) in Template Strings\",\"scope\":[\"string.template punctuation.definition.string\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Italics\",\"scope\":[\"italic\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"italic\"}},{\"name\":\"Bold\",\"scope\":[\"bold\"],\"settings\":{\"foreground\":\"#c5e478\",\"fontStyle\":\"bold\"}},{\"name\":\"Quote\",\"scope\":[\"quote\"],\"settings\":{\"foreground\":\"#969bb7\",\"fontStyle\":\"\"}},{\"name\":\"Raw Code\",\"scope\":[\"raw\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"CoffeScript Variable Assignment\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#31e1eb\"}},{\"name\":\"CoffeScript Parameter Function\",\"scope\":[\"variable.parameter.function.coffee\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"CoffeeScript Assignments\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"C# Readwrite Variables\",\"scope\":[\"variable.other.readwrite.cs\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C# Classes & Storage types\",\"scope\":[\"entity.name.type.class.cs\",\"storage.type.cs\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"C# Namespaces\",\"scope\":[\"entity.name.type.namespace.cs\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"C# Unquoted String Zone\",\"scope\":[\"string.unquoted.preprocessor.message.cs\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C# Region\",\"scope\":[\"punctuation.separator.hash.cs\",\"keyword.preprocessor.region.cs\",\"keyword.preprocessor.endregion.cs\"],\"settings\":{\"foreground\":\"#ffcb8b\",\"fontStyle\":\"bold\"}},{\"name\":\"C# Other Variables\",\"scope\":[\"variable.other.object.cs\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"C# Enum\",\"scope\":[\"entity.name.type.enum.cs\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Dart String\",\"scope\":[\"string.interpolated.single.dart\",\"string.interpolated.double.dart\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Dart Class\",\"scope\":[\"support.class.dart\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Tag names in Stylesheets\",\"scope\":[\"entity.name.tag.css\",\"entity.name.tag.less\",\"entity.name.tag.custom.css\",\"support.constant.property-value.css\"],\"settings\":{\"foreground\":\"#ff6d6d\",\"fontStyle\":\"\"}},{\"name\":\"Wildcard(*) selector in Stylesheets\",\"scope\":[\"entity.name.tag.wildcard.css\",\"entity.name.tag.wildcard.less\",\"entity.name.tag.wildcard.scss\",\"entity.name.tag.wildcard.sass\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"CSS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Attribute Name for CSS\",\"scope\":[\"meta.attribute-selector.css entity.other.attribute-name.attribute\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Elixir Classes\",\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Elixir Functions\",\"scope\":[\"source.elixir entity.name.function\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir Constants\",\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Elixir String Punctuations\",\"scope\":[\"source.elixir punctuation.definition.string\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir\",\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Elixir Binary Punctuations\",\"scope\":[\"source.elixir .punctuation.binary.elixir\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"Closure Constant Keyword\",\"scope\":[\"constant.keyword.clojure\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Go Function Calls\",\"scope\":[\"source.go meta.function-call.go\"],\"settings\":{\"foreground\":\"#dddddd\"}},{\"name\":\"Go Keywords\",\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"Go Constants e.g. nil, string format (%s, %d, etc.)\",\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"C++ Functions\",\"scope\":[\"entity.name.function.preprocessor.cpp\",\"entity.scope.name.cpp\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"C++ Meta Namespace\",\"scope\":[\"meta.namespace-block.cpp\"],\"settings\":{\"foreground\":\"#e0dec6\"}},{\"name\":\"C++ Language Primitive Storage\",\"scope\":[\"storage.type.language.primitive.cpp\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"C++ Preprocessor Macro\",\"scope\":[\"meta.preprocessor.macro.cpp\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"C++ Variable Parameter\",\"scope\":[\"variable.parameter\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Powershell Variables\",\"scope\":[\"variable.other.readwrite.powershell\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Powershell Function\",\"scope\":[\"support.function.powershell\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"ID Attribute Name in HTML\",\"scope\":[\"entity.other.attribute-name.id.html\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"HTML Punctuation Definition Tag\",\"scope\":[\"punctuation.definition.tag.html\"],\"settings\":{\"foreground\":\"#6ae9f0\"}},{\"name\":\"HTML Doctype\",\"scope\":[\"meta.tag.sgml.doctype.html\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Classes\",\"scope\":[\"meta.class entity.name.type.class.js\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"JavaScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.js\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"JavaScript Terminator\",\"scope\":[\"terminator.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Meta Punctuation Definition\",\"scope\":[\"meta.js punctuation.definition.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Entity Names in Code Documentations\",\"scope\":[\"entity.name.type.instance.jsdoc\",\"entity.name.type.instance.phpdoc\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"Other Variables in Code Documentations\",\"scope\":[\"variable.other.jsdoc\",\"variable.other.phpdoc\"],\"settings\":{\"foreground\":\"#78ccf0\"}},{\"name\":\"JavaScript module imports and exports\",\"scope\":[\"variable.other.meta.import.js\",\"meta.import.js variable.other\",\"variable.other.meta.export.js\",\"meta.export.js variable.other\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Variable Parameter Function\",\"scope\":[\"variable.parameter.function.js\"],\"settings\":{\"foreground\":\"#8b96ea\"}},{\"name\":\"JavaScript[React] Variable Other Object\",\"scope\":[\"variable.other.object.js\",\"variable.other.object.jsx\",\"variable.object.property.js\",\"variable.object.property.jsx\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Variables\",\"scope\":[\"variable.js\",\"variable.other.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JavaScript Entity Name Type\",\"scope\":[\"entity.name.type.js\",\"entity.name.type.module.js\"],\"settings\":{\"foreground\":\"#ffcb8b\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Support Classes\",\"scope\":[\"support.class.js\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"JSON Property Names\",\"scope\":[\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"JSON Support Constants\",\"scope\":[\"support.constant.json\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"JSON Property values (string)\",\"scope\":[\"meta.structure.dictionary.value.json string.quoted.double\"],\"settings\":{\"foreground\":\"#c789d6\"}},{\"name\":\"Strings in JSON values\",\"scope\":[\"string.quoted.double.json punctuation.definition.string.json\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Specific JSON Property values like null\",\"scope\":[\"meta.structure.dictionary.json meta.structure.dictionary.value constant.language\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"JavaScript Other Variable\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Ruby Variables\",\"scope\":[\"variable.other.ruby\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Ruby Class\",\"scope\":[\"entity.name.type.class.ruby\"],\"settings\":{\"foreground\":\"#ecc48d\"}},{\"name\":\"Ruby Hashkeys\",\"scope\":[\"constant.language.symbol.hashkey.ruby\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"LESS Tag names\",\"scope\":[\"entity.name.tag.less\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"LESS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"Attribute Name for LESS\",\"scope\":[\"meta.attribute-selector.less entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Markdown Headings\",\"scope\":[\"markup.heading.markdown\",\"markup.heading.setext.1.markdown\",\"markup.heading.setext.2.markdown\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown Italics\",\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"foreground\":\"#c792ea\",\"fontStyle\":\"italic\"}},{\"name\":\"Markdown Bold\",\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"foreground\":\"#c5e478\",\"fontStyle\":\"bold\"}},{\"name\":\"Markdown Quote + others\",\"scope\":[\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#969bb7\",\"fontStyle\":\"\"}},{\"name\":\"Markdown Raw Code + others\",\"scope\":[\"markup.inline.raw.markdown\"],\"settings\":{\"foreground\":\"#80cbc4\"}},{\"name\":\"Markdown Links\",\"scope\":[\"markup.underline.link.markdown\",\"markup.underline.link.image.markdown\"],\"settings\":{\"foreground\":\"#ff869a\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Link Title and Description\",\"scope\":[\"string.other.link.title.markdown\",\"string.other.link.description.markdown\"],\"settings\":{\"foreground\":\"#d6deeb\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Punctuation\",\"scope\":[\"punctuation.definition.string.markdown\",\"punctuation.definition.string.begin.markdown\",\"punctuation.definition.string.end.markdown\",\"meta.link.inline.markdown punctuation.definition.string\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown MetaData Punctuation\",\"scope\":[\"punctuation.definition.metadata.markdown\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"Markdown List Punctuation\",\"scope\":[\"beginning.punctuation.definition.list.markdown\"],\"settings\":{\"foreground\":\"#82b1ff\"}},{\"name\":\"Markdown Inline Raw String\",\"scope\":[\"markup.inline.raw.string.markdown\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"PHP Variables\",\"scope\":[\"variable.other.php\"],\"settings\":{\"foreground\":\"#bec5d4\"}},{\"name\":\"Support Classes in PHP\",\"scope\":[\"support.class.php\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"Punctuations in PHP function calls\",\"scope\":[\"meta.function-call.php punctuation\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"PHP Global Variables\",\"scope\":[\"variable.other.global.php\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Declaration Punctuation in PHP Global Variables\",\"scope\":[\"variable.other.global.php punctuation.definition.variable\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Language Constants in Python\",\"scope\":[\"constant.language.python\"],\"settings\":{\"foreground\":\"#ff6a83\"}},{\"name\":\"Python Function Parameter and Arguments\",\"scope\":[\"variable.parameter.function.python\",\"meta.function-call.arguments.python\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Python Function Call\",\"scope\":[\"meta.function-call.python\",\"meta.function-call.generic.python\"],\"settings\":{\"foreground\":\"#b2ccd6\"}},{\"name\":\"Punctuations in Python\",\"scope\":[\"punctuation.python\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"Decorator Functions in Python\",\"scope\":[\"entity.name.function.decorator.python\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Python Language Variable\",\"scope\":[\"source.python variable.language.special\"],\"settings\":{\"foreground\":\"#8eace3\"}},{\"name\":\"Python import control keyword\",\"scope\":[\"keyword.control\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"SCSS Variable\",\"scope\":[\"variable.scss\",\"variable.sass\",\"variable.parameter.url.scss\",\"variable.parameter.url.sass\"],\"settings\":{\"foreground\":\"#c5e478\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#bec5d4\"}},{\"name\":\"Attribute Name for SASS\",\"scope\":[\"meta.attribute-selector.scss entity.other.attribute-name.attribute\",\"meta.attribute-selector.sass entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#f78c6c\"}},{\"name\":\"Tag names in SASS\",\"scope\":[\"entity.name.tag.scss\",\"entity.name.tag.sass\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"SASS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.scss\",\"keyword.other.unit.sass\"],\"settings\":{\"foreground\":\"#ffeb95\"}},{\"name\":\"TypeScript[React] Variables and Object Properties\",\"scope\":[\"variable.other.readwrite.alias.ts\",\"variable.other.readwrite.alias.tsx\",\"variable.other.readwrite.ts\",\"variable.other.readwrite.tsx\",\"variable.other.object.ts\",\"variable.other.object.tsx\",\"variable.object.property.ts\",\"variable.object.property.tsx\",\"variable.other.ts\",\"variable.other.tsx\",\"variable.tsx\",\"variable.ts\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript[React] Entity Name Types\",\"scope\":[\"entity.name.type.ts\",\"entity.name.type.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript[React] Node Classes\",\"scope\":[\"support.class.node.ts\",\"support.class.node.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"TypeScript[React] Entity Name Types as Parameters\",\"scope\":[\"meta.type.parameters.ts entity.name.type\",\"meta.type.parameters.tsx entity.name.type\"],\"settings\":{\"foreground\":\"#889fb2\"}},{\"name\":\"TypeScript[React] Import/Export Punctuations\",\"scope\":[\"meta.import.ts punctuation.definition.block\",\"meta.import.tsx punctuation.definition.block\",\"meta.export.ts punctuation.definition.block\",\"meta.export.tsx punctuation.definition.block\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.decorator punctuation.decorator.ts\",\"meta.decorator punctuation.decorator.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.tag.js meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"YAML Entity Name Tags\",\"scope\":[\"entity.name.tag.yaml\"],\"settings\":{\"foreground\":\"#7fdbca\"}},{\"name\":\"JavaScript Variable Other ReadWrite\",\"scope\":[\"variable.other.readwrite.js\",\"variable.parameter\"],\"settings\":{\"foreground\":\"#d7dbe0\"}},{\"name\":\"Support Class Component\",\"scope\":[\"support.class.component.js\",\"support.class.component.tsx\"],\"settings\":{\"foreground\":\"#f78c6c\",\"fontStyle\":\"\"}},{\"name\":\"Text nested in React tags\",\"scope\":[\"meta.jsx.children\",\"meta.jsx.children.js\",\"meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#d6deeb\"}},{\"name\":\"TypeScript Classes\",\"scope\":[\"meta.class entity.name.type.class.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript Entity Name Type\",\"scope\":[\"entity.name.type.tsx\",\"entity.name.type.module.tsx\"],\"settings\":{\"foreground\":\"#ffcb8b\"}},{\"name\":\"TypeScript Class Variable Keyword\",\"scope\":[\"meta.class.ts meta.var.expr.ts storage.type.ts\",\"meta.class.tsx meta.var.expr.tsx storage.type.tsx\"],\"settings\":{\"foreground\":\"#c792ea\"}},{\"name\":\"TypeScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.ts\",\"meta.method.declaration storage.type.tsx\"],\"settings\":{\"foreground\":\"#82aaff\"}},{\"name\":\"normalize font style of certain components\",\"scope\":[\"meta.property-list.css meta.property-value.css variable.other.less\",\"meta.property-list.scss variable.scss\",\"meta.property-list.sass variable.sass\",\"meta.brace\",\"keyword.operator.operator\",\"keyword.operator.or.regexp\",\"keyword.operator.expression.in\",\"keyword.operator.relational\",\"keyword.operator.assignment\",\"keyword.operator.comparison\",\"keyword.operator.type\",\"keyword.operator\",\"keyword\",\"punctuation.definintion.string\",\"punctuation\",\"variable.other.readwrite.js\",\"storage.type\",\"source.css\",\"string.quoted\"],\"settings\":{\"fontStyle\":\"\"}}],\"styleOverrides\":{\"frames\":{\"editorBackground\":\"var(--sl-color-gray-6)\",\"terminalBackground\":\"var(--sl-color-gray-6)\",\"editorActiveTabBackground\":\"var(--sl-color-gray-6)\",\"terminalTitlebarDotsForeground\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"terminalTitlebarDotsOpacity\":\"0.75\",\"inlineButtonForeground\":\"var(--sl-color-text)\",\"frameBoxShadowCssValue\":\"none\"},\"textMarkers\":{\"markBackground\":\"#ffffff17\",\"markBorderColor\":\"#ffffff40\"}}},{\"name\":\"Night Owl Light\",\"type\":\"light\",\"colors\":{\"focusBorder\":\"#93a1a1\",\"foreground\":\"#403f53\",\"disabledForeground\":\"#61616180\",\"descriptionForeground\":\"#403f53\",\"errorForeground\":\"#403f53\",\"icon.foreground\":\"#424242\",\"contrastActiveBorder\":null,\"contrastBorder\":null,\"textBlockQuote.background\":\"#7f7f7f1a\",\"textBlockQuote.border\":\"#007acc80\",\"textCodeBlock.background\":\"#dcdcdc66\",\"textLink.activeForeground\":\"#006ab1\",\"textLink.foreground\":\"#006ab1\",\"textPreformat.foreground\":\"#a31515\",\"textSeparator.foreground\":\"#0000002e\",\"editor.background\":\"#f6f7f9\",\"editor.foreground\":\"#403f53\",\"editorLineNumber.foreground\":\"#90a7b2\",\"editorLineNumber.activeForeground\":\"#403f53\",\"editorActiveLineNumber.foreground\":\"#0b216f\",\"editor.selectionBackground\":\"#e0e0e0\",\"editor.inactiveSelectionBackground\":\"#e0e0e080\",\"editor.selectionHighlightBackground\":\"#339cec33\",\"editorError.foreground\":\"#e64d49\",\"editorWarning.foreground\":\"#daaa01\",\"editorInfo.foreground\":\"#1a85ff\",\"editorHint.foreground\":\"#6c6c6c\",\"problemsErrorIcon.foreground\":\"#e64d49\",\"problemsWarningIcon.foreground\":\"#daaa01\",\"problemsInfoIcon.foreground\":\"#1a85ff\",\"editor.findMatchBackground\":\"#93a1a16c\",\"editor.findMatchHighlightBackground\":\"#93a1a16c\",\"editor.findRangeHighlightBackground\":\"#7497a633\",\"editorLink.activeForeground\":\"#0000ff\",\"editorLightBulb.foreground\":\"#ddb100\",\"editorLightBulbAutoFix.foreground\":\"#007acc\",\"diffEditor.insertedTextBackground\":\"#9ccc2c40\",\"diffEditor.insertedTextBorder\":null,\"diffEditor.removedTextBackground\":\"#ff000033\",\"diffEditor.removedTextBorder\":null,\"diffEditor.insertedLineBackground\":\"#9bb95533\",\"diffEditor.removedLineBackground\":\"#ff000033\",\"editorStickyScroll.background\":\"#fbfbfb\",\"editorStickyScrollHover.background\":\"#f0f0f0\",\"editorInlayHint.background\":\"#2aa29899\",\"editorInlayHint.foreground\":\"#f0f0f0\",\"editorInlayHint.typeBackground\":\"#2aa29899\",\"editorInlayHint.typeForeground\":\"#f0f0f0\",\"editorInlayHint.parameterBackground\":\"#2aa29899\",\"editorInlayHint.parameterForeground\":\"#f0f0f0\",\"editorPane.background\":\"#fbfbfb\",\"editorGroup.emptyBackground\":null,\"editorGroup.focusedEmptyBorder\":null,\"editorGroupHeader.tabsBackground\":\"var(--sl-color-gray-6)\",\"editorGroupHeader.tabsBorder\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"editorGroupHeader.noTabsBackground\":\"#f0f0f0\",\"editorGroupHeader.border\":null,\"editorGroup.border\":\"#f0f0f0\",\"editorGroup.dropBackground\":\"#2677cb2d\",\"editorGroup.dropIntoPromptForeground\":\"#403f53\",\"editorGroup.dropIntoPromptBackground\":\"#f0f0f0\",\"editorGroup.dropIntoPromptBorder\":null,\"sideBySideEditor.horizontalBorder\":\"#f0f0f0\",\"sideBySideEditor.verticalBorder\":\"#f0f0f0\",\"scrollbar.shadow\":\"#cccccc\",\"scrollbarSlider.background\":\"#0000001a\",\"scrollbarSlider.hoverBackground\":\"#00000055\",\"scrollbarSlider.activeBackground\":\"#00000099\",\"panel.background\":\"#f0f0f0\",\"panel.border\":\"#d9d9d9\",\"panelTitle.activeBorder\":\"#424242\",\"panelTitle.activeForeground\":\"#424242\",\"panelTitle.inactiveForeground\":\"#424242bf\",\"panelSectionHeader.background\":\"#80808051\",\"terminal.background\":\"#f6f6f6\",\"widget.shadow\":\"#d9d9d9\",\"editorWidget.background\":\"#f0f0f0\",\"editorWidget.foreground\":\"#403f53\",\"editorWidget.border\":\"#d9d9d9\",\"quickInput.background\":\"#f0f0f0\",\"quickInput.foreground\":\"#403f53\",\"quickInputTitle.background\":\"#0000000f\",\"pickerGroup.foreground\":\"#403f53\",\"pickerGroup.border\":\"#d9d9d9\",\"editor.hoverHighlightBackground\":\"#339cec33\",\"editorHoverWidget.background\":\"#f0f0f0\",\"editorHoverWidget.foreground\":\"#403f53\",\"editorHoverWidget.border\":\"#d9d9d9\",\"editorHoverWidget.statusBarBackground\":\"#e4e4e4\",\"titleBar.activeBackground\":\"var(--sl-color-gray-6)\",\"titleBar.activeForeground\":\"var(--sl-color-text)\",\"titleBar.inactiveBackground\":\"#f0f0f099\",\"titleBar.inactiveForeground\":\"#33333399\",\"titleBar.border\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"toolbar.hoverBackground\":\"#b8b8b850\",\"toolbar.activeBackground\":\"#a6a6a650\",\"tab.activeBackground\":\"#f6f6f6\",\"tab.unfocusedActiveBackground\":\"#f6f6f6\",\"tab.inactiveBackground\":\"#f0f0f0\",\"tab.unfocusedInactiveBackground\":\"#f0f0f0\",\"tab.activeForeground\":\"var(--sl-color-text)\",\"tab.inactiveForeground\":\"#403f53\",\"tab.unfocusedActiveForeground\":\"#403f53b3\",\"tab.unfocusedInactiveForeground\":\"#403f5380\",\"tab.hoverBackground\":null,\"tab.unfocusedHoverBackground\":null,\"tab.hoverForeground\":null,\"tab.unfocusedHoverForeground\":null,\"tab.border\":\"#f0f0f0\",\"tab.lastPinnedBorder\":\"#a9a9a9\",\"tab.activeBorder\":\"transparent\",\"tab.unfocusedActiveBorder\":null,\"tab.activeBorderTop\":\"var(--sl-color-accent)\",\"tab.unfocusedActiveBorderTop\":null,\"tab.hoverBorder\":null,\"tab.unfocusedHoverBorder\":null,\"tab.activeModifiedBorder\":\"#2aa298\",\"tab.inactiveModifiedBorder\":\"#93a1a1\",\"tab.unfocusedActiveModifiedBorder\":\"#93a1a1\",\"tab.unfocusedInactiveModifiedBorder\":\"#93a1a1\",\"badge.background\":\"#2aa298\",\"badge.foreground\":\"#f0f0f0\",\"button.background\":\"#2aa298\",\"button.foreground\":\"#f0f0f0\",\"button.border\":null,\"button.separator\":\"#f0f0f066\",\"button.hoverBackground\":\"#22827a\",\"button.secondaryBackground\":\"#5f6a79\",\"button.secondaryForeground\":\"#ffffff\",\"button.secondaryHoverBackground\":\"#4c5561\",\"dropdown.background\":\"#f0f0f0\",\"dropdown.foreground\":\"#403f53\",\"dropdown.border\":\"#d9d9d9\",\"list.activeSelectionBackground\":\"#d3e8f8\",\"list.activeSelectionForeground\":\"#403f53\",\"tree.indentGuidesStroke\":\"#a9a9a9\",\"input.background\":\"#f0f0f0\",\"input.foreground\":\"#403f53\",\"input.placeholderForeground\":\"#93a1a1\",\"inputOption.activeBorder\":\"#2aa298\",\"inputOption.hoverBackground\":\"#b8b8b850\",\"inputOption.activeBackground\":\"#93a1a133\",\"inputOption.activeForeground\":\"#000000\",\"inputValidation.infoBackground\":\"#f0f0f0\",\"inputValidation.infoBorder\":\"#d0d0d0\",\"inputValidation.warningBackground\":\"#daaa01\",\"inputValidation.warningBorder\":\"#e0af02\",\"inputValidation.errorBackground\":\"#f76e6e\",\"inputValidation.errorBorder\":\"#de3d3b\",\"keybindingLabel.background\":\"#dddddd66\",\"keybindingLabel.foreground\":\"#555555\",\"keybindingLabel.border\":\"#cccccc66\",\"keybindingLabel.bottomBorder\":\"#bbbbbb66\",\"menu.foreground\":\"#403f53\",\"menu.background\":\"#f0f0f0\",\"menu.selectionForeground\":\"#403f53\",\"menu.selectionBackground\":\"#d3e8f8\",\"menu.separatorBackground\":\"#d4d4d4\",\"editor.snippetTabstopHighlightBackground\":\"#0a326433\",\"editor.snippetFinalTabstopHighlightBorder\":\"#0a326480\",\"terminal.ansiBlack\":\"#403f53\",\"terminal.ansiRed\":\"#de3d3b\",\"terminal.ansiGreen\":\"#08916a\",\"terminal.ansiYellow\":\"#e0af02\",\"terminal.ansiBlue\":\"#288ed7\",\"terminal.ansiMagenta\":\"#d6438a\",\"terminal.ansiCyan\":\"#2aa298\",\"terminal.ansiWhite\":\"#f0f0f0\",\"terminal.ansiBrightBlack\":\"#403f53\",\"terminal.ansiBrightRed\":\"#de3d3b\",\"terminal.ansiBrightGreen\":\"#08916a\",\"terminal.ansiBrightYellow\":\"#daaa01\",\"terminal.ansiBrightBlue\":\"#288ed7\",\"terminal.ansiBrightMagenta\":\"#d6438a\",\"terminal.ansiBrightCyan\":\"#2aa298\",\"terminal.ansiBrightWhite\":\"#f0f0f0\",\"selection.background\":\"#7a8181ad\",\"notifications.background\":\"#f0f0f0\",\"notifications.foreground\":\"#403f53\",\"notificationLink.foreground\":\"#994cc3\",\"notifications.border\":\"#cccccc\",\"notificationCenter.border\":\"#cccccc\",\"notificationToast.border\":\"#cccccc\",\"notificationCenterHeader.foreground\":\"#403f53\",\"notificationCenterHeader.background\":\"#f0f0f0\",\"input.border\":\"#d9d9d9\",\"progressBar.background\":\"#2aa298\",\"list.inactiveSelectionBackground\":\"#e0e7ea\",\"list.inactiveSelectionForeground\":\"#403f53\",\"list.focusBackground\":\"#d3e8f8\",\"list.hoverBackground\":\"#d3e8f8\",\"list.focusForeground\":\"#403f53\",\"list.hoverForeground\":\"#403f53\",\"list.highlightForeground\":\"#403f53\",\"list.errorForeground\":\"#e64d49\",\"list.warningForeground\":\"#daaa01\",\"activityBar.background\":\"#f0f0f0\",\"activityBar.foreground\":\"#403f53\",\"activityBar.dropBackground\":\"#d0d0d0\",\"activityBarBadge.background\":\"#403f53\",\"activityBarBadge.foreground\":\"#f0f0f0\",\"activityBar.border\":\"#f0f0f0\",\"sideBar.background\":\"#f0f0f0\",\"sideBar.foreground\":\"#403f53\",\"sideBarTitle.foreground\":\"#403f53\",\"sideBar.border\":\"#f0f0f0\",\"editorGroup.background\":\"#f6f6f6\",\"editorCursor.foreground\":\"#90a7b2\",\"editor.wordHighlightBackground\":\"#339cec33\",\"editor.wordHighlightStrongBackground\":\"#007dd659\",\"editor.lineHighlightBackground\":\"#f0f0f0\",\"editor.rangeHighlightBackground\":\"#7497a633\",\"editorWhitespace.foreground\":\"#d9d9d9\",\"editorIndentGuide.background\":\"#d9d9d9\",\"editorCodeLens.foreground\":\"#403f53\",\"editorBracketMatch.background\":\"#d3e8f8\",\"editorBracketMatch.border\":\"#2aa298\",\"editorError.border\":\"#fbfbfb\",\"editorWarning.border\":\"#daaa01\",\"editorGutter.addedBackground\":\"#49d0c5\",\"editorGutter.modifiedBackground\":\"#6fbef6\",\"editorGutter.deletedBackground\":\"#f76e6e\",\"editorRuler.foreground\":\"#d9d9d9\",\"editorOverviewRuler.errorForeground\":\"#e64d49\",\"editorOverviewRuler.warningForeground\":\"#daaa01\",\"editorSuggestWidget.background\":\"#f0f0f0\",\"editorSuggestWidget.foreground\":\"#403f53\",\"editorSuggestWidget.highlightForeground\":\"#403f53\",\"editorSuggestWidget.selectedBackground\":\"#d3e8f8\",\"editorSuggestWidget.border\":\"#d9d9d9\",\"debugExceptionWidget.background\":\"#f0f0f0\",\"debugExceptionWidget.border\":\"#d9d9d9\",\"editorMarkerNavigation.background\":\"#d0d0d0\",\"editorMarkerNavigationError.background\":\"#f76e6e\",\"editorMarkerNavigationWarning.background\":\"#daaa01\",\"debugToolBar.background\":\"#f0f0f0\",\"extensionButton.prominentBackground\":\"#2aa298\",\"extensionButton.prominentForeground\":\"#f0f0f0\",\"statusBar.background\":\"#f0f0f0\",\"statusBar.border\":\"#f0f0f0\",\"statusBar.debuggingBackground\":\"#f0f0f0\",\"statusBar.debuggingForeground\":\"#403f53\",\"statusBar.foreground\":\"#403f53\",\"statusBar.noFolderBackground\":\"#f0f0f0\",\"statusBar.noFolderForeground\":\"#403f53\",\"peekView.border\":\"#d9d9d9\",\"peekViewEditor.background\":\"#f6f6f6\",\"peekViewEditorGutter.background\":\"#f6f6f6\",\"peekViewEditor.matchHighlightBackground\":\"#49d0c5\",\"peekViewResult.background\":\"#f0f0f0\",\"peekViewResult.fileForeground\":\"#403f53\",\"peekViewResult.lineForeground\":\"#403f53\",\"peekViewResult.matchHighlightBackground\":\"#49d0c5\",\"peekViewResult.selectionBackground\":\"#e0e7ea\",\"peekViewResult.selectionForeground\":\"#403f53\",\"peekViewTitle.background\":\"#f0f0f0\",\"peekViewTitleLabel.foreground\":\"#403f53\",\"peekViewTitleDescription.foreground\":\"#403f53\",\"terminal.foreground\":\"#403f53\"},\"fg\":\"#403f53\",\"bg\":\"#f6f7f9\",\"semanticHighlighting\":false,\"settings\":[{\"name\":\"Changed\",\"scope\":[\"markup.changed\",\"meta.diff.header.git\",\"meta.diff.header.from-file\",\"meta.diff.header.to-file\"],\"settings\":{\"foreground\":\"#556484\"}},{\"name\":\"Deleted\",\"scope\":[\"markup.deleted.diff\"],\"settings\":{\"foreground\":\"#ae3c3afd\"}},{\"name\":\"Inserted\",\"scope\":[\"markup.inserted.diff\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Global settings\",\"settings\":{\"background\":\"#011627\",\"foreground\":\"#403f53\"}},{\"name\":\"Comment\",\"scope\":[\"comment\"],\"settings\":{\"foreground\":\"#5f636f\"}},{\"name\":\"String\",\"scope\":[\"string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"String Quoted\",\"scope\":[\"string.quoted\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Support Constant Math\",\"scope\":[\"support.constant.math\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Number\",\"scope\":[\"constant.numeric\",\"constant.character.numeric\"],\"settings\":{\"foreground\":\"#aa0982\",\"fontStyle\":\"\"}},{\"name\":\"Built-in constant\",\"scope\":[\"constant.language\",\"punctuation.definition.constant\",\"variable.other.constant\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"User-defined constant\",\"scope\":[\"constant.character\",\"constant.other\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Constant Character Escape\",\"scope\":[\"constant.character.escape\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"RegExp String\",\"scope\":[\"string.regexp\",\"string.regexp keyword.other\"],\"settings\":{\"foreground\":\"#3a688f\"}},{\"name\":\"Comma in functions\",\"scope\":[\"meta.function punctuation.separator.comma\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"Variable\",\"scope\":[\"variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Keyword\",\"scope\":[\"punctuation.accessor\",\"keyword\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage\",\"scope\":[\"storage\",\"meta.var.expr\",\"meta.class meta.method.declaration meta.var.expr storage.type.js\",\"storage.type.property.js\",\"storage.type.property.ts\",\"storage.type.property.tsx\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Storage type\",\"scope\":[\"storage.type.function.arrow.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Class name\",\"scope\":[\"entity.name.class\",\"meta.class entity.name.type.class\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Inherited class\",\"scope\":[\"entity.other.inherited-class\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Function name\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Meta Tag\",\"scope\":[\"punctuation.definition.tag\",\"meta.tag\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"HTML Tag names\",\"scope\":[\"entity.name.tag\",\"meta.tag.other.html\",\"meta.tag.other.js\",\"meta.tag.other.tsx\",\"entity.name.tag.tsx\",\"entity.name.tag.js\",\"entity.name.tag\",\"meta.tag.js\",\"meta.tag.tsx\",\"meta.tag.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Tag attribute\",\"scope\":[\"entity.other.attribute-name\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Entity Name Tag Custom\",\"scope\":[\"entity.name.tag.custom\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Library (function & constant)\",\"scope\":[\"support.function\",\"support.constant\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Support Constant Property Value meta\",\"scope\":[\"support.constant.meta.property-value\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Library class/type\",\"scope\":[\"support.type\",\"support.class\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Support Variable DOM\",\"scope\":[\"support.variable.dom\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Invalid\",\"scope\":[\"invalid\"],\"settings\":{\"foreground\":\"#bb2060\"}},{\"name\":\"Invalid deprecated\",\"scope\":[\"invalid.deprecated\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Keyword Operator\",\"scope\":[\"keyword.operator\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Keyword Operator Relational\",\"scope\":[\"keyword.operator.relational\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Assignment\",\"scope\":[\"keyword.operator.assignment\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Arithmetic\",\"scope\":[\"keyword.operator.arithmetic\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Bitwise\",\"scope\":[\"keyword.operator.bitwise\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Increment\",\"scope\":[\"keyword.operator.increment\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Operator Ternary\",\"scope\":[\"keyword.operator.ternary\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Double-Slashed Comment\",\"scope\":[\"comment.line.double-slash\"],\"settings\":{\"foreground\":\"#5d6376\"}},{\"name\":\"Object\",\"scope\":[\"object\"],\"settings\":{\"foreground\":\"#58656a\"}},{\"name\":\"Null\",\"scope\":[\"constant.language.null\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Meta Brace\",\"scope\":[\"meta.brace\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Meta Delimiter Period\",\"scope\":[\"meta.delimiter.period\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Punctuation Definition String\",\"scope\":[\"punctuation.definition.string\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Punctuation Definition String Markdown\",\"scope\":[\"punctuation.definition.string.begin.markdown\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Boolean\",\"scope\":[\"constant.language.boolean\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Object Comma\",\"scope\":[\"object.comma\"],\"settings\":{\"foreground\":\"#646464\"}},{\"name\":\"Variable Parameter Function\",\"scope\":[\"variable.parameter.function\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Support Type Property Name & entity name tags\",\"scope\":[\"support.type.vendor.property-name\",\"support.constant.vendor.property-value\",\"support.type.property-name\",\"meta.property-list entity.name.tag\"],\"settings\":{\"foreground\":\"#096e72\",\"fontStyle\":\"\"}},{\"name\":\"Entity Name tag reference in stylesheets\",\"scope\":[\"meta.property-list entity.name.tag.reference\"],\"settings\":{\"foreground\":\"#286d70\"}},{\"name\":\"Constant Other Color RGB Value Punctuation Definition Constant\",\"scope\":[\"constant.other.color.rgb-value punctuation.definition.constant\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Constant Other Color\",\"scope\":[\"constant.other.color\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Keyword Other Unit\",\"scope\":[\"keyword.other.unit\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Meta Selector\",\"scope\":[\"meta.selector\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Entity Other Attribute Name Id\",\"scope\":[\"entity.other.attribute-name.id\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Meta Property Name\",\"scope\":[\"meta.property-name\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Doctypes\",\"scope\":[\"entity.name.tag.doctype\",\"meta.tag.sgml.doctype\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Punctuation Definition Parameters\",\"scope\":[\"punctuation.definition.parameters\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Keyword Control Operator\",\"scope\":[\"keyword.control.operator\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Keyword Operator Logical\",\"scope\":[\"keyword.operator.logical\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"\"}},{\"name\":\"Variable Instances\",\"scope\":[\"variable.instance\",\"variable.other.instance\",\"variable.readwrite.instance\",\"variable.other.readwrite.instance\",\"variable.other.property\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Variable Property Other object property\",\"scope\":[\"variable.other.object.property\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Variable Property Other object\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"fontStyle\":\"\"}},{\"name\":\"Entity Name Function\",\"scope\":[\"entity.name.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Keyword Operator Comparison, imports, returns and Keyword Operator Ruby\",\"scope\":[\"keyword.operator.comparison\",\"keyword.control.flow.js\",\"keyword.control.flow.ts\",\"keyword.control.flow.tsx\",\"keyword.control.ruby\",\"keyword.control.module.ruby\",\"keyword.control.class.ruby\",\"keyword.control.def.ruby\",\"keyword.control.loop.js\",\"keyword.control.loop.ts\",\"keyword.control.import.js\",\"keyword.control.import.ts\",\"keyword.control.import.tsx\",\"keyword.control.from.js\",\"keyword.control.from.ts\",\"keyword.control.from.tsx\",\"keyword.operator.instanceof.js\",\"keyword.operator.expression.instanceof.ts\",\"keyword.operator.expression.instanceof.tsx\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Keyword Control Conditional\",\"scope\":[\"keyword.control.conditional.js\",\"keyword.control.conditional.ts\",\"keyword.control.switch.js\",\"keyword.control.switch.ts\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"\"}},{\"name\":\"Support Constant, `new` keyword, Special Method Keyword, `debugger`, other keywords\",\"scope\":[\"support.constant\",\"keyword.other.special-method\",\"keyword.other.new\",\"keyword.other.debugger\",\"keyword.control\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Support Function\",\"scope\":[\"support.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Invalid Broken\",\"scope\":[\"invalid.broken\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Invalid Unimplemented\",\"scope\":[\"invalid.unimplemented\"],\"settings\":{\"foreground\":\"#486e26\"}},{\"name\":\"Invalid Illegal\",\"scope\":[\"invalid.illegal\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Language Variable\",\"scope\":[\"variable.language\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Support Variable Property\",\"scope\":[\"support.variable.property\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Variable Function\",\"scope\":[\"variable.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variable Interpolation\",\"scope\":[\"variable.interpolation\"],\"settings\":{\"foreground\":\"#a64348\"}},{\"name\":\"Meta Function Call\",\"scope\":[\"meta.function-call\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Punctuation Section Embedded\",\"scope\":[\"punctuation.section.embedded\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Punctuation Tweaks\",\"scope\":[\"punctuation.terminator.expression\",\"punctuation.definition.arguments\",\"punctuation.definition.array\",\"punctuation.section.array\",\"meta.array\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"More Punctuation Tweaks\",\"scope\":[\"punctuation.definition.list.begin\",\"punctuation.definition.list.end\",\"punctuation.separator.arguments\",\"punctuation.definition.list\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Template Strings\",\"scope\":[\"string.template meta.template.expression\"],\"settings\":{\"foreground\":\"#b23834\"}},{\"name\":\"Backtics(``) in Template Strings\",\"scope\":[\"string.template punctuation.definition.string\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Italics\",\"scope\":[\"italic\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"italic\"}},{\"name\":\"Bold\",\"scope\":[\"bold\"],\"settings\":{\"foreground\":\"#3b61b0\",\"fontStyle\":\"bold\"}},{\"name\":\"Quote\",\"scope\":[\"quote\"],\"settings\":{\"foreground\":\"#5c6285\"}},{\"name\":\"Raw Code\",\"scope\":[\"raw\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"CoffeScript Variable Assignment\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#186e73\"}},{\"name\":\"CoffeScript Parameter Function\",\"scope\":[\"variable.parameter.function.coffee\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"CoffeeScript Assignments\",\"scope\":[\"variable.assignment.coffee\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"C# Readwrite Variables\",\"scope\":[\"variable.other.readwrite.cs\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"C# Classes & Storage types\",\"scope\":[\"entity.name.type.class.cs\",\"storage.type.cs\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"C# Namespaces\",\"scope\":[\"entity.name.type.namespace.cs\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Tag names in Stylesheets\",\"scope\":[\"entity.name.tag.css\",\"entity.name.tag.less\",\"entity.name.tag.custom.css\",\"support.constant.property-value.css\"],\"settings\":{\"foreground\":\"#984e4d\",\"fontStyle\":\"\"}},{\"name\":\"Wildcard(*) selector in Stylesheets\",\"scope\":[\"entity.name.tag.wildcard.css\",\"entity.name.tag.wildcard.less\",\"entity.name.tag.wildcard.scss\",\"entity.name.tag.wildcard.sass\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"CSS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Attribute Name for CSS\",\"scope\":[\"meta.attribute-selector.css entity.other.attribute-name.attribute\",\"variable.other.readwrite.js\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Elixir Classes\",\"scope\":[\"source.elixir support.type.elixir\",\"source.elixir meta.module.elixir entity.name.class.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Functions\",\"scope\":[\"source.elixir entity.name.function\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Constants\",\"scope\":[\"source.elixir constant.other.symbol.elixir\",\"source.elixir constant.other.keywords.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir String Punctuations\",\"scope\":[\"source.elixir punctuation.definition.string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir\",\"scope\":[\"source.elixir variable.other.readwrite.module.elixir\",\"source.elixir variable.other.readwrite.module.elixir punctuation.definition.variable.elixir\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Elixir Binary Punctuations\",\"scope\":[\"source.elixir .punctuation.binary.elixir\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Closure Constant Keyword\",\"scope\":[\"constant.keyword.clojure\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Go Function Calls\",\"scope\":[\"source.go meta.function-call.go\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Go Keywords\",\"scope\":[\"source.go keyword.package.go\",\"source.go keyword.import.go\",\"source.go keyword.function.go\",\"source.go keyword.type.go\",\"source.go keyword.struct.go\",\"source.go keyword.interface.go\",\"source.go keyword.const.go\",\"source.go keyword.var.go\",\"source.go keyword.map.go\",\"source.go keyword.channel.go\",\"source.go keyword.control.go\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"Go Constants e.g. nil, string format (%s, %d, etc.)\",\"scope\":[\"source.go constant.language.go\",\"source.go constant.other.placeholder.go\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"C++ Functions\",\"scope\":[\"entity.name.function.preprocessor.cpp\",\"entity.scope.name.cpp\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"C++ Meta Namespace\",\"scope\":[\"meta.namespace-block.cpp\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"C++ Language Primitive Storage\",\"scope\":[\"storage.type.language.primitive.cpp\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"C++ Preprocessor Macro\",\"scope\":[\"meta.preprocessor.macro.cpp\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"C++ Variable Parameter\",\"scope\":[\"variable.parameter\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Powershell Variables\",\"scope\":[\"variable.other.readwrite.powershell\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Powershell Function\",\"scope\":[\"support.function.powershell\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"ID Attribute Name in HTML\",\"scope\":[\"entity.other.attribute-name.id.html\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"HTML Punctuation Definition Tag\",\"scope\":[\"punctuation.definition.tag.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"HTML Doctype\",\"scope\":[\"meta.tag.sgml.doctype.html\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"JavaScript Classes\",\"scope\":[\"meta.class entity.name.type.class.js\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"JavaScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.js\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"JavaScript Terminator\",\"scope\":[\"terminator.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Meta Punctuation Definition\",\"scope\":[\"meta.js punctuation.definition.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Entity Names in Code Documentations\",\"scope\":[\"entity.name.type.instance.jsdoc\",\"entity.name.type.instance.phpdoc\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"Other Variables in Code Documentations\",\"scope\":[\"variable.other.jsdoc\",\"variable.other.phpdoc\"],\"settings\":{\"foreground\":\"#3e697c\"}},{\"name\":\"JavaScript module imports and exports\",\"scope\":[\"variable.other.meta.import.js\",\"meta.import.js variable.other\",\"variable.other.meta.export.js\",\"meta.export.js variable.other\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Variable Parameter Function\",\"scope\":[\"variable.parameter.function.js\"],\"settings\":{\"foreground\":\"#555ea2\"}},{\"name\":\"JavaScript[React] Variable Other Object\",\"scope\":[\"variable.other.object.js\",\"variable.other.object.jsx\",\"variable.object.property.js\",\"variable.object.property.jsx\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Variables\",\"scope\":[\"variable.js\",\"variable.other.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JavaScript Entity Name Type\",\"scope\":[\"entity.name.type.js\",\"entity.name.type.module.js\"],\"settings\":{\"foreground\":\"#111111\",\"fontStyle\":\"\"}},{\"name\":\"JavaScript Support Classes\",\"scope\":[\"support.class.js\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"JSON Property Names\",\"scope\":[\"support.type.property-name.json\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"JSON Support Constants\",\"scope\":[\"support.constant.json\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"JSON Property values (string)\",\"scope\":[\"meta.structure.dictionary.value.json string.quoted.double\"],\"settings\":{\"foreground\":\"#7c5686\"}},{\"name\":\"Strings in JSON values\",\"scope\":[\"string.quoted.double.json punctuation.definition.string.json\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Specific JSON Property values like null\",\"scope\":[\"meta.structure.dictionary.json meta.structure.dictionary.value constant.language\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"JavaScript Other Variable\",\"scope\":[\"variable.other.object.js\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Ruby Variables\",\"scope\":[\"variable.other.ruby\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Ruby Class\",\"scope\":[\"entity.name.type.class.ruby\"],\"settings\":{\"foreground\":\"#984e4d\"}},{\"name\":\"Ruby Hashkeys\",\"scope\":[\"constant.language.symbol.hashkey.ruby\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Ruby Symbols\",\"scope\":[\"constant.language.symbol.ruby\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"LESS Tag names\",\"scope\":[\"entity.name.tag.less\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"LESS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.css\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Attribute Name for LESS\",\"scope\":[\"meta.attribute-selector.less entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Markdown Headings\",\"scope\":[\"markup.heading.markdown\",\"markup.heading.setext.1.markdown\",\"markup.heading.setext.2.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown Italics\",\"scope\":[\"markup.italic.markdown\"],\"settings\":{\"foreground\":\"#8844ae\",\"fontStyle\":\"italic\"}},{\"name\":\"Markdown Bold\",\"scope\":[\"markup.bold.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\",\"fontStyle\":\"bold\"}},{\"name\":\"Markdown Quote + others\",\"scope\":[\"markup.quote.markdown\"],\"settings\":{\"foreground\":\"#5c6285\"}},{\"name\":\"Markdown Raw Code + others\",\"scope\":[\"markup.inline.raw.markdown\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Markdown Links\",\"scope\":[\"markup.underline.link.markdown\",\"markup.underline.link.image.markdown\"],\"settings\":{\"foreground\":\"#954f5a\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Link Title and Description\",\"scope\":[\"string.other.link.title.markdown\",\"string.other.link.description.markdown\"],\"settings\":{\"foreground\":\"#403f53\",\"fontStyle\":\"underline\"}},{\"name\":\"Markdown Punctuation\",\"scope\":[\"punctuation.definition.string.markdown\",\"punctuation.definition.string.begin.markdown\",\"punctuation.definition.string.end.markdown\",\"meta.link.inline.markdown punctuation.definition.string\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown MetaData Punctuation\",\"scope\":[\"punctuation.definition.metadata.markdown\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Markdown List Punctuation\",\"scope\":[\"beginning.punctuation.definition.list.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Markdown Inline Raw String\",\"scope\":[\"markup.inline.raw.string.markdown\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"PHP Variables\",\"scope\":[\"variable.other.php\",\"variable.other.property.php\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Support Classes in PHP\",\"scope\":[\"support.class.php\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Punctuations in PHP function calls\",\"scope\":[\"meta.function-call.php punctuation\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"PHP Global Variables\",\"scope\":[\"variable.other.global.php\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Declaration Punctuation in PHP Global Variables\",\"scope\":[\"variable.other.global.php punctuation.definition.variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Language Constants in Python\",\"scope\":[\"constant.language.python\"],\"settings\":{\"foreground\":\"#a24848\"}},{\"name\":\"Python Function Parameter and Arguments\",\"scope\":[\"variable.parameter.function.python\",\"meta.function-call.arguments.python\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Python Function Call\",\"scope\":[\"meta.function-call.python\",\"meta.function-call.generic.python\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"Punctuations in Python\",\"scope\":[\"punctuation.python\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Decorator Functions in Python\",\"scope\":[\"entity.name.function.decorator.python\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Python Language Variable\",\"scope\":[\"source.python variable.language.special\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Python import control keyword\",\"scope\":[\"keyword.control\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"SCSS Variable\",\"scope\":[\"variable.scss\",\"variable.sass\",\"variable.parameter.url.scss\",\"variable.parameter.url.sass\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"Variables in SASS At-Rules\",\"scope\":[\"source.css.scss meta.at-rule variable\",\"source.css.sass meta.at-rule variable\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"Attribute Name for SASS\",\"scope\":[\"meta.attribute-selector.scss entity.other.attribute-name.attribute\",\"meta.attribute-selector.sass entity.other.attribute-name.attribute\"],\"settings\":{\"foreground\":\"#aa0982\"}},{\"name\":\"Tag names in SASS\",\"scope\":[\"entity.name.tag.scss\",\"entity.name.tag.sass\"],\"settings\":{\"foreground\":\"#096e72\"}},{\"name\":\"SASS Keyword Other Unit\",\"scope\":[\"keyword.other.unit.scss\",\"keyword.other.unit.sass\"],\"settings\":{\"foreground\":\"#8844ae\"}},{\"name\":\"TypeScript[React] Variables and Object Properties\",\"scope\":[\"variable.other.readwrite.alias.ts\",\"variable.other.readwrite.alias.tsx\",\"variable.other.readwrite.ts\",\"variable.other.readwrite.tsx\",\"variable.other.object.ts\",\"variable.other.object.tsx\",\"variable.object.property.ts\",\"variable.object.property.tsx\",\"variable.other.ts\",\"variable.other.tsx\",\"variable.tsx\",\"variable.ts\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript[React] Entity Name Types\",\"scope\":[\"entity.name.type.ts\",\"entity.name.type.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript[React] Node Classes\",\"scope\":[\"support.class.node.ts\",\"support.class.node.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"TypeScript[React] Entity Name Types as Parameters\",\"scope\":[\"meta.type.parameters.ts entity.name.type\",\"meta.type.parameters.tsx entity.name.type\"],\"settings\":{\"foreground\":\"#4d667b\"}},{\"name\":\"TypeScript[React] Import/Export Punctuations\",\"scope\":[\"meta.import.ts punctuation.definition.block\",\"meta.import.tsx punctuation.definition.block\",\"meta.export.ts punctuation.definition.block\",\"meta.export.tsx punctuation.definition.block\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.decorator punctuation.decorator.ts\",\"meta.decorator punctuation.decorator.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"TypeScript[React] Punctuation Decorators\",\"scope\":[\"meta.tag.js meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"YAML Entity Name Tags\",\"scope\":[\"entity.name.tag.yaml\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"JavaScript Variable Other ReadWrite\",\"scope\":[\"variable.other.readwrite.js\",\"variable.parameter\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"Support Class Component\",\"scope\":[\"support.class.component.js\",\"support.class.component.tsx\"],\"settings\":{\"foreground\":\"#aa0982\",\"fontStyle\":\"\"}},{\"name\":\"Text nested in React tags\",\"scope\":[\"meta.jsx.children\",\"meta.jsx.children.js\",\"meta.jsx.children.tsx\"],\"settings\":{\"foreground\":\"#403f53\"}},{\"name\":\"TypeScript Classes\",\"scope\":[\"meta.class entity.name.type.class.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript Entity Name Type\",\"scope\":[\"entity.name.type.tsx\",\"entity.name.type.module.tsx\"],\"settings\":{\"foreground\":\"#111111\"}},{\"name\":\"TypeScript Class Variable Keyword\",\"scope\":[\"meta.class.ts meta.var.expr.ts storage.type.ts\",\"meta.class.tsx meta.var.expr.tsx storage.type.tsx\"],\"settings\":{\"foreground\":\"#76578b\"}},{\"name\":\"TypeScript Method Declaration e.g. `constructor`\",\"scope\":[\"meta.method.declaration storage.type.ts\",\"meta.method.declaration storage.type.tsx\"],\"settings\":{\"foreground\":\"#3b61b0\"}},{\"name\":\"normalize font style of certain components\",\"scope\":[\"meta.property-list.css meta.property-value.css variable.other.less\",\"meta.property-list.scss variable.scss\",\"meta.property-list.sass variable.sass\",\"meta.brace\",\"keyword.operator.operator\",\"keyword.operator.or.regexp\",\"keyword.operator.expression.in\",\"keyword.operator.relational\",\"keyword.operator.assignment\",\"keyword.operator.comparison\",\"keyword.operator.type\",\"keyword.operator\",\"keyword\",\"punctuation.definintion.string\",\"punctuation\",\"variable.other.readwrite.js\",\"storage.type\",\"source.css\",\"string.quoted\"],\"settings\":{\"fontStyle\":\"\"}}],\"styleOverrides\":{\"frames\":{\"editorBackground\":\"var(--sl-color-gray-7)\",\"terminalBackground\":\"var(--sl-color-gray-7)\",\"editorActiveTabBackground\":\"var(--sl-color-gray-7)\",\"terminalTitlebarDotsForeground\":\"color-mix(in srgb, var(--sl-color-gray-5), transparent 25%)\",\"terminalTitlebarDotsOpacity\":\"0.75\",\"inlineButtonForeground\":\"var(--sl-color-text)\",\"frameBoxShadowCssValue\":\"none\"},\"textMarkers\":{\"markBackground\":\"#0000001a\",\"markBorderColor\":\"#00000055\"}}}],\"defaultLocale\":\"en\",\"cascadeLayer\":\"starlight.components\",\"styleOverrides\":{\"borderRadius\":\"0px\",\"borderWidth\":\"1px\",\"codePaddingBlock\":\"0.75rem\",\"codePaddingInline\":\"1rem\",\"codeFontFamily\":\"var(--__sl-font-mono)\",\"codeFontSize\":\"var(--sl-text-code)\",\"codeLineHeight\":\"var(--sl-line-height)\",\"uiFontFamily\":\"var(--__sl-font)\",\"textMarkers\":{\"lineDiffIndicatorMarginLeft\":\"0.25rem\",\"defaultChroma\":\"45\",\"backgroundOpacity\":\"60%\"}},\"plugins\":[{\"name\":\"Starlight Plugin\",\"hooks\":{}},{\"name\":\"astro-expressive-code\",\"hooks\":{}}]}]],\"remarkRehype\":{},\"gfm\":true,\"smartypants\":true},\"security\":{\"checkOrigin\":true,\"allowedDomains\":[],\"actionBodySizeLimit\":1048576},\"env\":{\"schema\":{},\"validateSecrets\":false},\"experimental\":{\"clientPrerender\":false,\"contentIntellisense\":false,\"headingIdCompat\":false,\"preserveScriptOrder\":false,\"liveContentCollections\":false,\"csp\":false,\"staticImportMetaEnv\":false,\"chromeDevtoolsWorkspace\":false,\"failOnPrerenderConflict\":false,\"svgo\":false},\"legacy\":{\"collections\":false},\"prefetch\":{\"prefetchAll\":true},\"i18n\":{\"defaultLocale\":\"en\",\"locales\":[\"en\"],\"routing\":{\"prefixDefaultLocale\":false,\"redirectToDefaultLocale\":false,\"fallbackType\":\"redirect\"}}}","docs",["Map",11,12,25,26,36,37,63,64,74,75,85,86,96,97,106,107,117,118,128,129,139,140,150,151,161,162,172,173,183,184,194,195,205,206,216,217,227,228],"core/tools",{"id":11,"data":13,"body":22,"filePath":23,"digest":24,"deferredRender":16},{"title":14,"description":15,"editUrl":16,"head":17,"template":18,"sidebar":19,"pagefind":16,"draft":20},"Tools","Built-in tools and how to create custom tools for ChatCops.",true,[],"doc",{"hidden":20,"attrs":21},false,{},"Tools extend the AI's capabilities by letting it perform actions like capturing leads, querying databases, or calling APIs.\n\n## Built-in: Lead Capture\n\nThe `LeadCaptureTool` lets the AI collect contact information from conversations:\n\n```typescript\nimport { LeadCaptureTool } from '@chatcops/core/tools';\n\nconst leadTool = new LeadCaptureTool({\n onCapture: async (lead) => {\n console.log('New lead:', lead);\n // Save to database, CRM, send webhook, etc.\n },\n});\n```\n\n### LeadData Shape\n\n```typescript\ninterface LeadData {\n name: string;\n email: string;\n company?: string;\n phone?: string;\n projectDetails: string;\n source: string;\n metadata?: Record\u003Cstring, unknown>;\n}\n```\n\nThe tool has these parameters:\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `name` | string | Yes | Full name |\n| `email` | string | Yes | Email address |\n| `company` | string | No | Company name |\n| `phone` | string | No | Phone number |\n| `projectDetails` | string | Yes | Summary of needs |\n\n## ChatTool Interface\n\nCreate custom tools by implementing the `ChatTool` interface:\n\n```typescript\ninterface ChatTool {\n name: string;\n description: string;\n parameters: Record\u003Cstring, ToolParameter>;\n required: string[];\n execute(input: Record\u003Cstring, unknown>): Promise\u003CToolResult>;\n}\n\ninterface ToolParameter {\n type: 'string' | 'number' | 'boolean';\n description: string;\n enum?: string[];\n}\n\ninterface ToolResult {\n success: boolean;\n data?: unknown;\n message?: string;\n}\n```\n\n## Custom Tool Example\n\n```typescript\nconst weatherTool: ChatTool = {\n name: 'get_weather',\n description: 'Get current weather for a city',\n parameters: {\n city: { type: 'string', description: 'City name' },\n unit: { type: 'string', description: 'Temperature unit', enum: ['celsius', 'fahrenheit'] },\n },\n required: ['city'],\n\n async execute(input) {\n const response = await fetch(\n `https://api.weather.example.com/${input.city}`\n );\n const data = await response.json();\n return {\n success: true,\n data,\n message: `It's ${data.temp}° in ${input.city}`,\n };\n },\n};\n\n// Use in server config\nchatcopsMiddleware({\n provider: { type: 'claude', apiKey: '...' },\n systemPrompt: 'Help users with weather queries.',\n tools: [weatherTool],\n});\n```\n\n## How Tools Work\n\n1. The AI decides when to call a tool based on conversation context\n2. ChatCops converts tool definitions to the provider's native format\n3. When the AI invokes a tool, `execute()` runs server-side\n4. The result is fed back to the AI, which formulates a response\n5. Tool calls are transparent to the user — they only see the final message","src/content/docs/core/tools.mdx","327d66582fca65ab","core/knowledge-base",{"id":25,"data":27,"body":33,"filePath":34,"digest":35,"deferredRender":16},{"title":28,"description":29,"editUrl":16,"head":30,"template":18,"sidebar":31,"pagefind":16,"draft":20},"Knowledge Base","Provide context-aware responses with text and FAQ knowledge sources.",[],{"hidden":20,"attrs":32},{},"Knowledge sources give the AI relevant context for each query, grounding responses in your actual content.\n\n## FAQ Knowledge Source\n\nBest for structured question-answer pairs:\n\n```typescript\nimport { FAQKnowledgeSource } from '@chatcops/core/knowledge';\n\nconst faq = new FAQKnowledgeSource([\n { question: 'What are your business hours?', answer: '9am-5pm EST, Monday to Friday.' },\n { question: 'Do you offer refunds?', answer: 'Yes, full refunds within 30 days.' },\n { question: 'How do I contact support?', answer: 'Email support@example.com or use this chat!' },\n { question: 'What payment methods do you accept?', answer: 'Visa, Mastercard, PayPal, and wire transfer.' },\n]);\n```\n\n### How FAQ Matching Works\n\n1. User's query is tokenized into words\n2. Each FAQ pair is scored by word frequency overlap (question + answer)\n3. Top 5 matching FAQs are returned as context\n4. Context is formatted as `Q: ...\\nA: ...` and injected into the AI prompt\n\n## Text Knowledge Source\n\nBest for unstructured content (documentation, product descriptions, policies):\n\n```typescript\nimport { TextKnowledgeSource } from '@chatcops/core/knowledge';\n\nconst docs = new TextKnowledgeSource(\n `Our company was founded in 2020 by Jane Doe.\n We specialize in AI-powered customer support solutions.\n Our flagship product is ChatCops, an embeddable chatbot widget.\n We serve over 500 businesses worldwide.\n Our headquarters is in San Francisco, CA.`,\n { chunkSize: 500 } // Optional: characters per chunk\n);\n```\n\n### How Text Matching Works\n\n1. Source text is split into chunks at initialization\n2. User's query words are matched against each chunk\n3. Top 3 relevant chunks are returned\n4. Context is prefixed with `\"Relevant context:\\n\"`\n\n## KnowledgeSource Interface\n\n```typescript\ninterface KnowledgeSource {\n type: string;\n getContext(query: string): Promise\u003Cstring>;\n}\n```\n\n## Multiple Sources\n\nCombine multiple knowledge sources — all contexts are concatenated:\n\n```typescript\nchatcopsMiddleware({\n provider: { type: 'claude', apiKey: '...' },\n systemPrompt: 'Answer using the provided context. If unsure, say so.',\n knowledge: [\n new FAQKnowledgeSource(faqs),\n new TextKnowledgeSource(productDocs),\n new TextKnowledgeSource(policyDocs),\n ],\n});\n```\n\n## Custom Knowledge Source\n\nImplement `KnowledgeSource` for database-backed or vector search:\n\n```typescript\nclass VectorKnowledgeSource implements KnowledgeSource {\n type = 'vector';\n\n async getContext(query: string): Promise\u003Cstring> {\n const results = await vectorDB.search(query, { topK: 5 });\n return results.map(r => r.text).join('\\n\\n');\n }\n}\n```","src/content/docs/core/knowledge-base.mdx","68db4953598819f6","index",{"id":36,"data":38,"body":60,"filePath":61,"digest":62,"deferredRender":16},{"title":39,"description":40,"editUrl":16,"head":41,"template":42,"hero":43,"sidebar":58,"pagefind":16,"draft":20},"ChatCops Documentation","Learn how to add an AI chatbot to any website with ChatCops.",[],"splash",{"tagline":44,"actions":45},"Universal embeddable AI chatbot widget. Multi-provider, zero dependencies, fully customizable.",[46,53],{"text":47,"link":48,"variant":49,"icon":50},"Quick Start","/getting-started/quick-start","primary",{"type":51,"name":52},"icon","right-arrow",{"text":54,"link":55,"variant":49,"icon":56},"View on GitHub","https://github.com/codercops/chatcops",{"type":51,"name":57},"external",{"hidden":20,"attrs":59},{},"import { Card, CardGrid } from '@astrojs/starlight/components';\n\n## Get Started\n\n\u003CCardGrid>\n \u003CCard title=\"Quick Start\" icon=\"rocket\">\n Add a chatbot to your website in under 5 minutes. [Get started →](/getting-started/quick-start)\n \u003C/Card>\n \u003CCard title=\"Widget Config\" icon=\"setting\">\n Customize appearance, branding, and behavior. [Configure →](/widget/configuration)\n \u003C/Card>\n \u003CCard title=\"Server Setup\" icon=\"laptop\">\n Set up your backend with Express, Vercel, or Cloudflare. [Setup →](/server/setup)\n \u003C/Card>\n \u003CCard title=\"AI Providers\" icon=\"puzzle\">\n Connect to Claude, OpenAI, or Gemini. [Providers →](/core/providers)\n \u003C/Card>\n\u003C/CardGrid>\n\n## Packages\n\n| Package | Description |\n|---------|-------------|\n| `@chatcops/widget` | Embeddable chat widget (IIFE + ESM), Shadow DOM isolated, ~7KB gzipped |\n| `@chatcops/server` | Server handler + Express, Vercel, Cloudflare adapters |\n| `@chatcops/core` | AI provider abstraction, tools, knowledge base, i18n, analytics |\n\n## Architecture\n\n```\n┌──────────────────┐ ┌──────────────────┐\n│ Your Website │ SSE │ Your Server │\n│ │ ──────► │ │\n│ \u003Cscript> tag │ ◄────── │ @chatcops/server│\n│ @chatcops/widget│ stream │ ├─ Provider │\n│ Shadow DOM │ │ ├─ Knowledge │\n│ Chat Panel │ │ ├─ Tools │\n└──────────────────┘ │ └─ Analytics │\n └──────────────────┘\n```","src/content/docs/index.mdx","e70196edcae7ad87","core/analytics",{"id":63,"data":65,"body":71,"filePath":72,"digest":73,"deferredRender":16},{"title":66,"description":67,"editUrl":16,"head":68,"template":18,"sidebar":69,"pagefind":16,"draft":20},"Analytics","Track conversations, messages, and lead captures with the built-in analytics collector.",[],{"hidden":20,"attrs":70},{},"ChatCops includes a lightweight analytics collector that tracks conversation metrics server-side.\n\n## Enabling Analytics\n\n```typescript\nchatcopsMiddleware({\n provider: { type: 'claude', apiKey: '...' },\n systemPrompt: '...',\n analytics: true, // Enable analytics tracking\n});\n```\n\n## Tracked Events\n\nWhen `analytics: true`, the server automatically tracks:\n\n| Event | When |\n|-------|------|\n| `conversation:started` | New conversation ID first seen |\n| `message:sent` | User sends a message |\n| `message:received` | AI responds |\n| `lead:captured` | Lead capture tool fires |\n\n## AnalyticsCollector API\n\n```typescript\nimport { AnalyticsCollector } from '@chatcops/core/analytics';\n\nconst analytics = new AnalyticsCollector();\n\n// Track custom events\nanalytics.track('custom:event', { key: 'value' });\n\n// Get aggregated stats\nconst stats = analytics.getStats();\n// {\n// totalConversations: 150,\n// totalMessages: 2340,\n// leadsCaptured: 23,\n// averageMessagesPerConversation: 15.6,\n// eventCounts: { 'conversation:started': 150, ... }\n// }\n\n// Get raw events (optionally filter by type)\nconst allEvents = analytics.getEvents();\nconst leads = analytics.getEvents('lead:captured');\n\n// Clear all events\nanalytics.clear();\n```\n\n## AnalyticsStats Interface\n\n```typescript\ninterface AnalyticsStats {\n totalConversations: number;\n totalMessages: number;\n leadsCaptured: number;\n averageMessagesPerConversation: number;\n eventCounts: Record\u003Cstring, number>;\n}\n\ninterface AnalyticsEvent {\n type: string;\n data?: Record\u003Cstring, unknown>;\n timestamp: number;\n}\n```\n\n## Storage\n\nThe built-in collector stores events in memory (max 1000 events). For production use, export events to your analytics platform:\n\n```typescript\nconst collector = new AnalyticsCollector();\n\n// Periodically flush to your analytics service\nsetInterval(() => {\n const events = collector.getEvents();\n if (events.length > 0) {\n sendToAnalytics(events);\n collector.clear();\n }\n}, 60_000); // Every minute\n```\n\n## Client-Side Events\n\nCombine with widget events for full-stack analytics:\n\n```typescript\n// Client-side\nChatCops.on('open', () => gtag('event', 'chat_opened'));\nChatCops.on('message', (m) => {\n if (m.role === 'user') gtag('event', 'chat_message_sent');\n});\n\n// Server-side (automatic with analytics: true)\n// conversation:started, message:sent, message:received, lead:captured\n```","src/content/docs/core/analytics.mdx","b5b63f32cfaf29f6","examples/express-full",{"id":74,"data":76,"body":82,"filePath":83,"digest":84,"deferredRender":16},{"title":77,"description":78,"editUrl":16,"head":79,"template":18,"sidebar":80,"pagefind":16,"draft":20},"Express Full Example","Complete Express.js server with all ChatCops features.",[],{"hidden":20,"attrs":81},{},"A production-ready Express server with lead capture, knowledge base, webhooks, and analytics.\n\n## Complete Server\n\n```typescript\nimport express from 'express';\nimport { chatcopsMiddleware } from '@chatcops/server';\nimport { LeadCaptureTool } from '@chatcops/core/tools';\nimport { FAQKnowledgeSource, TextKnowledgeSource } from '@chatcops/core/knowledge';\n\nconst app = express();\napp.use(express.json());\n\n// Health check\napp.get('/health', (req, res) => res.json({ status: 'ok' }));\n\n// ChatCops endpoint\napp.post('/chat', chatcopsMiddleware({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001',\n },\n\n systemPrompt: `You are a helpful customer support assistant for Acme Corp.\n Be friendly, concise, and professional.\n If someone asks about pricing, refer to our plans: Starter ($0), Pro ($29/mo), Enterprise (custom).\n If someone shares their contact information or wants to be contacted,\n use the capture_lead tool to save their details.\n Always be transparent about being an AI assistant.`,\n\n tools: [\n new LeadCaptureTool({\n onCapture: async (lead) => {\n console.log('New lead captured:', lead.email);\n // Save to database\n // await db.leads.create(lead);\n\n // Send to webhook/CRM\n // await fetch('https://hooks.zapier.com/...', {\n // method: 'POST',\n // body: JSON.stringify(lead),\n // });\n },\n }),\n ],\n\n knowledge: [\n new FAQKnowledgeSource([\n { question: 'What are your business hours?', answer: '9am-5pm EST, Monday to Friday.' },\n { question: 'Do you offer refunds?', answer: 'Full refunds within 30 days of purchase.' },\n { question: 'How do I contact support?', answer: 'Email support@acme.com or use this chat.' },\n { question: 'What payment methods do you accept?', answer: 'Visa, Mastercard, PayPal, wire transfer.' },\n { question: 'Do you have an API?', answer: 'Yes! Check docs.acme.com for our REST API.' },\n ]),\n new TextKnowledgeSource(\n `Acme Corp was founded in 2020. We build AI-powered customer support tools.\n Our flagship product helps businesses add intelligent chat to their websites.\n We serve over 500 businesses across 30 countries.\n Our team is based in San Francisco, CA with remote employees worldwide.`\n ),\n ],\n\n webhooks: [\n {\n url: process.env.WEBHOOK_URL || 'https://hooks.example.com/chatcops',\n events: ['message:received', 'lead:captured'],\n secret: process.env.WEBHOOK_SECRET,\n },\n ],\n\n rateLimit: { maxRequests: 30, windowMs: 60_000 },\n analytics: true,\n cors: process.env.CORS_ORIGIN || '*',\n}));\n\nconst PORT = process.env.PORT ?? 3001;\napp.listen(PORT, () => {\n console.log(`ChatCops server running on http://localhost:${PORT}`);\n});\n```\n\n## Widget HTML\n\n```html\n\u003C!DOCTYPE html>\n\u003Chtml>\n\u003Chead>\n \u003Ctitle>Acme Corp\u003C/title>\n\u003C/head>\n\u003Cbody>\n \u003Ch1>Welcome to Acme Corp\u003C/h1>\n\n \u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"http://localhost:3001/chat\"\n data-accent=\"#6366f1\"\n data-brand-name=\"Acme Support\"\n data-brand-subtitle=\"Usually replies instantly\"\n data-welcome-message=\"Hi! I'm Acme's AI assistant. How can I help you today?\"\n data-welcome-bubble=\"Need help? Chat with us!\"\n data-welcome-bubble-delay=\"5000\"\n >\u003C/script>\n\u003C/body>\n\u003C/html>\n```\n\n## Environment Variables\n\n```bash\nANTHROPIC_API_KEY=sk-ant-...\nWEBHOOK_URL=https://hooks.example.com/chatcops\nWEBHOOK_SECRET=your-webhook-secret\nCORS_ORIGIN=https://your-website.com\nPORT=3001\n```","src/content/docs/examples/express-full.mdx","1de9dd0c9f238732","core/providers",{"id":85,"data":87,"body":93,"filePath":94,"digest":95,"deferredRender":16},{"title":88,"description":89,"editUrl":16,"head":90,"template":18,"sidebar":91,"pagefind":16,"draft":20},"AI Providers","Connect to Claude, OpenAI, or Gemini with a unified interface.",[],{"hidden":20,"attrs":92},{},"ChatCops abstracts AI providers behind a unified `AIProvider` interface. Switch between Claude, OpenAI, and Gemini by changing one config value.\n\n## Provider Configuration\n\n```typescript\n// Claude (Anthropic)\nprovider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001', // Default\n}\n\n// OpenAI\nprovider: {\n type: 'openai',\n apiKey: process.env.OPENAI_API_KEY!,\n model: 'gpt-4o-mini', // Default\n}\n\n// Google Gemini\nprovider: {\n type: 'gemini',\n apiKey: process.env.GOOGLE_AI_API_KEY!,\n model: 'gemini-2.0-flash', // Default\n}\n```\n\n## Default Models\n\n| Provider | Default Model | Streaming |\n|----------|--------------|-----------|\n| Claude | `claude-haiku-4-5-20251001` | SSE via `messages.stream()` |\n| OpenAI | `gpt-4o-mini` | SSE via `chat.completions.create({ stream: true })` |\n| Gemini | `gemini-2.0-flash` | SSE via `generateContentStream()` |\n\n## AIProvider Interface\n\n```typescript\ninterface AIProvider {\n name: string;\n chat(params: ProviderChatParams): AsyncGenerator\u003Cstring>;\n chatSync(params: ProviderChatParams): Promise\u003Cstring>;\n}\n\ninterface ProviderChatParams {\n messages: ChatMessage[];\n systemPrompt: string;\n tools?: ToolDefinition[];\n maxTokens?: number; // Default: 1024\n temperature?: number; // Default: provider-specific\n}\n```\n\n## Direct Provider Usage\n\nFor advanced use cases, you can use providers directly:\n\n```typescript\nimport { createProvider } from '@chatcops/core';\n\nconst provider = await createProvider({\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n});\n\n// Streaming\nfor await (const token of provider.chat({\n messages: [{ id: '1', role: 'user', content: 'Hello!', timestamp: Date.now() }],\n systemPrompt: 'You are helpful.',\n})) {\n process.stdout.write(token);\n}\n\n// Non-streaming\nconst response = await provider.chatSync({\n messages: [{ id: '1', role: 'user', content: 'Hello!', timestamp: Date.now() }],\n systemPrompt: 'You are helpful.',\n});\nconsole.log(response);\n```\n\n## Tool Support\n\nAll providers support tool calling with a unified format. ChatCops automatically converts tool definitions to each provider's native format:\n\n- Claude: `tools` array with `input_schema`\n- OpenAI: `tools` array with `function.parameters`\n- Gemini: `functionDeclarations` in `tools`\n\n```typescript\nchatcopsMiddleware({\n provider: { type: 'claude', apiKey: '...' },\n systemPrompt: '...',\n tools: [new LeadCaptureTool({ onCapture: saveLead })],\n});\n```\n\nThe same tool definition works across all providers without changes.","src/content/docs/core/providers.mdx","22f44791f6bd3a90","getting-started/quick-start",{"id":96,"data":98,"body":103,"filePath":104,"digest":105,"deferredRender":16},{"title":47,"description":99,"editUrl":16,"head":100,"template":18,"sidebar":101,"pagefind":16,"draft":20},"Add an AI chatbot to your website in under 5 minutes.",[],{"hidden":20,"attrs":102},{},"Get ChatCops running in three steps: add the widget, set up a server, and start chatting.\n\n## 1. Add the Widget\n\nDrop a single `\u003Cscript>` tag into your HTML. The widget auto-initializes and appears as a floating button in the bottom-right corner.\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://your-api.com/chat\"\n data-accent=\"#6366f1\"\n>\u003C/script>\n```\n\nThe widget accepts configuration via `data-*` attributes:\n\n| Attribute | Description | Default |\n|-----------|-------------|---------|\n| `data-api-url` | Your server endpoint (required) | — |\n| `data-accent` | Primary accent color | `#6366f1` |\n| `data-brand-name` | Name shown in chat header | `\"AI Assistant\"` |\n| `data-welcome-message` | First message from the bot | — |\n| `data-position` | `bottom-right` or `bottom-left` | `bottom-right` |\n\n## 2. Set Up the Server\n\nInstall the server package:\n\n```bash\nnpm install @chatcops/server express\n```\n\nCreate a minimal Express server:\n\n```typescript\nimport express from 'express';\nimport { chatcopsMiddleware } from '@chatcops/server';\n\nconst app = express();\napp.use(express.json());\n\napp.post('/chat', chatcopsMiddleware({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001',\n },\n systemPrompt: `You are a helpful customer support assistant for our website.\n Be friendly, concise, and helpful.`,\n cors: '*',\n rateLimit: { maxRequests: 30, windowMs: 60_000 },\n}));\n\napp.listen(3001, () => {\n console.log('ChatCops server running on http://localhost:3001');\n});\n```\n\n## 3. Test It\n\n1. Start your server: `node server.js`\n2. Open your HTML page in a browser\n3. Click the chat bubble — you're live!\n\n## Next Steps\n\n- [Widget Configuration](/widget/configuration) — customize appearance and behavior\n- [Server Setup](/server/setup) — advanced server configuration\n- [AI Providers](/core/providers) — switch between Claude, OpenAI, and Gemini\n- [Theming](/widget/theming) — match the widget to your brand","src/content/docs/getting-started/quick-start.mdx","9adfb8b6ea180369","examples/vercel-full",{"id":106,"data":108,"body":114,"filePath":115,"digest":116,"deferredRender":16},{"title":109,"description":110,"editUrl":16,"head":111,"template":18,"sidebar":112,"pagefind":16,"draft":20},"Vercel Edge Full Example","Complete Vercel Edge Function with all ChatCops features.",[],{"hidden":20,"attrs":113},{},"A production-ready Vercel Edge Function with lead capture, knowledge base, and analytics.\n\n## API Route (`api/chat.ts`)\n\n```typescript\nimport { chatcopsVercelHandler } from '@chatcops/server';\nimport { LeadCaptureTool } from '@chatcops/core/tools';\nimport { FAQKnowledgeSource } from '@chatcops/core/knowledge';\n\nexport const config = { runtime: 'edge' };\n\nexport default chatcopsVercelHandler({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001',\n },\n\n systemPrompt: `You are a helpful AI assistant for our SaaS product.\n Answer questions about features, pricing, and getting started.\n If a user shares contact info, capture it with the lead tool.`,\n\n tools: [\n new LeadCaptureTool({\n onCapture: async (lead) => {\n // Send to webhook (e.g., Zapier, Make, n8n)\n await fetch(process.env.WEBHOOK_URL!, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n type: 'lead_captured',\n lead,\n timestamp: new Date().toISOString(),\n }),\n });\n },\n }),\n ],\n\n knowledge: [\n new FAQKnowledgeSource([\n { question: 'What is your pricing?', answer: 'Starter: Free, Pro: $29/mo, Enterprise: Custom.' },\n { question: 'Is there a free trial?', answer: 'Yes, 14-day free trial on all paid plans.' },\n { question: 'What integrations do you support?', answer: 'Slack, Discord, Zapier, webhooks, and REST API.' },\n ]),\n ],\n\n cors: '*',\n analytics: true,\n});\n```\n\n## Next.js Integration\n\nIf using Next.js, place the file at `app/api/chat/route.ts`:\n\n```typescript\nimport { chatcopsVercelHandler } from '@chatcops/server';\n\nexport const runtime = 'edge';\n\nconst handler = chatcopsVercelHandler({\n provider: {\n type: 'openai',\n apiKey: process.env.OPENAI_API_KEY!,\n },\n systemPrompt: 'You are a helpful assistant.',\n cors: '*',\n});\n\nexport const POST = handler;\n```\n\n## Widget in Next.js Layout\n\n```tsx\n// app/layout.tsx\nimport Script from 'next/script';\n\nexport default function RootLayout({ children }) {\n return (\n \u003Chtml>\n \u003Cbody>\n {children}\n \u003CScript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"/api/chat\"\n data-accent=\"#6366f1\"\n data-brand-name=\"Support\"\n strategy=\"lazyOnload\"\n />\n \u003C/body>\n \u003C/html>\n );\n}\n```\n\n## Environment Variables\n\nSet in Vercel dashboard → Settings → Environment Variables:\n\n```bash\nANTHROPIC_API_KEY=sk-ant-...\nWEBHOOK_URL=https://hooks.zapier.com/...\n```","src/content/docs/examples/vercel-full.mdx","0a148f215567b4a7","examples/cloudflare-full",{"id":117,"data":119,"body":125,"filePath":126,"digest":127,"deferredRender":16},{"title":120,"description":121,"editUrl":16,"head":122,"template":18,"sidebar":123,"pagefind":16,"draft":20},"Cloudflare Worker Full Example","Complete Cloudflare Worker with all ChatCops features.",[],{"hidden":20,"attrs":124},{},"A production-ready Cloudflare Worker with lead capture, knowledge base, and rate limiting.\n\n## Worker (`src/index.ts`)\n\n```typescript\nimport { chatcopsCloudflareHandler } from '@chatcops/server';\nimport { LeadCaptureTool } from '@chatcops/core/tools';\nimport { FAQKnowledgeSource, TextKnowledgeSource } from '@chatcops/core/knowledge';\n\ninterface Env {\n ANTHROPIC_API_KEY: string;\n WEBHOOK_URL: string;\n SYSTEM_PROMPT: string;\n}\n\nexport default {\n async fetch(request: Request, env: Env): Promise\u003CResponse> {\n // Health check\n if (new URL(request.url).pathname === '/health') {\n return new Response(JSON.stringify({ status: 'ok' }), {\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n const handler = chatcopsCloudflareHandler({\n provider: {\n type: 'claude',\n apiKey: env.ANTHROPIC_API_KEY,\n model: 'claude-haiku-4-5-20251001',\n },\n\n systemPrompt: env.SYSTEM_PROMPT || `You are a helpful customer support assistant.\n Be friendly and concise. Capture leads when users share contact info.`,\n\n tools: [\n new LeadCaptureTool({\n onCapture: async (lead) => {\n // Forward to webhook\n if (env.WEBHOOK_URL) {\n await fetch(env.WEBHOOK_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ type: 'lead', ...lead }),\n });\n }\n },\n }),\n ],\n\n knowledge: [\n new FAQKnowledgeSource([\n { question: 'Pricing?', answer: 'Free tier available. Pro starts at $29/mo.' },\n { question: 'Support hours?', answer: '24/7 via chat, email support 9am-5pm EST.' },\n { question: 'Refund policy?', answer: '30-day money-back guarantee on all plans.' },\n ]),\n new TextKnowledgeSource(\n `We are a SaaS company specializing in developer tools.\n Founded in 2023. Based in San Francisco.\n Used by 1000+ developers worldwide.`\n ),\n ],\n\n cors: '*',\n rateLimit: { maxRequests: 20, windowMs: 60_000 },\n analytics: true,\n });\n\n return handler(request);\n },\n};\n```\n\n## `wrangler.toml`\n\n```toml\nname = \"chatcops-worker\"\nmain = \"src/index.ts\"\ncompatibility_date = \"2024-01-01\"\n\n[vars]\nSYSTEM_PROMPT = \"You are a helpful AI assistant.\"\n```\n\n## Secrets\n\n```bash\nnpx wrangler secret put ANTHROPIC_API_KEY\nnpx wrangler secret put WEBHOOK_URL\n```\n\n## Deploy\n\n```bash\nnpx wrangler deploy\n```\n\n## Widget HTML\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://chatcops-worker.your-subdomain.workers.dev\"\n data-accent=\"#6366f1\"\n data-brand-name=\"AI Support\"\n data-welcome-message=\"Hi! How can I help?\"\n>\u003C/script>\n```\n\n## With Cloudflare KV (Conversation Storage)\n\n```typescript\ninterface Env {\n ANTHROPIC_API_KEY: string;\n CONVERSATIONS: KVNamespace; // Bind in wrangler.toml\n}\n\n// Store conversation history in KV\nconst conversation = await env.CONVERSATIONS.get(conversationId, 'json');\nawait env.CONVERSATIONS.put(conversationId, JSON.stringify(updated), {\n expirationTtl: 86400, // 24 hours\n});\n```","src/content/docs/examples/cloudflare-full.mdx","658c3e689ec90762","getting-started/installation",{"id":128,"data":130,"body":136,"filePath":137,"digest":138,"deferredRender":16},{"title":131,"description":132,"editUrl":16,"head":133,"template":18,"sidebar":134,"pagefind":16,"draft":20},"Installation","Install ChatCops packages via npm, CDN, or ESM imports.",[],{"hidden":20,"attrs":135},{},"ChatCops consists of three packages. Install only what you need.\n\n## Widget (Client-Side)\n\n### CDN (Recommended)\n\nThe simplest way — no build step required:\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://your-api.com/chat\"\n>\u003C/script>\n```\n\n### npm\n\nFor bundler-based projects (Vite, webpack, Next.js):\n\n```bash\nnpm install @chatcops/widget\n```\n\n```typescript\nimport { ChatCops } from '@chatcops/widget';\n\nChatCops.init({\n apiUrl: 'https://your-api.com/chat',\n theme: { accent: '#6366f1' },\n branding: { name: 'My Assistant' },\n});\n```\n\n## Server\n\n```bash\nnpm install @chatcops/server\n```\n\nThe server package includes adapters for Express, Vercel, and Cloudflare Workers:\n\n```typescript\n// Express\nimport { chatcopsMiddleware } from '@chatcops/server';\n\n// Vercel Edge\nimport { chatcopsVercelHandler } from '@chatcops/server';\n\n// Cloudflare Workers\nimport { chatcopsCloudflareHandler } from '@chatcops/server';\n```\n\n## Core (Optional)\n\nOnly needed if building custom integrations:\n\n```bash\nnpm install @chatcops/core\n```\n\nProvides direct access to providers, tools, knowledge base, and i18n:\n\n```typescript\nimport { createProvider } from '@chatcops/core';\nimport { LeadCaptureTool } from '@chatcops/core/tools';\nimport { FAQKnowledgeSource } from '@chatcops/core/knowledge';\n```\n\n## Requirements\n\n- **Widget:** Any modern browser (Chrome, Firefox, Safari, Edge)\n- **Server:** Node.js 22+ (Express), or edge runtime (Vercel/Cloudflare)\n- **TypeScript:** Full type definitions included in all packages","src/content/docs/getting-started/installation.mdx","91afd1f27d007153","server/vercel",{"id":139,"data":141,"body":147,"filePath":148,"digest":149,"deferredRender":16},{"title":142,"description":143,"editUrl":16,"head":144,"template":18,"sidebar":145,"pagefind":16,"draft":20},"Vercel Adapter","Deploy ChatCops as a Vercel Edge Function.",[],{"hidden":20,"attrs":146},{},"The Vercel adapter creates an edge function handler for Vercel's serverless platform.\n\n## Setup\n\nCreate an API route at `api/chat.ts`:\n\n```typescript\nimport { chatcopsVercelHandler } from '@chatcops/server';\n\nexport const config = { runtime: 'edge' };\n\nexport default chatcopsVercelHandler({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n },\n systemPrompt: 'You are a helpful assistant.',\n cors: '*',\n});\n```\n\n## Environment Variables\n\nSet these in your Vercel dashboard or `.env.local`:\n\n```bash\nANTHROPIC_API_KEY=sk-ant-...\n# or\nOPENAI_API_KEY=sk-...\n# or\nGOOGLE_AI_API_KEY=...\n```\n\n## Widget Configuration\n\nPoint the widget to your Vercel deployment:\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://your-app.vercel.app/api/chat\"\n>\u003C/script>\n```\n\n## Full Example with Tools\n\n```typescript\nimport { chatcopsVercelHandler } from '@chatcops/server';\nimport { LeadCaptureTool } from '@chatcops/core/tools';\nimport { FAQKnowledgeSource } from '@chatcops/core/knowledge';\n\nexport const config = { runtime: 'edge' };\n\nexport default chatcopsVercelHandler({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001',\n },\n systemPrompt: `You are the AI assistant for Acme Corp.\n Help users with product questions and capture leads.`,\n tools: [\n new LeadCaptureTool({\n onCapture: async (lead) => {\n await fetch('https://hooks.zapier.com/...', {\n method: 'POST',\n body: JSON.stringify(lead),\n });\n },\n }),\n ],\n knowledge: [\n new FAQKnowledgeSource([\n { question: 'Pricing?', answer: 'Plans start at $29/mo.' },\n ]),\n ],\n cors: '*',\n});\n```\n\n## Notes\n\n- Edge functions have a 25-second timeout on Vercel's Hobby plan\n- Streaming (SSE) works out of the box on Vercel Edge\n- For longer conversations, consider upgrading to Vercel Pro for extended timeouts","src/content/docs/server/vercel.mdx","956154e5954805d0","server/express",{"id":150,"data":152,"body":158,"filePath":159,"digest":160,"deferredRender":16},{"title":153,"description":154,"editUrl":16,"head":155,"template":18,"sidebar":156,"pagefind":16,"draft":20},"Express Adapter","Set up ChatCops with Express.js.",[],{"hidden":20,"attrs":157},{},"The Express adapter wraps the ChatCops handler as Express middleware.\n\n## Basic Setup\n\n```typescript\nimport express from 'express';\nimport { chatcopsMiddleware } from '@chatcops/server';\n\nconst app = express();\napp.use(express.json());\n\napp.post('/chat', chatcopsMiddleware({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001',\n },\n systemPrompt: `You are a helpful customer support assistant for our website.\n Be concise, friendly, and helpful. If the user wants to contact us,\n use the lead capture tool to collect their information.`,\n cors: '*',\n rateLimit: { maxRequests: 30, windowMs: 60_000 },\n analytics: true,\n}));\n\nconst PORT = process.env.PORT ?? 3001;\napp.listen(PORT, () => {\n console.log(`ChatCops server running on http://localhost:${PORT}`);\n});\n```\n\n## With Lead Capture\n\n```typescript\nimport { LeadCaptureTool } from '@chatcops/core/tools';\n\napp.post('/chat', chatcopsMiddleware({\n provider: {\n type: 'claude',\n apiKey: process.env.ANTHROPIC_API_KEY!,\n },\n systemPrompt: 'You are a helpful assistant. Capture leads when users share contact info.',\n tools: [\n new LeadCaptureTool({\n onCapture: async (lead) => {\n // Save to your database, CRM, etc.\n await db.leads.create(lead);\n console.log('Lead captured:', lead.email);\n },\n }),\n ],\n}));\n```\n\n## With Knowledge Base\n\n```typescript\nimport { FAQKnowledgeSource, TextKnowledgeSource } from '@chatcops/core/knowledge';\n\napp.post('/chat', chatcopsMiddleware({\n provider: { type: 'openai', apiKey: process.env.OPENAI_API_KEY! },\n systemPrompt: 'Answer questions using the provided context.',\n knowledge: [\n new FAQKnowledgeSource([\n { question: 'What are your hours?', answer: '9am-5pm EST, Monday-Friday.' },\n { question: 'Do you offer refunds?', answer: 'Yes, within 30 days of purchase.' },\n ]),\n new TextKnowledgeSource(\n 'Our company was founded in 2020. We specialize in AI solutions...',\n { chunkSize: 500 }\n ),\n ],\n}));\n```\n\n## Express Compatibility\n\nThe adapter works with both Express 4.x and 5.x. Express is listed as an optional peer dependency — install it separately:\n\n```bash\nnpm install express @chatcops/server\n```","src/content/docs/server/express.mdx","f6412fe7f9b1832c","server/cloudflare",{"id":161,"data":163,"body":169,"filePath":170,"digest":171,"deferredRender":16},{"title":164,"description":165,"editUrl":16,"head":166,"template":18,"sidebar":167,"pagefind":16,"draft":20},"Cloudflare Workers Adapter","Deploy ChatCops as a Cloudflare Worker.",[],{"hidden":20,"attrs":168},{},"The Cloudflare adapter creates a handler compatible with the Workers runtime.\n\n## Setup\n\nCreate a Worker at `src/index.ts`:\n\n```typescript\nimport { chatcopsCloudflareHandler } from '@chatcops/server';\n\nexport default {\n async fetch(\n request: Request,\n env: Record\u003Cstring, string>\n ): Promise\u003CResponse> {\n const handler = chatcopsCloudflareHandler({\n provider: {\n type: 'claude',\n apiKey: env.ANTHROPIC_API_KEY,\n },\n systemPrompt: 'You are a helpful assistant.',\n cors: '*',\n });\n\n return handler(request);\n },\n};\n```\n\n## Environment Variables\n\nSet secrets using Wrangler:\n\n```bash\nnpx wrangler secret put ANTHROPIC_API_KEY\n```\n\nOr in `wrangler.toml` for non-secret values:\n\n```toml\n[vars]\nSYSTEM_PROMPT = \"You are a helpful assistant.\"\n```\n\n## Widget Configuration\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://chatcops.your-domain.workers.dev\"\n>\u003C/script>\n```\n\n## Full Example\n\n```typescript\nimport { chatcopsCloudflareHandler } from '@chatcops/server';\nimport { LeadCaptureTool } from '@chatcops/core/tools';\n\nexport default {\n async fetch(request: Request, env: Record\u003Cstring, string>): Promise\u003CResponse> {\n const handler = chatcopsCloudflareHandler({\n provider: {\n type: 'gemini',\n apiKey: env.GOOGLE_AI_API_KEY,\n model: 'gemini-2.0-flash',\n },\n systemPrompt: env.SYSTEM_PROMPT || 'You are a helpful assistant.',\n tools: [\n new LeadCaptureTool({\n onCapture: async (lead) => {\n // Use Cloudflare KV, D1, or external webhook\n await fetch(env.WEBHOOK_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(lead),\n });\n },\n }),\n ],\n cors: '*',\n rateLimit: { maxRequests: 20, windowMs: 60_000 },\n });\n\n return handler(request);\n },\n};\n```\n\n## Notes\n\n- Cloudflare Workers have a 30-second CPU time limit (Bundled plan) or 15 minutes (Unbound)\n- SSE streaming works natively on Workers\n- Use Cloudflare KV or D1 for persistent storage (conversation history, analytics)\n- The `env` object provides access to secrets and bindings","src/content/docs/server/cloudflare.mdx","7436cc3bf9e91851","server/setup",{"id":172,"data":174,"body":180,"filePath":181,"digest":182,"deferredRender":16},{"title":175,"description":176,"editUrl":16,"head":177,"template":18,"sidebar":178,"pagefind":16,"draft":20},"Server Setup","Configure the ChatCops server handler with providers, tools, and rate limiting.",[],{"hidden":20,"attrs":179},{},"The `@chatcops/server` package provides a universal chat handler that works with any HTTP framework via adapters.\n\n## Installation\n\n```bash\nnpm install @chatcops/server\n```\n\n## Configuration\n\n```typescript\nimport { chatcopsMiddleware } from '@chatcops/server';\n\nconst handler = chatcopsMiddleware({\n // Required: AI provider\n provider: {\n type: 'claude', // 'claude' | 'openai' | 'gemini'\n apiKey: process.env.ANTHROPIC_API_KEY!,\n model: 'claude-haiku-4-5-20251001', // Optional, each provider has defaults\n },\n\n // Required: System prompt\n systemPrompt: `You are a helpful customer support assistant.\n Be friendly, concise, and helpful.\n If the user provides contact info, use the lead capture tool.`,\n\n // Optional: Tools\n tools: [\n new LeadCaptureTool({ onCapture: (lead) => saveLead(lead) }),\n ],\n\n // Optional: Knowledge base\n knowledge: [\n new FAQKnowledgeSource([\n { question: 'What are your hours?', answer: 'We are open 9am-5pm EST.' },\n ]),\n ],\n\n // Optional: Rate limiting\n rateLimit: {\n maxRequests: 30, // Max requests per window\n windowMs: 60_000, // Window duration in ms\n },\n\n // Optional: Webhooks\n webhooks: [\n {\n url: 'https://hooks.example.com/chatcops',\n events: ['message:received', 'lead:captured'],\n secret: process.env.WEBHOOK_SECRET,\n },\n ],\n\n // Optional: Analytics\n analytics: true,\n\n // Optional: CORS origin\n cors: '*',\n\n // Optional: i18n\n i18n: {\n defaultLocale: 'en',\n locales: { /* custom strings */ },\n },\n});\n```\n\n## ChatCopsServerConfig\n\n```typescript\ninterface ChatCopsServerConfig {\n provider: {\n type: 'claude' | 'openai' | 'gemini';\n apiKey: string;\n model?: string;\n };\n systemPrompt: string;\n tools?: ChatTool[];\n knowledge?: KnowledgeSource[];\n rateLimit?: {\n maxRequests: number;\n windowMs: number;\n };\n webhooks?: WebhookConfig[];\n analytics?: boolean;\n cors?: string;\n i18n?: {\n defaultLocale: string;\n locales: Record\u003Cstring, LocaleStrings>;\n };\n}\n```\n\n## Request Schema\n\nThe server validates incoming requests with Zod:\n\n```typescript\n{\n conversationId: string, // 1-128 chars\n message: string, // 1-10000 chars\n pageContext?: { // Optional page context\n url: string, // Valid URL\n title: string, // Max 500 chars\n description?: string, // Max 1000 chars\n contentSnippet?: string, // Max 2000 chars\n },\n locale?: string, // Max 10 chars\n}\n```\n\n## Response Format\n\nThe server responds with SSE (Server-Sent Events) for streaming:\n\n```\nContent-Type: text/event-stream\n\ndata: {\"type\":\"token\",\"content\":\"Hello\"}\ndata: {\"type\":\"token\",\"content\":\" there\"}\ndata: {\"type\":\"token\",\"content\":\"!\"}\ndata: {\"type\":\"done\"}\n```","src/content/docs/server/setup.mdx","531fe6aa180add1d","widget/api",{"id":183,"data":185,"body":191,"filePath":192,"digest":193,"deferredRender":16},{"title":186,"description":187,"editUrl":16,"head":188,"template":18,"sidebar":189,"pagefind":16,"draft":20},"API Reference","The ChatCops global singleton API for programmatic control.",[],{"hidden":20,"attrs":190},{},"The `ChatCops` singleton is exposed on `window.ChatCops` when using the IIFE bundle, or importable from the ESM bundle.\n\n## Methods\n\n### `ChatCops.init(config)`\n\nInitialize the widget with a configuration object. Must be called before any other method if not using script tag auto-init.\n\n```typescript\nChatCops.init({\n apiUrl: 'https://your-api.com/chat',\n theme: { accent: '#6366f1' },\n branding: { name: 'My Bot' },\n welcomeMessage: 'Hello! How can I help?',\n});\n```\n\n### `ChatCops.open()`\n\nProgrammatically open the chat panel.\n\n```typescript\ndocument.querySelector('#help-btn').addEventListener('click', () => {\n ChatCops.open();\n});\n```\n\n### `ChatCops.close()`\n\nClose the chat panel.\n\n```typescript\nChatCops.close();\n```\n\n### `ChatCops.destroy()`\n\nCompletely remove the widget from the DOM and clean up all event listeners.\n\n```typescript\nChatCops.destroy();\n```\n\n### `ChatCops.on(event, callback)`\n\nSubscribe to widget events. Returns an unsubscribe function.\n\n```typescript\nconst unsub = ChatCops.on('message', (data) => {\n console.log('New message:', data);\n});\n\n// Later: unsubscribe\nunsub();\n```\n\n### `ChatCops.off(event, callback)`\n\nRemove a specific event listener.\n\n```typescript\nfunction onOpen() {\n console.log('Widget opened');\n}\n\nChatCops.on('open', onOpen);\nChatCops.off('open', onOpen);\n```\n\n## Auto-Initialization\n\nWhen using the CDN script tag, the widget auto-initializes by reading `data-*` attributes:\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://your-api.com/chat\"\n data-accent=\"#6366f1\"\n>\u003C/script>\n```\n\nThe script tag approach is equivalent to calling `ChatCops.init()` with the corresponding config. You can still use the programmatic API after auto-init (e.g., `ChatCops.open()`).\n\n## ESM Usage\n\n```typescript\nimport { ChatCops } from '@chatcops/widget';\n\nChatCops.init({ apiUrl: '/api/chat' });\n\n// Use methods as needed\nChatCops.on('message', (msg) => console.log(msg));\n```","src/content/docs/widget/api.mdx","72eace4be9df35d8","widget/configuration",{"id":194,"data":196,"body":202,"filePath":203,"digest":204,"deferredRender":16},{"title":197,"description":198,"editUrl":16,"head":199,"template":18,"sidebar":200,"pagefind":16,"draft":20},"Widget Configuration","All configuration options for the ChatCops widget.",[],{"hidden":20,"attrs":201},{},"The widget can be configured via `data-*` attributes on the script tag or programmatically via `ChatCops.init()`.\n\n## Script Tag Attributes\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"https://your-api.com/chat\"\n data-accent=\"#6366f1\"\n data-text-color=\"#FAFAF9\"\n data-bg-color=\"#0A0A0A\"\n data-font-family=\"Inter, sans-serif\"\n data-border-radius=\"12\"\n data-position=\"bottom-right\"\n data-brand-name=\"Support Bot\"\n data-brand-avatar=\"https://example.com/avatar.png\"\n data-brand-subtitle=\"Usually replies instantly\"\n data-welcome-message=\"Hi! How can I help you today?\"\n data-welcome-bubble=\"Need help? Chat with us!\"\n data-welcome-bubble-delay=\"3000\"\n data-placeholder=\"Type a message...\"\n data-locale=\"en\"\n>\u003C/script>\n```\n\n## Programmatic Configuration\n\n```typescript\nimport { ChatCops } from '@chatcops/widget';\n\nChatCops.init({\n apiUrl: 'https://your-api.com/chat',\n\n // Theme\n theme: {\n accent: '#6366f1',\n textColor: '#FAFAF9',\n bgColor: '#0A0A0A',\n fontFamily: 'Inter, sans-serif',\n borderRadius: 12,\n position: 'bottom-right', // 'bottom-right' | 'bottom-left'\n },\n\n // Branding\n branding: {\n name: 'Support Bot',\n avatar: 'https://example.com/avatar.png',\n subtitle: 'Usually replies instantly',\n },\n\n // Behavior\n welcomeMessage: 'Hi! How can I help you today?',\n welcomeBubble: 'Need help? Chat with us!',\n welcomeBubbleDelay: 3000, // ms before showing bubble\n placeholder: 'Type a message...',\n locale: 'en',\n});\n```\n\n## WidgetConfig Interface\n\n```typescript\ninterface WidgetConfig {\n apiUrl: string;\n\n theme?: {\n accent?: string; // Hex color, default: '#6366f1'\n textColor?: string; // Hex color, default: '#FAFAF9'\n bgColor?: string; // Hex color, default: '#0A0A0A'\n fontFamily?: string; // CSS font-family\n borderRadius?: number; // px, default: 12\n position?: 'bottom-right' | 'bottom-left';\n };\n\n branding?: {\n name?: string; // Header title\n avatar?: string; // URL or data URI\n subtitle?: string; // Below title in header\n };\n\n welcomeMessage?: string; // First assistant message\n welcomeBubble?: string; // Text shown on hover bubble\n welcomeBubbleDelay?: number;// ms before bubble appears\n placeholder?: string; // Input placeholder text\n locale?: string; // 'en' | 'es' | 'hi' | 'fr' | 'de' | 'ja' | 'zh' | 'ar'\n}\n```\n\n## CSS Custom Properties\n\nThe widget uses Shadow DOM and exposes these CSS custom properties on its host element:\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `--cc-accent` | Primary accent color | `#6366f1` |\n| `--cc-accent-hover` | Hover state of accent | Darkened accent |\n| `--cc-text` | Primary text color | `#FAFAF9` |\n| `--cc-bg` | Background color | `#0A0A0A` |\n| `--cc-bg-surface` | Surface background | `#111111` |\n| `--cc-bg-input` | Input area background | `#171717` |\n| `--cc-border` | Border color | `#262626` |\n| `--cc-text-secondary` | Secondary text | `#A8A29E` |\n| `--cc-font` | Font family | `system-ui` |\n| `--cc-radius` | Border radius | `12px` |\n| `--cc-fab-size` | FAB button size | `56px` |\n| `--cc-panel-width` | Chat panel width | `400px` |\n| `--cc-panel-height` | Chat panel height | `560px` |","src/content/docs/widget/configuration.mdx","9cb544ca5055dc98","widget/events",{"id":205,"data":207,"body":213,"filePath":214,"digest":215,"deferredRender":16},{"title":208,"description":209,"editUrl":16,"head":210,"template":18,"sidebar":211,"pagefind":16,"draft":20},"Events","Subscribe to widget lifecycle and messaging events.",[],{"hidden":20,"attrs":212},{},"The ChatCops widget emits events you can listen to for analytics, custom behavior, or integration with your app.\n\n## Subscribing to Events\n\n```typescript\n// Using .on()\nChatCops.on('open', () => {\n console.log('Chat opened');\n});\n\n// Returns unsubscribe function\nconst unsub = ChatCops.on('message', (data) => {\n console.log('Message:', data);\n});\n\n// Unsubscribe later\nunsub();\n```\n\n## Event Types\n\n### `open`\n\nFired when the chat panel opens.\n\n```typescript\nChatCops.on('open', () => {\n analytics.track('chat_opened');\n});\n```\n\n### `close`\n\nFired when the chat panel closes.\n\n```typescript\nChatCops.on('close', () => {\n analytics.track('chat_closed');\n});\n```\n\n### `message`\n\nFired when a message is sent or received.\n\n```typescript\nChatCops.on('message', (data) => {\n // data.role: 'user' | 'assistant'\n // data.content: string\n // data.timestamp: number\n console.log(`${data.role}: ${data.content}`);\n});\n```\n\n### `error`\n\nFired when an error occurs (network failure, rate limit, etc.).\n\n```typescript\nChatCops.on('error', (error) => {\n // error.type: 'network' | 'rate_limit' | 'generic'\n // error.message: string\n console.error('Chat error:', error.message);\n});\n```\n\n## Use Cases\n\n### Analytics Integration\n\n```typescript\nChatCops.on('open', () => {\n gtag('event', 'chat_widget_open');\n});\n\nChatCops.on('message', (data) => {\n if (data.role === 'user') {\n gtag('event', 'chat_message_sent');\n }\n});\n```\n\n### Custom Triggers\n\nOpen the chat when a user clicks a help button:\n\n```typescript\ndocument.querySelector('#help-btn').addEventListener('click', () => {\n ChatCops.open();\n});\n```\n\n### Conditional Display\n\n```typescript\n// Only show chat on certain pages\nif (window.location.pathname.startsWith('/support')) {\n ChatCops.init({ apiUrl: '/api/chat' });\n}\n```","src/content/docs/widget/events.mdx","07ba90f4168a3d3c","widget/theming",{"id":216,"data":218,"body":224,"filePath":225,"digest":226,"deferredRender":16},{"title":219,"description":220,"editUrl":16,"head":221,"template":18,"sidebar":222,"pagefind":16,"draft":20},"Theming","Customize the ChatCops widget appearance to match your brand.",[],{"hidden":20,"attrs":223},{},"ChatCops uses a theme engine that applies CSS custom properties to the Shadow DOM host element.\n\n## Theme Configuration\n\n```typescript\nChatCops.init({\n apiUrl: '/api/chat',\n theme: {\n accent: '#6366f1', // Primary color for buttons, user messages\n textColor: '#FAFAF9', // Main text color\n bgColor: '#0A0A0A', // Widget background\n fontFamily: 'Inter, sans-serif',\n borderRadius: 12, // px\n position: 'bottom-right', // or 'bottom-left'\n },\n});\n```\n\n## Color Manipulation\n\nThe theme engine automatically generates hover and surface colors from your accent:\n\n- **Accent hover:** Darkened by 15% from your accent\n- **Accent light:** Lightened by 40% for subtle backgrounds\n- **Surface colors:** Derived from `bgColor`\n\n## Built-in Dark Theme\n\nThe default theme is optimized for dark mode:\n\n| Element | Color |\n|---------|-------|\n| Background | `#0A0A0A` |\n| Surface | `#111111` |\n| Input area | `#171717` |\n| Border | `#262626` |\n| Text | `#FAFAF9` |\n| Secondary text | `#A8A29E` |\n| Accent | `#6366f1` (indigo) |\n\n## Light Theme Example\n\n```typescript\nChatCops.init({\n apiUrl: '/api/chat',\n theme: {\n accent: '#4f46e5',\n textColor: '#1a1a1a',\n bgColor: '#ffffff',\n borderRadius: 16,\n },\n});\n```\n\n## CSS Override (Advanced)\n\nYou can override widget styles by targeting the custom element:\n\n```css\nchatcops-widget {\n --cc-accent: #e11d48;\n --cc-bg: #ffffff;\n --cc-text: #111111;\n --cc-panel-width: 450px;\n --cc-panel-height: 600px;\n --cc-fab-size: 64px;\n}\n```\n\n## ThemeConfig Interface\n\n```typescript\ninterface ThemeConfig {\n accent?: string; // Hex color\n textColor?: string; // Hex color\n bgColor?: string; // Hex color\n fontFamily?: string; // CSS font-family string\n borderRadius?: number; // Pixels\n position?: 'bottom-right' | 'bottom-left';\n}\n```\n\n## Position\n\nThe widget supports two positions:\n\n- `bottom-right` (default) — FAB and panel anchored to bottom-right\n- `bottom-left` — FAB and panel anchored to bottom-left\n\nOn mobile screens, the chat panel always goes full-screen regardless of position.","src/content/docs/widget/theming.mdx","44fb6dcddb661a3a","widget/i18n",{"id":227,"data":229,"body":235,"filePath":236,"digest":237,"deferredRender":16},{"title":230,"description":231,"editUrl":16,"head":232,"template":18,"sidebar":233,"pagefind":16,"draft":20},"Internationalization","Localize the ChatCops widget for different languages.",[],{"hidden":20,"attrs":234},{},"ChatCops includes 8 built-in locales with full UI string translations.\n\n## Setting a Locale\n\n### Via script tag\n\n```html\n\u003Cscript\n src=\"https://cdn.jsdelivr.net/npm/@chatcops/widget/dist/chatcops.min.js\"\n data-api-url=\"/api/chat\"\n data-locale=\"es\"\n>\u003C/script>\n```\n\n### Programmatically\n\n```typescript\nChatCops.init({\n apiUrl: '/api/chat',\n locale: 'fr',\n});\n```\n\n## Available Locales\n\n| Code | Language |\n|------|----------|\n| `en` | English (default) |\n| `es` | Spanish |\n| `hi` | Hindi |\n| `fr` | French |\n| `de` | German |\n| `ja` | Japanese |\n| `zh` | Chinese |\n| `ar` | Arabic |\n\n## Locale Strings\n\nEach locale provides translations for:\n\n```typescript\ninterface LocaleStrings {\n welcomeMessage: string;\n inputPlaceholder: string;\n sendButton: string;\n closeButton: string;\n errorGeneric: string;\n errorNetwork: string;\n errorRateLimit: string;\n typingIndicator: string;\n poweredBy: string;\n newConversation: string;\n welcomeBubbleDefault: string;\n}\n```\n\n## Server-Side i18n\n\nThe server also supports i18n for error messages and system prompts:\n\n```typescript\nchatcopsMiddleware({\n provider: { type: 'claude', apiKey: '...' },\n systemPrompt: '...',\n i18n: {\n defaultLocale: 'en',\n locales: {\n es: {\n welcomeMessage: 'Hola! Como puedo ayudarte?',\n inputPlaceholder: 'Escribe un mensaje...',\n sendButton: 'Enviar',\n closeButton: 'Cerrar',\n errorGeneric: 'Algo salio mal. Intentalo de nuevo.',\n errorNetwork: 'Error de conexion.',\n errorRateLimit: 'Demasiados mensajes. Espera un momento.',\n typingIndicator: 'Escribiendo...',\n poweredBy: 'Desarrollado por',\n newConversation: 'Nueva conversacion',\n welcomeBubbleDefault: 'Necesitas ayuda?',\n },\n },\n },\n});\n```\n\nThe widget sends its current `locale` with each request, and the server uses it to select the appropriate strings.","src/content/docs/widget/i18n.mdx","105d3fe1643873e9"] \ No newline at end of file diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000..e985853 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1 @@ +.vercel diff --git a/website/astro.config.mjs b/website/astro.config.mjs index 26a56be..b73eb01 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -2,9 +2,11 @@ import { defineConfig } from 'astro/config'; import starlight from '@astrojs/starlight'; import react from '@astrojs/react'; import tailwindcss from '@tailwindcss/vite'; +import vercel from '@astrojs/vercel'; export default defineConfig({ output: 'static', + adapter: vercel(), site: 'https://chatcops.codercops.com', vite: { plugins: [tailwindcss()], @@ -20,6 +22,20 @@ export default defineConfig({ social: [ { icon: 'github', label: 'GitHub', href: 'https://github.com/codercops/chatcops' }, ], + head: [ + { + tag: 'script', + attrs: { + src: 'https://cdn.jsdelivr.net/npm/@chatcops/widget@0.2.0/dist/chatcops.min.js', + 'data-api-url': '/api/chat', + 'data-accent': '#6366f1', + 'data-brand-name': 'ChatCops AI', + 'data-welcome-message': "Hi! I'm the ChatCops assistant. Ask me anything about setting up ChatCops on your website.", + 'data-position': 'bottom-right', + defer: true, + }, + }, + ], customCss: [ '@fontsource/inter/400.css', '@fontsource/inter/500.css', diff --git a/website/package.json b/website/package.json index 837e483..2d4413b 100644 --- a/website/package.json +++ b/website/package.json @@ -12,6 +12,10 @@ "dependencies": { "@astrojs/react": "^4.4.2", "@astrojs/starlight": "^0.34.0", + "@astrojs/vercel": "^9.0.4", + "@chatcops/core": "^0.2.0", + "@chatcops/server": "^0.2.0", + "@chatcops/widget": "workspace:^", "@tailwindcss/vite": "^4.2.1", "astro": "^5.7.0", "motion": "^12.35.0", diff --git a/website/src/components/landing/LiveDemo.astro b/website/src/components/landing/LiveDemo.astro index 08f7439..40833de 100644 --- a/website/src/components/landing/LiveDemo.astro +++ b/website/src/components/landing/LiveDemo.astro @@ -19,6 +19,6 @@ import LiveDemoReact from '../react/LiveDemo.tsx';

- + diff --git a/website/src/components/react/LiveDemo.tsx b/website/src/components/react/LiveDemo.tsx index 05e72a1..5fb62bc 100644 --- a/website/src/components/react/LiveDemo.tsx +++ b/website/src/components/react/LiveDemo.tsx @@ -1,169 +1,52 @@ -import { useState, useEffect, useRef } from 'react'; -import { motion, AnimatePresence } from 'motion/react'; - -interface Message { - id: string; - role: 'user' | 'assistant'; - content: string; -} - -const conversation: Message[] = [ - { id: '1', role: 'assistant', content: "Hey! I'm your AI assistant powered by ChatCops. How can I help?" }, - { id: '2', role: 'user', content: 'What pricing plans do you offer?' }, - { - id: '3', - role: 'assistant', - content: - "We have three plans: **Starter** (free), **Pro** ($29/mo), and **Enterprise** (custom). All include unlimited conversations and every integration. Want me to help you choose?", - }, -]; +import { useEffect, useRef } from 'react'; +import { motion } from 'motion/react'; +import { Widget } from '@chatcops/widget'; export default function LiveDemo() { - const [messages, setMessages] = useState([]); - const [typing, setTyping] = useState(false); - const ref = useRef(null); + const containerRef = useRef(null); + const widgetRef = useRef(null); useEffect(() => { - let step = 0; - const delays = [500, 1400, 900]; - - function next() { - if (step >= conversation.length) return; - const msg = conversation[step]; - - if (msg.role === 'assistant' && step > 0) { - setTyping(true); - setTimeout(() => { - setTyping(false); - streamMsg(msg); - step++; - setTimeout(next, delays[step] || 1000); - }, 1200); - } else { - setMessages((p) => [...p, msg]); - step++; - setTimeout(next, delays[step] || 900); - } - } - - function streamMsg(msg: Message) { - const words = msg.content.split(' '); - let i = 0; - setMessages((p) => [...p, { ...msg, content: '' }]); - - const iv = setInterval(() => { - if (i >= words.length) { - clearInterval(iv); - setMessages((p) => p.map((m) => (m.id === msg.id ? { ...m, content: msg.content } : m))); - return; - } - i++; - const partial = words.slice(0, i).join(' '); - setMessages((p) => p.map((m) => (m.id === msg.id ? { ...m, content: partial } : m))); - }, 35); - } - - const t = setTimeout(next, 700); - return () => clearTimeout(t); + if (widgetRef.current || !containerRef.current) return; + + const widget = new Widget({ + apiUrl: '/api/chat', + mode: 'inline', + container: containerRef.current, + welcomeMessage: "Hey! I'm your AI assistant powered by ChatCops. Ask me anything!", + branding: { + name: 'ChatCops', + subtitle: 'Always online', + }, + theme: { + accent: '#6366f1', + }, + persistHistory: false, + }); + widget.init(); + widgetRef.current = widget; + + return () => { + widget.destroy(); + widgetRef.current = null; + }; }, []); - useEffect(() => { - ref.current?.scrollTo({ top: ref.current.scrollHeight, behavior: 'smooth' }); - }, [messages, typing]); - return ( -
- {/* Header */} -
-
-
- C -
-
-
-
-
ChatCops
-
Always online
-
-
- - {/* Messages */} -
- - {messages.map((msg) => ( - -
- {formatText(msg.content)} -
-
- ))} -
- - {typing && ( - -
- {[0, 1, 2].map((i) => ( - - ))} -
-
- )} -
- - {/* Input */} -
-
- Type a message... -
- -
-
+
+

+ This is the actual ChatCops widget running in inline mode. +

); } - -function formatText(text: string) { - const parts = text.split(/(\*\*[^*]+\*\*)/g); - return parts.map((part, i) => { - if (part.startsWith('**') && part.endsWith('**')) { - return ( - - {part.slice(2, -2)} - - ); - } - return part; - }); -} diff --git a/website/src/content/docs/widget/api.mdx b/website/src/content/docs/widget/api.mdx index e1fd146..999d67e 100644 --- a/website/src/content/docs/widget/api.mdx +++ b/website/src/content/docs/widget/api.mdx @@ -12,18 +12,32 @@ The `ChatCops` singleton is exposed on `window.ChatCops` when using the IIFE bun Initialize the widget with a configuration object. Must be called before any other method if not using script tag auto-init. ```typescript +// Popup mode (default) ChatCops.init({ apiUrl: 'https://your-api.com/chat', theme: { accent: '#6366f1' }, branding: { name: 'My Bot' }, welcomeMessage: 'Hello! How can I help?', }); + +// Inline mode +ChatCops.init({ + apiUrl: 'https://your-api.com/chat', + mode: 'inline', + container: '#chat-container', + branding: { name: 'My Bot' }, +}); ``` +Calling `init()` again will destroy the previous instance and create a new one. + ### `ChatCops.open()` Programmatically open the chat panel. +- **Popup mode:** Shows the panel and updates the FAB icon. +- **Inline mode:** Shows the panel (useful if you've previously called `close()`). + ```typescript document.querySelector('#help-btn').addEventListener('click', () => { ChatCops.open(); @@ -34,6 +48,9 @@ document.querySelector('#help-btn').addEventListener('click', () => { Close the chat panel. +- **Popup mode:** Hides the panel and resets the FAB icon. +- **Inline mode:** Hides the panel. Call `open()` to show it again. + ```typescript ChatCops.close(); ``` @@ -42,21 +59,21 @@ ChatCops.close(); Completely remove the widget from the DOM and clean up all event listeners. +- **Popup mode:** Removes FAB, panel, and welcome bubble from the page. +- **Inline mode:** Removes the widget from the container element. + ```typescript ChatCops.destroy(); ``` ### `ChatCops.on(event, callback)` -Subscribe to widget events. Returns an unsubscribe function. +Subscribe to widget events. ```typescript -const unsub = ChatCops.on('message', (data) => { +ChatCops.on('message', (data) => { console.log('New message:', data); }); - -// Later: unsubscribe -unsub(); ``` ### `ChatCops.off(event, callback)` @@ -76,6 +93,8 @@ ChatCops.off('open', onOpen); When using the CDN script tag, the widget auto-initializes by reading `data-*` attributes: +### Popup (default) + ```html ``` +### Inline + +```html +
+ +``` + The script tag approach is equivalent to calling `ChatCops.init()` with the corresponding config. You can still use the programmatic API after auto-init (e.g., `ChatCops.open()`). ## ESM Usage ```typescript -import { ChatCops } from '@chatcops/widget'; +import ChatCops from '@chatcops/widget'; +// Popup ChatCops.init({ apiUrl: '/api/chat' }); +// Inline with element reference +const el = document.getElementById('chat'); +ChatCops.init({ + apiUrl: '/api/chat', + mode: 'inline', + container: el, +}); + // Use methods as needed ChatCops.on('message', (msg) => console.log(msg)); ``` + +## React / Framework Usage + +For inline mode in React or other frameworks, pass the container element directly: + +```tsx +import { useEffect, useRef } from 'react'; +import ChatCops from '@chatcops/widget'; + +function Chat() { + const ref = useRef(null); + + useEffect(() => { + if (!ref.current) return; + ChatCops.init({ + apiUrl: '/api/chat', + mode: 'inline', + container: ref.current, + }); + return () => ChatCops.destroy(); + }, []); + + return
; +} +``` diff --git a/website/src/content/docs/widget/configuration.mdx b/website/src/content/docs/widget/configuration.mdx index da5091f..fbdde75 100644 --- a/website/src/content/docs/widget/configuration.mdx +++ b/website/src/content/docs/widget/configuration.mdx @@ -5,8 +5,17 @@ description: All configuration options for the ChatCops widget. The widget can be configured via `data-*` attributes on the script tag or programmatically via `ChatCops.init()`. +## Display Modes + +ChatCops supports two display modes: + +- **Popup** (default) — Floating action button (FAB) in the corner that opens a chat panel overlay. +- **Inline** — The chat panel renders directly inside a container element on your page. No FAB, no overlay. + ## Script Tag Attributes +### Popup Mode (default) + ```html ``` +### Inline Mode + +```html +
+ +``` + +In inline mode, the chat panel fills the container element. You control the size via the container's CSS. + ## Programmatic Configuration +### Popup Mode + ```typescript -import { ChatCops } from '@chatcops/widget'; +import ChatCops from '@chatcops/widget'; ChatCops.init({ apiUrl: 'https://your-api.com/chat', @@ -42,7 +70,7 @@ ChatCops.init({ textColor: '#FAFAF9', bgColor: '#0A0A0A', fontFamily: 'Inter, sans-serif', - borderRadius: 12, + borderRadius: '12', position: 'bottom-right', // 'bottom-right' | 'bottom-left' }, @@ -55,25 +83,53 @@ ChatCops.init({ // Behavior welcomeMessage: 'Hi! How can I help you today?', - welcomeBubble: 'Need help? Chat with us!', - welcomeBubbleDelay: 3000, // ms before showing bubble + welcomeBubble: { + text: 'Need help? Chat with us!', + delay: 3000, + }, placeholder: 'Type a message...', + autoOpen: 1000, // Open after 1s, or true for immediate locale: 'en', }); ``` +### Inline Mode + +```typescript +import ChatCops from '@chatcops/widget'; + +ChatCops.init({ + apiUrl: 'https://your-api.com/chat', + mode: 'inline', + container: '#chat-container', // CSS selector or HTMLElement + + branding: { + name: 'Support Bot', + subtitle: 'Online', + }, + welcomeMessage: 'Hi! How can I help you today?', + persistHistory: false, +}); +``` + +The `container` option accepts a CSS selector string or a direct `HTMLElement` reference. + ## WidgetConfig Interface ```typescript interface WidgetConfig { apiUrl: string; + // Display mode + mode?: 'popup' | 'inline'; // Default: 'popup' + container?: string | HTMLElement; // Required when mode is 'inline' + theme?: { accent?: string; // Hex color, default: '#6366f1' textColor?: string; // Hex color, default: '#FAFAF9' bgColor?: string; // Hex color, default: '#0A0A0A' fontFamily?: string; // CSS font-family - borderRadius?: number; // px, default: 12 + borderRadius?: string; // px, default: '12' position?: 'bottom-right' | 'bottom-left'; }; @@ -84,13 +140,50 @@ interface WidgetConfig { }; welcomeMessage?: string; // First assistant message - welcomeBubble?: string; // Text shown on hover bubble - welcomeBubbleDelay?: number;// ms before bubble appears + welcomeBubble?: { // Popup mode only + text: string; // Text shown on hover bubble + delay?: number; // ms before bubble appears + showOnce?: boolean; // Only show once per session + }; placeholder?: string; // Input placeholder text + persistHistory?: boolean; // Save chat history, default: true + maxMessages?: number; // Max messages to persist, default: 50 + pageContext?: boolean; // Send page URL/title, default: true + autoOpen?: boolean | number; // Popup mode only. true = immediate, number = delay in ms locale?: string; // 'en' | 'es' | 'hi' | 'fr' | 'de' | 'ja' | 'zh' | 'ar' + strings?: Partial; // Custom i18n overrides + + // Callbacks + onOpen?: () => void; + onClose?: () => void; + onMessage?: (message: MessageData) => void; + onError?: (error: Error) => void; } ``` +## Script Tag Attribute Reference + +| Attribute | Config Key | Description | +|-----------|-----------|-------------| +| `data-api-url` | `apiUrl` | API endpoint URL (required) | +| `data-mode` | `mode` | `'popup'` or `'inline'` | +| `data-container` | `container` | CSS selector for inline container | +| `data-accent` | `theme.accent` | Primary accent color | +| `data-text-color` | `theme.textColor` | Primary text color | +| `data-bg-color` | `theme.bgColor` | Background color | +| `data-font-family` | `theme.fontFamily` | Font family | +| `data-border-radius` | `theme.borderRadius` | Border radius in px | +| `data-position` | `theme.position` | `'bottom-right'` or `'bottom-left'` | +| `data-brand-name` | `branding.name` | Header title | +| `data-brand-avatar` | `branding.avatar` | Avatar image URL | +| `data-brand-subtitle` | `branding.subtitle` | Subtitle text | +| `data-welcome-message` | `welcomeMessage` | First assistant message | +| `data-welcome-bubble` | `welcomeBubble.text` | Welcome bubble text | +| `data-welcome-bubble-delay` | `welcomeBubble.delay` | Bubble delay in ms | +| `data-placeholder` | `placeholder` | Input placeholder | +| `data-auto-open` | `autoOpen` | Auto-open delay in ms or `true` | +| `data-locale` | `locale` | Language code | + ## CSS Custom Properties The widget uses Shadow DOM and exposes these CSS custom properties on its host element: @@ -110,3 +203,16 @@ The widget uses Shadow DOM and exposes these CSS custom properties on its host e | `--cc-fab-size` | FAB button size | `56px` | | `--cc-panel-width` | Chat panel width | `400px` | | `--cc-panel-height` | Chat panel height | `560px` | + +## Inline Mode Behavior + +When using `mode: 'inline'`: + +- The chat panel renders inside the specified container element +- No floating action button (FAB) is created +- No welcome bubble is shown +- The panel is visible immediately (no toggle needed) +- `autoOpen` is ignored (always open) +- The panel fills 100% width and height of the container +- Mobile responsive overrides do not apply — the container controls sizing +- `open()` and `close()` still work programmatically diff --git a/website/src/layouts/Landing.astro b/website/src/layouts/Landing.astro index 506abf9..e6be90e 100644 --- a/website/src/layouts/Landing.astro +++ b/website/src/layouts/Landing.astro @@ -36,6 +36,17 @@ const canonicalURL = new URL(Astro.url.pathname, Astro.site); + + + diff --git a/website/src/pages/api/chat.ts b/website/src/pages/api/chat.ts new file mode 100644 index 0000000..dc8e135 --- /dev/null +++ b/website/src/pages/api/chat.ts @@ -0,0 +1,124 @@ +import type { APIRoute } from 'astro'; +import { createChatHandler } from '@chatcops/server'; +import { FAQKnowledgeSource } from '@chatcops/core'; + +export const prerender = false; + +const faq = new FAQKnowledgeSource([ + { + question: 'What is ChatCops?', + answer: + 'ChatCops is an open-source, universal AI chatbot widget you can embed on any website with a single script tag. It supports Claude, OpenAI, and Gemini as AI providers.', + }, + { + question: 'How do I install ChatCops?', + answer: + 'The easiest way is via CDN: add a