From 43c5be6427935ee19c89a2cc7746b6c0ef5f8055 Mon Sep 17 00:00:00 2001 From: JakeSCahill Date: Mon, 6 Jul 2026 17:08:49 +0100 Subject: [PATCH 01/10] Migrate Ask AI to Kapa Agent SDK: tools, history, login gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the Kapa Chat SDK (@kapaai/react-sdk) with the Agent SDK (@kapaai/agent-react) and builds the signed-in "AI agent" experience on top of it. Requires the docs-site backend (kapa-session endpoint + docs login) — inert until that ships. - Agent SDK migration: AskAI.jsx (AgentProvider + getSessionToken), and ChatInterface.jsx rewritten onto useAgentChat (flat messages, isStreaming, sources from tool-call blocks, tool-call approval cards). Drops the old localStorage persistence (chatPersistence/persistentApiService) in favor of server-side history. - Client tools (agentTools.js): navigate_to_page, switch_product, run_bloblang (verifies mappings in the playground WASM before the agent presents them), open_bloblang_playground, submit_docs_feedback, ask_community. All approval-gated except the sandboxed run_bloblang. - Custom instructions (system prompt, not shown to users): deployment clarifying questions (Cloud vs Self-Managed first, version only when it matters), Bloblang verify-before-present, feedback consent/PII rules. - Two-tier gating: agent panel is signed-in only; the panel's sign-in screen is the discovery surface. Header account control (26-docs-account.js) — Sign in opens a feature modal; signed-in shows an avatar menu. Component- scoped console link (Cloud/Data Platform -> Cloud Console; ADP -> ADP Console). conversation history UI (AgentThreadHistory). - Feedback is Heap-only (Agent SDK dropped addFeedback); signed-in feedback attaches email + thread id server-side. - Sources list de-dupes and disambiguates repeated titles by version/section. - Theming/UX: unified indigo palette + WCAG-AA contrast across drawer, header modal and login page in both themes; single-scroll panel with sticky input; full-screen toggle; textarea input (Enter sends, Shift+Enter newline). Co-Authored-By: Claude Opus 4.8 --- gulp.d/tasks/bundle-react.js | 3 + package-lock.json | 2928 ++++++++++++++++++--- package.json | 6 +- src/css/chat-panel-bump.css | 316 ++- src/css/chat-panel.css | 318 ++- src/css/header-bump.css | 186 ++ src/css/header.css | 186 ++ src/js/19-chat-panel.js | 17 +- src/js/26-docs-account.js | 131 + src/js/react/AskAI.jsx | 233 +- src/js/react/agentTools.js | 359 +++ src/js/react/chatPersistence.js | 78 - src/js/react/components/ChatInterface.jsx | 422 ++- src/js/react/heap.js | 10 + src/js/react/persistentApiService.js | 55 - src/partials/chat-panel-bump.hbs | 43 +- src/partials/chat-panel.hbs | 21 +- src/partials/head-scripts.hbs | 4 +- src/partials/header-content.hbs | 66 +- 19 files changed, 4514 insertions(+), 868 deletions(-) create mode 100644 src/js/26-docs-account.js create mode 100644 src/js/react/agentTools.js delete mode 100644 src/js/react/chatPersistence.js create mode 100644 src/js/react/heap.js delete mode 100644 src/js/react/persistentApiService.js diff --git a/gulp.d/tasks/bundle-react.js b/gulp.d/tasks/bundle-react.js index c0644746..61361933 100644 --- a/gulp.d/tasks/bundle-react.js +++ b/gulp.d/tasks/bundle-react.js @@ -56,6 +56,9 @@ async function bundleAllReactTask ({ srcDir, destDir }) { define: { 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'), }, + // @kapaai/agent-core lazily imports zod-to-json-schema only when a tool + // defines Zod-schema parameters; we register no tools, so leave it unresolved + external: ['zod-to-json-schema'], }) log.info(`Built ${outName}`) } catch (error) { diff --git a/package-lock.json b/package-lock.json index eb4a2f0d..b41729c0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,6 +6,9 @@ "": { "name": "@redpanda-data/docs-ui", "license": "MPL-2.0", + "dependencies": { + "@kapaai/agent-react": "^1.0.0" + }, "devDependencies": { "@algolia/autocomplete-plugin-tags": "^1.12.2", "@asciidoctor/core": "~2.2", @@ -16,7 +19,6 @@ "@docsearch/js": "^3.3.3", "@fontsource/roboto": "~4.5", "@fontsource/roboto-mono": "~4.5", - "@kapaai/react-sdk": "^0.9.0", "autoprefixer": "~9.7", "babelify": "^10.0.0", "browser-pack-flat": "~3.4", @@ -1953,10 +1955,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", - "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", - "dev": true, + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -2503,36 +2504,6 @@ "node": ">=18" } }, - "node_modules/@fingerprintjs/fingerprintjs-pro": { - "version": "3.12.9", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.12.9.tgz", - "integrity": "sha512-MiM8ASp9nQgY/abPK+1+LaZHvn6aaTX9Zze1ghCDO/Y86k1dbRnDeBr5Zg5fmEhwMda9J7+6zl54lds6GENZUw==", - "dev": true, - "license": "SEE LICENSE IN LICENSE" - }, - "node_modules/@fingerprintjs/fingerprintjs-pro-react": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.7.1.tgz", - "integrity": "sha512-/vQtjd+P8C9OFU8Wvd4AScoNRP6RKDIvYQwwaY/b31PcRBNDqVV9xm7DDBg9uTdDv4KZM3ubEY4JyyVWkXs4EA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.3", - "fast-deep-equal": "3.1.3" - } - }, - "node_modules/@fingerprintjs/fingerprintjs-pro-spa": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.3.tgz", - "integrity": "sha512-jM5k30S9RT/WW6gnmNWACc7UHeK1md9NbZg8kUsdxvPtDeW8xKnA6tb58Rqfkg6kvqHTq5aHFzw9hgsTH3DbNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@fingerprintjs/fingerprintjs-pro": "^3.12.0", - "tslib": "^2.7.0" - } - }, "node_modules/@fontsource/roboto": { "version": "4.5.8", "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz", @@ -2625,28 +2596,6 @@ "node": ">=0.10.0" } }, - "node_modules/@hcaptcha/loader": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.3.0.tgz", - "integrity": "sha512-i4lnNxKBe+COf3R1nFZEWaZoHIoJjvDgWqvcNrdZq8ehoSNMN6KVZ56dcQ02qKie2h3+BkbkwlJA9DOIuLlK/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@hcaptcha/react-hcaptcha": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/@hcaptcha/react-hcaptcha/-/react-hcaptcha-1.17.4.tgz", - "integrity": "sha512-rIvgesG1N7SS9sAYYHFoWm+nXqRrxq7RcA9z2pKkDWV+S1GdfmrTNYA1aPyVWVe3eowphTCwyDJvl97Swwy0mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.17.9", - "@hcaptcha/loader": "^2.3.0" - }, - "peerDependencies": { - "react": ">= 16.3.0", - "react-dom": ">= 16.3.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -2697,22 +2646,45 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@kapaai/react-sdk": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/@kapaai/react-sdk/-/react-sdk-0.9.9.tgz", - "integrity": "sha512-NMkUCmuXTTONgr8Qn9m0Z7JA0nAr/OpUyX6K9KPjYLwq+r+Wy9X+PQle9N5qRBD1cpeTVum4YscreiQ3nUrolg==", - "dev": true, - "license": "MIT", + "node_modules/@kapaai/agent-core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@kapaai/agent-core/-/agent-core-1.0.0.tgz", + "integrity": "sha512-tqGc29U+j+IqdqUBrUkfO4hebeg3tryf3UJltJswtjEQYzN7vgMnyTLGCy39MB6b/3vnEpyjCTdffMnKC4CZNg==", + "license": "UNLICENSED", + "peerDependencies": { + "zod": "^3.22.0", + "zod-to-json-schema": "^3.23.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + }, + "zod-to-json-schema": { + "optional": true + } + } + }, + "node_modules/@kapaai/agent-react": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@kapaai/agent-react/-/agent-react-1.0.0.tgz", + "integrity": "sha512-DiSHjhzJAvw+GySD9hrt05ilpww/5IldXHT4nU3d3HQVGvpTqTvACr9EhtcRBHZ0/jpLPJ5wntdmmp92A0uEoQ==", + "license": "UNLICENSED", "dependencies": { - "@fingerprintjs/fingerprintjs-pro-react": "^2.7.0", - "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.0", - "@hcaptcha/react-hcaptcha": "^1.12.0", - "js-cookie": "^3.0.5", - "tldts": "^7.0.7" + "@kapaai/agent-core": "1.0.0", + "@tabler/icons-react": "^3.0.0", + "react-markdown": "^8.0.0", + "react-syntax-highlighter": "^15.0.0", + "remark-gfm": "^3.0.0" }, "peerDependencies": { - "react": ">=17.0.0", - "react-dom": ">=17.0.0" + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0", + "zod": "^3.22.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } } }, "node_modules/@nodelib/fs.scandir": { @@ -2983,6 +2955,32 @@ "postcss-syntax": ">=0.36.2" } }, + "node_modules/@tabler/icons": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.44.0.tgz", + "integrity": "sha512-Wn0AOZG9sg0L+bjfMqq4eNhC6pQjIrk94LvvWYNYkY8KH8wC3YILRzQlrnVJc4FUeMxH/AK97QsYCX35H3LndA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.44.0", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.44.0.tgz", + "integrity": "sha512-8+rvzBbVm/1Z3sG3x7GUNAaxIKxwgz8xaMhRs23nrCnMTKRFAhEC+82zAIFeAA0seXdrAGX5HFCkaLpGK2rVHg==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.44.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", @@ -2990,6 +2988,15 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, "node_modules/@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -3008,6 +3015,15 @@ "@types/node": "*" } }, + "node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -3019,7 +3035,6 @@ "version": "3.0.15", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/unist": "^2" @@ -3039,6 +3054,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "license": "MIT" + }, "node_modules/@types/node": { "version": "25.6.0", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", @@ -3063,6 +3084,12 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/prop-types": { + "version": "15.7.15", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", + "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", + "license": "MIT" + }, "node_modules/@types/q": { "version": "1.5.8", "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz", @@ -3070,6 +3097,16 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "license": "MIT", + "peer": true, + "dependencies": { + "csstype": "^3.2.2" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -3082,7 +3119,6 @@ "version": "2.0.11", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz", "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", - "dev": true, "license": "MIT" }, "node_modules/@types/yauzl": { @@ -5463,6 +5499,16 @@ "node": ">=4" } }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -5482,7 +5528,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz", "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -5493,7 +5538,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz", "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -5504,7 +5548,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz", "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -5882,6 +5925,16 @@ "dev": true, "license": "MIT" }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -6594,6 +6647,13 @@ "node": ">=0.10.0" } }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT", + "peer": true + }, "node_modules/cuint": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", @@ -6704,7 +6764,6 @@ "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6767,6 +6826,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decode-named-character-reference": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz", + "integrity": "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==", + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decode-named-character-reference/node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/decode-uri-component": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", @@ -7122,6 +7204,15 @@ "deps-sort": "bin/cmd.js" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/des.js": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", @@ -7189,6 +7280,15 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/diff": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", + "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/diffie-hellman": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", @@ -8789,7 +8889,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, "license": "MIT" }, "node_modules/extend-shallow": { @@ -9002,6 +9101,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fault": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz", + "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==", + "license": "MIT", + "dependencies": { + "format": "^0.2.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", @@ -9416,6 +9528,14 @@ "dev": true, "license": "BSD" }, + "node_modules/format": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz", + "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==", + "engines": { + "node": ">=0.4.x" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -10934,6 +11054,76 @@ "node": ">= 0.4" } }, + "node_modules/hast-util-parse-selector": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz", + "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz", + "integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz", + "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "comma-separated-tokens": "^1.0.0", + "hast-util-parse-selector": "^2.0.0", + "property-information": "^5.0.0", + "space-separated-tokens": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hastscript/node_modules/comma-separated-tokens": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz", + "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hastscript/node_modules/property-information": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz", + "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==", + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/hastscript/node_modules/space-separated-tokens": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz", + "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/hex-color-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz", @@ -10952,6 +11142,12 @@ "node": "*" } }, + "node_modules/highlightjs-vue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/highlightjs-vue/-/highlightjs-vue-1.0.0.tgz", + "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", + "license": "CC0-1.0" + }, "node_modules/hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -11365,6 +11561,12 @@ "source-map": "~0.5.3" } }, + "node_modules/inline-style-parser": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz", + "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==", + "license": "MIT" + }, "node_modules/inquirer": { "version": "7.3.3", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", @@ -11642,7 +11844,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz", "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -11653,7 +11854,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz", "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==", - "dev": true, "license": "MIT", "dependencies": { "is-alphabetical": "^1.0.0", @@ -11858,7 +12058,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz", "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -12011,7 +12210,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz", "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==", - "dev": true, "license": "MIT", "funding": { "type": "github", @@ -12508,21 +12706,10 @@ "node": ">=6" } }, - "node_modules/js-cookie": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", - "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -12696,6 +12883,15 @@ "node": ">=0.10.0" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/known-css-properties": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.18.0.tgz", @@ -13087,7 +13283,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -13122,6 +13317,29 @@ "node": ">=0.10.0" } }, + "node_modules/lowlight": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz", + "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==", + "license": "MIT", + "dependencies": { + "fault": "^1.0.0", + "highlight.js": "~10.7.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lowlight/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, "node_modules/lpad-align": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/lpad-align/-/lpad-align-1.1.2.tgz", @@ -13292,6 +13510,16 @@ "node": ">=0.10.0" } }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/marked": { "version": "15.0.12", "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", @@ -13496,299 +13724,1399 @@ "safe-buffer": "^5.1.2" } }, - "node_modules/mdast-util-from-markdown": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", - "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", - "dev": true, + "node_modules/mdast-util-definitions": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", + "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", "license": "MIT", "dependencies": { "@types/mdast": "^3.0.0", - "mdast-util-to-string": "^2.0.0", - "micromark": "~2.11.0", - "parse-entities": "^2.0.0", - "unist-util-stringify-position": "^2.0.0" + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-markdown": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", - "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", - "dev": true, + "node_modules/mdast-util-find-and-replace": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-2.2.2.tgz", + "integrity": "sha512-MTtdFRz/eMDHXzeK6W3dO7mXUlF82Gom4y0oOgvHhh/HXZAGvIQDUvQ0SuUx+j2tv44b8xTHOm8K/9OoRFnXKw==", "license": "MIT", "dependencies": { - "@types/unist": "^2.0.0", - "longest-streak": "^2.0.0", - "mdast-util-to-string": "^2.0.0", - "parse-entities": "^2.0.0", - "repeat-string": "^1.0.0", - "zwitch": "^1.0.0" + "@types/mdast": "^3.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/mdast-util-to-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", - "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", - "dev": true, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", "license": "MIT", + "engines": { + "node": ">=12" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/unified" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mdn-data": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", - "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", - "dev": true, - "license": "CC0-1.0" - }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "dev": true, + "node_modules/mdast-util-find-and-replace/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/memoizee": { - "version": "0.4.17", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", - "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", - "dev": true, - "license": "ISC", "dependencies": { - "d": "^1.0.2", - "es5-ext": "^0.10.64", - "es6-weak-map": "^2.0.3", - "event-emitter": "^0.3.5", - "is-promise": "^2.2.2", - "lru-queue": "^0.1.0", - "next-tick": "^1.1.0", - "timers-ext": "^0.1.7" + "@types/unist": "^2.0.0" }, - "engines": { - "node": ">=0.12" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "node_modules/mdast-util-from-markdown": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz", + "integrity": "sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "@types/mdast": "^3.0.0", + "mdast-util-to-string": "^2.0.0", + "micromark": "~2.11.0", + "parse-entities": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", - "dev": true, + "node_modules/mdast-util-gfm": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-2.0.2.tgz", + "integrity": "sha512-qvZ608nBppZ4icQlhQQIAdc6S3Ffj9RGmzwUKUWuEICFnd1LVkN3EktF7ZHAgfcEdvZB5owU9tQgt99e2TlLjg==", "license": "MIT", - "optional": true, "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-gfm-autolink-literal": "^1.0.0", + "mdast-util-gfm-footnote": "^1.0.0", + "mdast-util-gfm-strikethrough": "^1.0.0", + "mdast-util-gfm-table": "^1.0.0", + "mdast-util-gfm-task-list-item": "^1.0.0", + "mdast-util-to-markdown": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", - "dev": true, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-1.0.3.tgz", + "integrity": "sha512-My8KJ57FYEy2W2LyNom4n3E7hKTuQk/0SES0u16tjA9Z3oFkF4RrC/hPAPgjlSpezsOvI8ObcXcElo92wn5IGA==", "license": "MIT", - "optional": true, "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "@types/mdast": "^3.0.0", + "ccount": "^2.0.0", + "mdast-util-find-and-replace": "^2.0.0", + "micromark-util-character": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", - "dev": true, + "node_modules/mdast-util-gfm-footnote": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-1.0.2.tgz", + "integrity": "sha512-56D19KOGbE00uKVj3sgIykpwKL179QsVFwx/DCW0u/0+URsryacI4MAdNJl0dh+u2PSsD9FtxPFbHCzJ78qJFQ==", "license": "MIT", - "optional": true, "dependencies": { - "error-ex": "^1.2.0" + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0", + "micromark-util-normalize-identifier": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", - "dev": true, + "node_modules/mdast-util-gfm-footnote/node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-footnote/node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", "license": "MIT", - "optional": true, "dependencies": { - "pinkie-promise": "^2.0.0" + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", - "dev": true, + "node_modules/mdast-util-gfm-footnote/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", "license": "MIT", - "optional": true, "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "@types/mdast": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, + "node_modules/mdast-util-gfm-footnote/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/meow/node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", - "dev": true, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-1.0.3.tgz", + "integrity": "sha512-DAPhYzTYrRcXdMjUtUjKvW9z/FNAMTdU0ORyMcbmkwYNbKocDpdk+PX1L1dQgOID/+vVs1uBQ7ElrBQfZ0cuiQ==", "license": "MIT", - "optional": true, "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", - "dev": true, + "node_modules/mdast-util-gfm-strikethrough/node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", "license": "MIT", - "optional": true, "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/meow/node_modules/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", - "dev": true, + "node_modules/mdast-util-gfm-strikethrough/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", "license": "MIT", - "optional": true, "dependencies": { - "is-utf8": "^0.2.0" + "@types/mdast": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/merge-descriptors": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", - "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", - "dev": true, + "node_modules/mdast-util-gfm-strikethrough/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", "license": "MIT", "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/merge-source-map": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", - "integrity": "sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==", - "dev": true, + "node_modules/mdast-util-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-1.0.7.tgz", + "integrity": "sha512-jjcpmNnQvrmN5Vx7y7lEc2iIOEytYv7rTvu+MeyAsSHTASGCCRA79Igg2uKssgOs1i1po8s3plW0sTu1wkkLGg==", "license": "MIT", "dependencies": { - "source-map": "^0.5.6" + "@types/mdast": "^3.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" + "node_modules/mdast-util-gfm-table/node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-1.0.2.tgz", + "integrity": "sha512-PFTA1gzfp1B1UaiJVyhJZA1rm0+Tzn690frc/L8vNX1Jop4STZgOE6bxUhnzdVSB+vm2GU1tIsuQcA9bxTQpMQ==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-to-markdown": "^1.3.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm/node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-gfm/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm/node_modules/mdast-util-to-markdown": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-1.5.0.tgz", + "integrity": "sha512-bbv7TPv/WC49thZPg3jXuqzuvI45IL2EVAr/KxF0BSdHsU0ceFHOmwQn6evxAh1GaoK/6GQ1wp4R4oW2+LFL/A==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^3.0.0", + "mdast-util-to-string": "^3.0.0", + "micromark-util-decode-string": "^1.0.0", + "unist-util-visit": "^4.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/mdast-util-gfm/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm/node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-3.0.1.tgz", + "integrity": "sha512-WmI1gTXUBJo4/ZmSk79Wcb2HcjPJBzM1nlI/OUWA8yk2X9ik3ffNbBGsU+09BFmXaL1IBb9fiuvq6/KMiNycSg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-12.3.0.tgz", + "integrity": "sha512-pits93r8PhnIoU4Vy9bjW39M2jJ6/tdHyja9rrot9uujkN7UTU9SDnE6WNJz/IGyQk3XHX6yNNtrBH6cQzm8Hw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-definitions": "^5.0.0", + "micromark-util-sanitize-uri": "^1.1.0", + "trim-lines": "^3.0.0", + "unist-util-generated": "^2.0.0", + "unist-util-position": "^4.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz", + "integrity": "sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "longest-streak": "^2.0.0", + "mdast-util-to-string": "^2.0.0", + "parse-entities": "^2.0.0", + "repeat-string": "^1.0.0", + "zwitch": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz", + "integrity": "sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz", + "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizee": { + "version": "0.4.17", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.17.tgz", + "integrity": "sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "es5-ext": "^0.10.64", + "es6-weak-map": "^2.0.3", + "event-emitter": "^0.3.5", + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha512-TNdwZs0skRlpPpCUK25StC4VH+tP5GgeY1HQOOGP+lQ2xtdkN2VtT/5tiX9k3IWpkBPV9b3LsAWXn4GGi/PrSA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha512-S4eENJz1pkiQn9Znv33Q+deTOKmbl+jj1Fl+qiP/vYezj+S8x+J3Uo0ISrx/QoEvIlOaDWJhPaRd1flJ9HXZqg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha512-7BGwRHqt4s/uVbuyoeejRn4YmFnYZiFl4AuaeXHlgZf3sONF0SOGlxs2Pw8g6hCKupo08RafIO5YXFNOKTfwsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha512-WD9MTlNtI55IwYUS27iHh9tK3YoIVhxis8yKhLpTqWtml739uXc9NWTpxoHkfZf3+DkCCsXox94/VWZniuZm6A==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/meow/node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromark": { + "version": "2.11.4", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", + "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "debug": "^4.0.0", + "parse-entities": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-1.1.0.tgz", + "integrity": "sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-factory-destination": "^1.0.0", + "micromark-factory-label": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-factory-title": "^1.0.0", + "micromark-factory-whitespace": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-html-tag-name": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-2.0.3.tgz", + "integrity": "sha512-vb9OoHqrhCmbRidQv/2+Bc6pkP0FrtlhurxZofvOEy5o8RtuuvTq+RQ1Vw5ZDNrVraQZu3HixESqbG+0iKk/MQ==", + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^1.0.0", + "micromark-extension-gfm-footnote": "^1.0.0", + "micromark-extension-gfm-strikethrough": "^1.0.0", + "micromark-extension-gfm-table": "^1.0.0", + "micromark-extension-gfm-tagfilter": "^1.0.0", + "micromark-extension-gfm-task-list-item": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-1.0.5.tgz", + "integrity": "sha512-z3wJSLrDf8kRDOh2qBtoTRD53vJ+CWIyo7uyZuxf/JAbNJjiHsOpG1y5wxk8drtv3ETAHutCu6N3thkOOgueWg==", + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-1.1.2.tgz", + "integrity": "sha512-Yxn7z7SxgyGWRNa4wzf8AhYYWNrwl5q1Z8ii+CSTTIqVkmGZF1CElX2JI8g5yGoM3GAman9/PVCUFUSJ0kB/8Q==", + "license": "MIT", + "dependencies": { + "micromark-core-commonmark": "^1.0.0", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-1.0.7.tgz", + "integrity": "sha512-sX0FawVE1o3abGk3vRjOH50L5TTLr3b5XMqnP9YDRb34M0v5OoZhG+OHFz1OffZ9dlwgpTBKaT4XW/AsUVnSDw==", + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-classify-character": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-1.0.7.tgz", + "integrity": "sha512-3ZORTHtcSnMQEKtAOsBQ9/oHp9096pI/UvdPtN7ehKvrmZZ2+bbWhi0ln+I9drmwXMt5boocn6OlwQzNXeVeqw==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-1.0.2.tgz", + "integrity": "sha512-5XWB9GbAUSHTn8VPU8/1DBXMuKYT5uOgEjJb8gN3mW0PNW5OPHpSdojoqf+iq1xo7vWzw/P8bAHY0n6ijpXF7g==", + "license": "MIT", + "dependencies": { + "micromark-util-types": "^1.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-1.0.5.tgz", + "integrity": "sha512-RMFXl2uQ0pNQy6Lun2YBYT9g9INXtWJULgbt01D/x8/6yJ2qpKyzdZD3pi6UIkzF++Da49xAelVKUeUMqd5eIQ==", + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-1.1.0.tgz", + "integrity": "sha512-XaNDROBgx9SgSChd69pjiGKbV+nfHGDPVYFs5dOoDd7ZnMAE+Cuu91BCpsY8RT2NP9vo/B8pds2VQNCLiu0zhg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-1.1.0.tgz", + "integrity": "sha512-OLtyez4vZo/1NjxGhcpDSbHQ+m0IIGnT8BoPamh+7jVlzLJBH98zzuCoUeMxvM6WsNeh8wx8cKvqLiPHEACn0w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-1.1.0.tgz", + "integrity": "sha512-cRzEj7c0OL4Mw2v6nwzttyOZe8XY/Z8G0rzmWQZTBi/jjwyw/U4uqKtUORXQrR5bAZZnbTI/feRV/R7hc4jQYQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-1.1.0.tgz", + "integrity": "sha512-J7n9R3vMmgjDOCY8NPw55jiyaQnH5kBdV2/UXCtZIpnHH3P6nHUKaH7XXEYuWwx/xUJcawa8plLBEjMPU24HzQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-1.1.0.tgz", + "integrity": "sha512-v2WlmiymVSp5oMg+1Q0N1Lxmt6pMhIHD457whWM7/GUlEks1hI9xj5w3zbc4uuMKXGisksZk8DzP2UyGbGqNsQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-1.2.0.tgz", + "integrity": "sha512-lXraTwcX3yH/vMDaFWCQJP1uIszLVebzUa3ZHdrgxr7KEU/9mL4mVgCpGbyhvNLNlauROiNUq7WN5u7ndbY6xg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-1.1.0.tgz", + "integrity": "sha512-Ye01HXpkZPNcV6FiyoW2fGZDUw4Yc7vT0E9Sad83+bEDiCJ1uXu0S3mr8WLpsz3HaG3x2q0HM6CTuPdcZcluFQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-1.1.0.tgz", + "integrity": "sha512-SL0wLxtKSnklKSUplok1WQFoGhUdWYKggKUiqhX+Swala+BtptGCu5iPRc+xvzJ4PXE/hwM3FNXsfEVgoZsWbw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.1.0.tgz", + "integrity": "sha512-Q20sp4mfNf9yEqDL50WwuWZHUrCO4fEyeDCnMGmG5Pr0Cz15Uo7KBs6jq+dq0EgX4DPwwrh9m0X+zPV1ypFvUA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^1.0.0", + "micromark-util-types": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.1.0.tgz", + "integrity": "sha512-m9V0ExGv0jB1OT21mrWcuf4QhP46pH1KkfWy9ZEezqHKAxkj4mPCy3nIH1rkbdMlChLHX531eOrymlwyZIf2iw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-1.1.0.tgz", + "integrity": "sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-symbol": "^1.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-1.1.0.tgz", + "integrity": "sha512-EuEzTWSTAj9PA5GOAs992GzNh2dGQO52UvAbtSOMvXTxv3Criqb6IOzJUBCmEqrrXSblJIJBbFFv6zPxpreiJw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.2.0.tgz", + "integrity": "sha512-VTQzcuQgFUD7yYztuQFKXT49KghjtETQ+Wv/zUjGSGBioZnkA4P1XXZPT1FHeJA6RwRXSF47yvJ1tsJdoxwO+Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.1.0.tgz", + "integrity": "sha512-N+w5vhqrBihhjdpM8+5Xsxy71QWqGn7HYNUvch71iV2PM7+E3uWGox1Qp90loa1ephtCxG2ftRV/Conitc6P2Q==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^1.0.0" + } }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, + "node_modules/micromark-util-resolve-all": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-1.1.0.tgz", + "integrity": "sha512-b/G6BTMSg+bX+xVCshPTPyAu2tmA0E4X98NSR7eIbeC6ycCqCeE7wjfDIgzEbkzdEVJXRtOG4FbEm/uGbCRouA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 8" + "dependencies": { + "micromark-util-types": "^1.0.0" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true, + "node_modules/micromark-util-sanitize-uri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.2.0.tgz", + "integrity": "sha512-QO4GXv0XZfWey4pYFndLUKEAktKkG5kZTdUNaTAkzbuJxn2tNBOr+QtxR2XpWaMhbImT2dPzyLrPXLlPhph34A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.6" + "dependencies": { + "micromark-util-character": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-symbol": "^1.0.0" } }, - "node_modules/micromark": { - "version": "2.11.4", - "resolved": "https://registry.npmjs.org/micromark/-/micromark-2.11.4.tgz", - "integrity": "sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA==", - "dev": true, + "node_modules/micromark-util-subtokenize": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-1.1.0.tgz", + "integrity": "sha512-kUQHyzRoxvZO2PuLzMt2P/dwVsTiivCK8icYTeR+3WgbuPqfHgPPy7nFKbeqRivBvn/3N3GBiNC+JRTMSxEC7A==", "funding": [ { "type": "GitHub Sponsors", @@ -13801,10 +15129,44 @@ ], "license": "MIT", "dependencies": { - "debug": "^4.0.0", - "parse-entities": "^2.0.0" + "micromark-util-chunked": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "uvu": "^0.5.0" } }, + "node_modules/micromark-util-symbol": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-1.1.0.tgz", + "integrity": "sha512-uEjpEYY6KMs1g7QfJ2eX1SQEV+ZT4rUD3UcF6l57acZvLNK7PBZL+ty82Z1qhK1/yXIY4bdx04FKMgR0g4IAag==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-1.1.0.tgz", + "integrity": "sha512-ukRBgie8TIAcacscVHSiddHjO4k/q3pnedmzMQ4iwDcK0FtFCohKOlFbaOL/mPgfnPsL3C1ZyxJa4sbWrBl3jg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -14126,11 +15488,19 @@ "node": ">= 0.8.0" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mute-stdout": { @@ -14574,7 +15944,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15158,7 +16527,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz", "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==", - "dev": true, "license": "MIT", "dependencies": { "character-entities": "^1.0.0", @@ -16775,6 +18143,15 @@ "node": ">= 0.8" } }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -16802,6 +18179,33 @@ "node": ">=0.4.0" } }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/property-information": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -17269,27 +18673,292 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dev": true, "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0" + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT" + }, + "node_modules/react-markdown": { + "version": "8.0.7", + "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-8.0.7.tgz", + "integrity": "sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^2.0.0", + "@types/prop-types": "^15.0.0", + "@types/unist": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^2.0.0", + "prop-types": "^15.0.0", + "property-information": "^6.0.0", + "react-is": "^18.0.0", + "remark-parse": "^10.0.0", + "remark-rehype": "^10.0.0", + "space-separated-tokens": "^2.0.0", + "style-to-object": "^0.4.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + }, + "peerDependencies": { + "@types/react": ">=16", + "react": ">=16" + } + }, + "node_modules/react-markdown/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/react-markdown/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/react-markdown/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-markdown/node_modules/mdast-util-from-markdown": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-1.3.1.tgz", + "integrity": "sha512-4xTO/M8c82qBcnQc1tgpNtubGUW/Y1tBQ1B0i5CtSoelOLKFYlElIr3bvgREYYO5iRqbMY1YuqZng0GVOI8Qww==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "decode-named-character-reference": "^1.0.0", + "mdast-util-to-string": "^3.1.0", + "micromark": "^3.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-decode-string": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.0", + "unist-util-stringify-position": "^3.0.0", + "uvu": "^0.5.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/mdast-util-to-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-3.2.0.tgz", + "integrity": "sha512-V4Zn/ncyN1QNSqSBxTrMOLpjr+IKdHl2v3KVLoWmDPscP4r9GcCi71gjgvUV1SFSKh92AjAG4peFuBl2/YgCJg==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/micromark": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-3.2.0.tgz", + "integrity": "sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "micromark-core-commonmark": "^1.0.1", + "micromark-factory-space": "^1.0.0", + "micromark-util-character": "^1.0.0", + "micromark-util-chunked": "^1.0.0", + "micromark-util-combine-extensions": "^1.0.0", + "micromark-util-decode-numeric-character-reference": "^1.0.0", + "micromark-util-encode": "^1.0.0", + "micromark-util-normalize-identifier": "^1.0.0", + "micromark-util-resolve-all": "^1.0.0", + "micromark-util-sanitize-uri": "^1.0.0", + "micromark-util-subtokenize": "^1.0.0", + "micromark-util-symbol": "^1.0.0", + "micromark-util-types": "^1.0.1", + "uvu": "^0.5.0" + } + }, + "node_modules/react-markdown/node_modules/remark-parse": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz", + "integrity": "sha512-3ydxgHa/ZQzG8LvC7jTXccARYDcRld3VfcgIIFs7bI6vbRSxJJmzgLEIIoYKyrfhaY+ujuWaf/PJiMZXoiCXgw==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-from-markdown": "^1.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/react-markdown/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/react-markdown/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "dev": true, + "node_modules/react-syntax-highlighter": { + "version": "15.6.6", + "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.6.6.tgz", + "integrity": "sha512-DgXrc+AZF47+HvAPEmn7Ua/1p10jNoVZVI/LoPiYdtY+OM+/nG5yefLHKJwdKqY1adMuHFbeyBaG9j64ML7vTw==", "license": "MIT", "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" + "@babel/runtime": "^7.3.1", + "highlight.js": "^10.4.1", + "highlightjs-vue": "^1.0.0", + "lowlight": "^1.17.0", + "prismjs": "^1.30.0", + "refractor": "^3.6.0" }, "peerDependencies": { - "react": "^18.3.1" + "react": ">= 0.14.0" + } + }, + "node_modules/react-syntax-highlighter/node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "license": "BSD-3-Clause", + "engines": { + "node": "*" } }, "node_modules/read-cache": { @@ -17589,6 +19258,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/refractor": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz", + "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==", + "license": "MIT", + "dependencies": { + "hastscript": "^6.0.0", + "parse-entities": "^2.0.0", + "prismjs": "~1.27.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/refractor/node_modules/prismjs": { + "version": "1.27.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz", + "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -17619,143 +19312,409 @@ "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" }, - "engines": { - "node": ">=0.10.0" + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-not/node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/regexpu-core": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", + "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.2", + "regjsgen": "^0.8.0", + "regjsparser": "^0.13.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.2.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", + "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.1.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/remark": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", + "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "remark-parse": "^9.0.0", + "remark-stringify": "^9.0.0", + "unified": "^9.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-3.0.1.tgz", + "integrity": "sha512-lEFDoi2PICJyNrACFOfDD3JlLkuSbOa5Wd8EPt06HUdptv8Gn0bxYTdbU/XXQ3swAPkEaGxxPN9cbnMHvVu1Ig==", + "license": "MIT", + "dependencies": { + "@types/mdast": "^3.0.0", + "mdast-util-gfm": "^2.0.0", + "micromark-extension-gfm": "^2.0.0", + "unified": "^10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/remark-gfm/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/remark-gfm/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/remark-gfm/node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/remark-gfm/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==", + "node_modules/remark-parse": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", + "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", "dev": true, "license": "MIT", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "mdast-util-from-markdown": "^0.8.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, + "node_modules/remark-rehype": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-10.1.0.tgz", + "integrity": "sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw==", "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "@types/hast": "^2.0.0", + "@types/mdast": "^3.0.0", + "mdast-util-to-hast": "^12.1.0", + "unified": "^10.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regex-not/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, + "node_modules/remark-rehype/node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/remark-rehype/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", - "dependencies": { - "isobject": "^3.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, + "node_modules/remark-rehype/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true, + "node_modules/remark-rehype/node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", "license": "MIT", - "engines": { - "node": ">=6.5.0" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, + "node_modules/remark-rehype/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", "license": "MIT", "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" }, - "engines": { - "node": ">=4" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.1.tgz", - "integrity": "sha512-dLsljMd9sqwRkby8zhO1gSg3PnJIBFid8f4CQj/sXx+7cKx+E7u0PKhZ+U4wmhx7EfmtvnA318oVaIkAB1lRJw==", - "dev": true, - "license": "BSD-2-Clause", + "node_modules/remark-rehype/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "license": "MIT", "dependencies": { - "jsesc": "~3.1.0" + "@types/unist": "^2.0.0" }, - "bin": { - "regjsparser": "bin/parser" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" } }, - "node_modules/remark": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/remark/-/remark-13.0.0.tgz", - "integrity": "sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA==", - "dev": true, + "node_modules/remark-rehype/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", "license": "MIT", "dependencies": { - "remark-parse": "^9.0.0", - "remark-stringify": "^9.0.0", - "unified": "^9.1.0" + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/unified" } }, - "node_modules/remark-parse": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-9.0.0.tgz", - "integrity": "sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw==", - "dev": true, + "node_modules/remark-rehype/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", "license": "MIT", "dependencies": { - "mdast-util-from-markdown": "^0.8.0" + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" }, "funding": { "type": "opencollective", @@ -18130,6 +20089,18 @@ "dev": true, "license": "0BSD" }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-array-concat": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", @@ -18254,7 +20225,6 @@ "version": "0.23.2", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "dev": true, "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -19062,6 +21032,16 @@ "dev": true, "license": "MIT" }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/sparkles": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", @@ -19667,6 +21647,15 @@ "dev": true, "license": "ISC" }, + "node_modules/style-to-object": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz", + "integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.1.1" + } + }, "node_modules/stylehacks": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz", @@ -20726,26 +22715,6 @@ "tlds": "bin.js" } }, - "node_modules/tldts": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.29.tgz", - "integrity": "sha512-JIXCerhudr/N6OWLwLF1HVsTTUo7ry6qHa5eWZEkiMuxsIiAACL55tGLfqfHfoH7QaMQUW8fngD7u7TxWexYQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^7.0.29" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "7.0.29", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.29.tgz", - "integrity": "sha512-W99NuU7b1DcG3uJ3v9k9VztCH3WialNbBkBft5wCs8V8mexu0XQqaZEYb9l9RNNzK8+3EJ9PKWB0/RUtTQ/o+Q==", - "dev": true, - "license": "MIT" - }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -21003,6 +22972,16 @@ "node": ">=4" } }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/trim-newlines": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", @@ -21505,6 +23484,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-generated": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-2.0.1.tgz", + "integrity": "sha512-qF72kLmPxAw0oN2fwpWIqbXAVyEqUzDHMsbtPvOudIlUzXYFIeQIuxXQCRCFh22B7cixvU0MG7m3MW8FTq/S+A==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-is": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.1.0.tgz", @@ -21516,6 +23505,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-position": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz", + "integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/unist-util-stringify-position": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", @@ -21530,6 +23532,61 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "license": "MIT", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -21821,6 +23878,24 @@ "uuid": "bin/uuid" } }, + "node_modules/uvu": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", + "integrity": "sha512-+g8ENReyr8YsOc6fv/NVJs2vFdHBnBNdfE49rshrTzDWOlUx4Gq7KOS2GD8eqhy2j+Ejq29+SbKH8yjkAqXqoA==", + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0", + "diff": "^5.0.0", + "kleur": "^4.0.3", + "sade": "^1.7.3" + }, + "bin": { + "uvu": "bin.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/v8-compile-cache": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", @@ -22466,7 +24541,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4" diff --git a/package.json b/package.json index fea318c2..b31ea4b9 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,6 @@ "@docsearch/js": "^3.3.3", "@fontsource/roboto": "~4.5", "@fontsource/roboto-mono": "~4.5", - "@kapaai/react-sdk": "^0.9.0", "autoprefixer": "~9.7", "babelify": "^10.0.0", "browser-pack-flat": "~3.4", @@ -37,6 +36,7 @@ "eslint-plugin-node": "~11.1", "eslint-plugin-promise": "~4.2", "eslint-plugin-standard": "~4.0", + "express": "^4.18.0", "fancy-log": "~1.3", "fs-extra": "~8.1", "gulp": "~4.0", @@ -63,7 +63,6 @@ "postcss-url": "~8.0", "prettier-eslint": "~9.0", "puppeteer": "^21.0.0", - "express": "^4.18.0", "react": "^18.3.1", "react-dom": "^18.3.1", "require-directory": "~2.1", @@ -82,5 +81,8 @@ "build:wasm": "cd blobl-editor/wasm && GOOS=js GOARCH=wasm go build -o ../../src/static/blobl.wasm .", "copy:wasm-exec": "cp \"$(go env GOROOT)/lib/wasm/wasm_exec.js\" src/js/vendor/", "serve:playground": "npx serve ." + }, + "dependencies": { + "@kapaai/agent-react": "^1.0.0" } } diff --git a/src/css/chat-panel-bump.css b/src/css/chat-panel-bump.css index e2ea24be..9247b7b9 100644 --- a/src/css/chat-panel-bump.css +++ b/src/css/chat-panel-bump.css @@ -94,8 +94,7 @@ /* Scrollable content area */ .chat-scroll { flex: 1; - overflow-y: auto; - overflow-x: hidden; + overflow: hidden; padding: 0; min-height: 0; /* Critical for flex children to respect parent constraints */ position: relative; @@ -124,7 +123,6 @@ display: flex; flex-direction: column; height: 100%; - min-height: 0; font-family: var(--font-sans, "Inter", -apple-system, BlinkMacSystemFont, sans-serif); } @@ -132,17 +130,17 @@ #chat-panel-kapa-root .chat-container { display: flex; flex-direction: column; - height: 100%; - overflow: hidden; + flex: 1; + min-height: 0; } /* Conversation area - scrollable */ #chat-panel-kapa-root .conversation-area { flex: 1; - overflow-y: auto; - padding: 16px 18px 180px; min-height: 0; + overflow-y: auto; overscroll-behavior: contain; + padding: 16px 18px 24px; } #chat-panel-kapa-root .conversation { @@ -305,8 +303,13 @@ display: flex; justify-content: space-between; align-items: center; - margin-top: 8px; - padding-top: 8px; + margin: 8px 0 12px; + min-height: 0; + padding: 8px 0 0; + border: none; + border-radius: 0; + box-shadow: none; + background: transparent; } #chat-panel-kapa-root .action-buttons { @@ -339,40 +342,6 @@ } /* Feedback buttons (thumbs up/down) */ -#chat-panel-kapa-root .feedback-container { - display: flex; - gap: 2px; -} - -#chat-panel-kapa-root .feedback-group { - display: flex; - gap: 2px; -} - -#chat-panel-kapa-root .feedback-button { - display: inline-grid; - place-items: center; - width: 28px; - height: 28px; - padding: 0; - background: transparent; - border: 1px solid var(--grey-200-new, #e5e5e5); - border-radius: 6px; - color: var(--grey-500-new, #6b7280); - cursor: pointer; - transition: all 0.12s ease; -} - -#chat-panel-kapa-root .feedback-button:hover { - background: var(--grey-50-new, #f9fafb); - border-color: var(--grey-300-new, #d1d5db); - color: var(--grey-700-new, #374151); -} - -#chat-panel-kapa-root .feedback-icon { - width: 14px; - height: 14px; -} /* Footer wrapper - fixed at bottom */ #chat-panel-kapa-root .chat-footer-wrapper { @@ -382,14 +351,19 @@ display: flex; flex-direction: column; flex-shrink: 0; + /* Explicit: page-level styles must not leak into the panel */ + position: static; + z-index: auto; + max-width: none; + width: auto; } #chat-panel-kapa-root .chat-footer-wrapper.fixed-bottom { - position: absolute; - bottom: 0; - left: 0; - right: 0; border-top: 1px solid var(--grey-100-new, #e5e5e5); + position: static; + bottom: auto; + padding: 0; + background: #fff; } #chat-panel-kapa-root .chat-footer-wrapper form { @@ -543,11 +517,12 @@ display: flex; flex-direction: column; align-items: center; - justify-content: center; - padding: 60px 24px 24px; + justify-content: flex-start; + padding: 40px 24px 24px; text-align: center; flex: 1; min-height: 0; + overflow-y: auto; } #chat-panel-kapa-root .welcome-icon { @@ -617,7 +592,7 @@ #chat-panel-kapa-root .chat-input-wrapper { display: flex; - align-items: center; + align-items: flex-end; gap: 10px; background: #fff; border: 2px solid var(--grey-200-new, #e5e5e5); @@ -699,7 +674,8 @@ /* Disclaimer - always visible at bottom */ #chat-panel-kapa-root .disclaimer { - padding: 10px 14px 14px; + margin: 0; + padding: 8px 14px 10px; font-size: calc(12 / var(--rem-base) * 1rem); color: var(--grey-500-new, #6b7280); text-align: center; @@ -1064,17 +1040,6 @@ html[data-theme="dark"] #chat-panel-kapa-root .action-button:hover { color: #aab8ca !important; } -html[data-theme="dark"] #chat-panel-kapa-root .feedback-button { - border-color: rgba(255, 255, 255, 0.1) !important; - color: #7c8ca8 !important; -} - -html[data-theme="dark"] #chat-panel-kapa-root .feedback-button:hover { - background: rgba(255, 255, 255, 0.05) !important; - border-color: rgba(255, 255, 255, 0.15) !important; - color: #aab8ca !important; -} - /* ============================================================================= TOAST NOTIFICATIONS Floating toast for copy/feedback confirmations @@ -1174,3 +1139,230 @@ html[data-theme="dark"] #chat-panel-kapa-root .chat-toast-error { border-color: #ef4444 !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(239, 68, 68, 0.2) !important; } + +/* ——— Conversation history (Kapa Agent SDK) ——— */ +#chat-panel-kapa-root .chat-history-toggle-row { + display: flex; + justify-content: flex-end; + padding: 8px 0 0; +} + +#chat-panel-kapa-root .chat-history-view { + flex: 1; + min-height: 0; + overflow-y: auto; + margin: 8px 18px; + border: 1px solid var(--kapa-border, #dcdcde); + border-radius: 8px; + background: var(--kapa-surface, #fff); +} + +/* ——— Per-answer sources ——— */ +#chat-panel-kapa-root .answer-sources { + margin-top: 8px; + font-size: calc(12 / var(--rem-base) * 1rem); +} + +#chat-panel-kapa-root .answer-sources-label { + display: block; + font-weight: 600; + color: var(--kapa-text-muted, #4b5563); + margin-bottom: 2px; +} + +#chat-panel-kapa-root .answer-sources ul { + margin: 0; + padding-left: 16px; +} + +#chat-panel-kapa-root .answer-sources li { + margin: 2px 0; +} + +#chat-panel-kapa-root .answer-sources a { + color: var(--kapa-accent, #444ce7); + text-decoration: none; +} + +#chat-panel-kapa-root .answer-sources a:hover { + text-decoration: underline; +} + +/* ——— Error answers ——— */ +#chat-panel-kapa-root .qa-pair-error .answer { + color: #ef4444; +} + +/* ——— Full-screen mode ——— */ +.chat-panel .chat-icon-collapse { + display: none; +} + +.chat-panel.is-fullscreen .chat-icon-expand { + display: none; +} + +.chat-panel.is-fullscreen .chat-icon-collapse { + display: block; +} + +.chat-panel.is-fullscreen { + width: 100%; + border-left: none; + box-shadow: none; +} + +/* Keep a readable centered column when the panel spans the viewport */ +.chat-panel.is-fullscreen #chat-panel-kapa-root .conversation, +.chat-panel.is-fullscreen #chat-panel-kapa-root .welcome-screen, +.chat-panel.is-fullscreen #chat-panel-kapa-root .chat-history-toggle-row, +.chat-panel.is-fullscreen #chat-panel-kapa-root .chat-history-view, +.chat-panel.is-fullscreen #chat-panel-kapa-root .chat-input-form, +.chat-panel.is-fullscreen #chat-panel-kapa-root .disclaimer { + width: 100%; + max-width: 860px; + margin-left: auto; + margin-right: auto; +} + +/* The drawer is already full-width on small screens */ +@media (max-width: 520px) { + .chat-panel [data-chat-action="expand"] { + display: none; + } +} + +/* ——— Multiline input (Enter submits, Shift+Enter adds a line) ——— */ +#chat-panel-kapa-root .chat-input-wrapper textarea.chat-input { + resize: none; + min-height: 0; + max-height: 132px; + overflow-y: auto; + line-height: 1.5; +} + +#chat-panel-kapa-root .chat-input-wrapper .submit-button { + flex-shrink: 0; +} + +/* ——— Agent tool call cards (SDK-rendered) ——— */ +#chat-panel-kapa-root .tool-calls { + margin: 8px 0; +} + +/* ——— Sign-in gate (agent tier is signed-in only) ——— */ +#chat-panel-kapa-root .signin-screen { + flex: 1; + min-height: 0; + overflow-y: auto; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + padding: 48px 24px 24px; + text-align: center; +} + +#chat-panel-kapa-root .signin-button { + display: inline-block; + margin-top: 20px; + padding: 10px 28px; + background: var(--kapa-accent, #444ce7); + color: #fff; + border-radius: 999px; + font-weight: 600; + font-size: calc(14 / var(--rem-base) * 1rem); + text-decoration: none; +} + +#chat-panel-kapa-root .signin-button:hover { + background: var(--kapa-accent-hover, #3538cd); + text-decoration: none; +} + +#chat-panel-kapa-root .signin-quick-ask { + margin-top: 14px; + padding: 4px 8px; + background: none; + border: none; + color: var(--kapa-text-muted, #79797d); + font-size: calc(13 / var(--rem-base) * 1rem); + font-family: inherit; + cursor: pointer; + text-decoration: underline; +} + +#chat-panel-kapa-root .signin-quick-ask:hover { + color: var(--kapa-text, #181818); +} + +#chat-panel-kapa-root .signin-coming-soon { + margin: 16px 0 0; + font-size: calc(13 / var(--rem-base) * 1rem); + color: var(--kapa-text-muted, #79797d); +} + +#chat-panel-kapa-root button.signin-button { + border: none; + cursor: pointer; + font-family: inherit; +} + +.dark-theme #chat-panel-kapa-root .signin-button { + color: #0f1729; +} + +#chat-panel-kapa-root .signin-features { + margin: 4px auto 20px; + padding: 0 0 0 20px; + max-width: 320px; + text-align: left; + display: flex; + flex-direction: column; + gap: 8px; + font-size: calc(14 / var(--rem-base) * 1rem); + line-height: 1.45; + color: var(--kapa-text, #181818); +} + +/* ——— Scroll-to-input button (panel-scoped; home.css only styles it under .home) ——— */ +#chat-panel-kapa-root .scroll-down-button { + position: absolute; + top: -3rem; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + background: var(--kapa-surface, #fff); + color: var(--kapa-text, #181818); + border: 1px solid var(--kapa-border, #e5e5e5); + border-radius: 50%; + padding: 8px; + z-index: 10; + box-shadow: 0 4px 12px rgba(15, 23, 42, 0.18); + cursor: pointer; +} + +#chat-panel-kapa-root .scroll-down-button:hover { + background: var(--kapa-surface-hover, #ebebeb); +} + +#chat-panel-kapa-root .scroll-down-button svg { + width: 18px; + height: 18px; +} + +html[data-theme="dark"] #chat-panel-kapa-root .action-button, +html[data-theme="dark"] #chat-panel-kapa-root .chat-history-toggle { + color: var(--kapa-text-subtle, #aab8ca); + background: var(--kapa-surface-elevated, #232f3e); + border-color: rgba(255, 255, 255, 0.28); +} + +html[data-theme="dark"] #chat-panel-kapa-root .action-button:hover, +html[data-theme="dark"] #chat-panel-kapa-root .chat-history-toggle:hover { + color: var(--kapa-text, #e8eef6); + border-color: rgba(255, 255, 255, 0.4); + background: var(--kapa-surface-hover, #2d3a53); +} diff --git a/src/css/chat-panel.css b/src/css/chat-panel.css index 695a9f02..3dbdae66 100644 --- a/src/css/chat-panel.css +++ b/src/css/chat-panel.css @@ -94,8 +94,7 @@ /* Scrollable content area */ .chat-scroll { flex: 1; - overflow-y: auto; - overflow-x: hidden; + overflow: hidden; padding: 0; min-height: 0; /* Critical for flex children to respect parent constraints */ position: relative; @@ -124,7 +123,6 @@ display: flex; flex-direction: column; height: 100%; - min-height: 0; font-family: var(--font-sans, "Inter", -apple-system, BlinkMacSystemFont, sans-serif); } @@ -132,17 +130,17 @@ #chat-panel-kapa-root .chat-container { display: flex; flex-direction: column; - height: 100%; - overflow: hidden; + flex: 1; + min-height: 0; } /* Conversation area - scrollable */ #chat-panel-kapa-root .conversation-area { flex: 1; - overflow-y: auto; - padding: 16px 18px 240px; min-height: 0; + overflow-y: auto; overscroll-behavior: contain; + padding: 16px 18px 24px; } #chat-panel-kapa-root .conversation { @@ -305,9 +303,13 @@ display: flex; justify-content: space-between; align-items: center; - margin-top: 8px; - margin-bottom: 20px; - min-height: 60px; + margin: 8px 0 12px; + min-height: 0; + padding: 0; + border: none; + border-radius: 0; + box-shadow: none; + background: transparent; } #chat-panel-kapa-root .action-buttons { @@ -340,40 +342,6 @@ } /* Feedback buttons (thumbs up/down) */ -#chat-panel-kapa-root .feedback-container { - display: flex; - gap: 2px; -} - -#chat-panel-kapa-root .feedback-group { - display: flex; - gap: 2px; -} - -#chat-panel-kapa-root .feedback-button { - display: inline-grid; - place-items: center; - width: 28px; - height: 28px; - padding: 0; - background: transparent; - border: 1px solid var(--kapa-border-subtle, #e5e5e5); - border-radius: 6px; - color: var(--kapa-text-muted, #6b7280); - cursor: pointer; - transition: all 0.12s ease; -} - -#chat-panel-kapa-root .feedback-button:hover { - background: var(--kapa-surface-hover, #f9fafb); - border-color: var(--kapa-border, #d1d5db); - color: var(--kapa-text, #374151); -} - -#chat-panel-kapa-root .feedback-icon { - width: 14px; - height: 14px; -} /* Footer wrapper - fixed at bottom */ #chat-panel-kapa-root .chat-footer-wrapper { @@ -383,14 +351,20 @@ display: flex; flex-direction: column; flex-shrink: 0; + /* Explicit: page-level styles for the legacy home-page chat (home.css + .chat-footer-wrapper rules) must not leak into the panel */ + position: static; + z-index: auto; + max-width: none; + width: auto; } #chat-panel-kapa-root .chat-footer-wrapper.fixed-bottom { - position: absolute; - bottom: 0; - left: 0; - right: 0; border-top: 1px solid var(--kapa-border, #e5e5e5); + position: static; + bottom: auto; + padding: 0; + background: var(--kapa-surface, #fff); } #chat-panel-kapa-root .chat-footer-wrapper form { @@ -544,11 +518,12 @@ display: flex; flex-direction: column; align-items: center; - justify-content: center; - padding: 60px 24px 24px; + justify-content: flex-start; + padding: 40px 24px 24px; text-align: center; flex: 1; min-height: 0; + overflow-y: auto; } #chat-panel-kapa-root .welcome-icon { @@ -618,7 +593,7 @@ #chat-panel-kapa-root .chat-input-wrapper { display: flex; - align-items: center; + align-items: flex-end; gap: 10px; background: var(--kapa-surface, #fff); border: 2px solid var(--kapa-border-subtle, #e5e5e5); @@ -700,7 +675,8 @@ /* Disclaimer - always visible at bottom */ #chat-panel-kapa-root .disclaimer { - padding: 10px 14px 14px; + margin: 0; + padding: 8px 14px 10px; font-size: calc(12 / var(--rem-base) * 1rem); color: var(--kapa-text-muted, #6b7280); text-align: center; @@ -903,17 +879,6 @@ color: var(--kapa-text-muted); } -.dark-theme #chat-panel-kapa-root .feedback-button { - border-color: var(--kapa-border-subtle); - color: var(--kapa-text-muted); -} - -.dark-theme #chat-panel-kapa-root .feedback-button:hover { - background: rgba(255, 255, 255, 0.05); - border-color: var(--kapa-border); - color: var(--kapa-text-subtle); -} - /* ============================================================================= TOAST NOTIFICATIONS Floating toast for copy/feedback confirmations @@ -1013,3 +978,230 @@ border-color: #ef4444; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(239, 68, 68, 0.2); } + +/* ——— Conversation history (Kapa Agent SDK) ——— */ +#chat-panel-kapa-root .chat-history-toggle-row { + display: flex; + justify-content: flex-end; + padding: 8px 0 0; +} + +#chat-panel-kapa-root .chat-history-view { + flex: 1; + min-height: 0; + overflow-y: auto; + margin: 8px 18px; + border: 1px solid var(--kapa-border, #dcdcde); + border-radius: 8px; + background: var(--kapa-surface, #fff); +} + +/* ——— Per-answer sources ——— */ +#chat-panel-kapa-root .answer-sources { + margin-top: 8px; + font-size: calc(12 / var(--rem-base) * 1rem); +} + +#chat-panel-kapa-root .answer-sources-label { + display: block; + font-weight: 600; + color: var(--kapa-text-muted, #4b5563); + margin-bottom: 2px; +} + +#chat-panel-kapa-root .answer-sources ul { + margin: 0; + padding-left: 16px; +} + +#chat-panel-kapa-root .answer-sources li { + margin: 2px 0; +} + +#chat-panel-kapa-root .answer-sources a { + color: var(--kapa-accent, #444ce7); + text-decoration: none; +} + +#chat-panel-kapa-root .answer-sources a:hover { + text-decoration: underline; +} + +/* ——— Error answers ——— */ +#chat-panel-kapa-root .qa-pair-error .answer { + color: #ef4444; +} + +/* ——— Full-screen mode ——— */ +.chat-panel .chat-icon-collapse { + display: none; +} + +.chat-panel.is-fullscreen .chat-icon-expand { + display: none; +} + +.chat-panel.is-fullscreen .chat-icon-collapse { + display: block; +} + +.chat-panel.is-fullscreen { + width: 100%; + border-left: none; + box-shadow: none; +} + +/* Keep a readable centered column when the panel spans the viewport */ +.chat-panel.is-fullscreen #chat-panel-kapa-root .conversation, +.chat-panel.is-fullscreen #chat-panel-kapa-root .welcome-screen, +.chat-panel.is-fullscreen #chat-panel-kapa-root .chat-history-toggle-row, +.chat-panel.is-fullscreen #chat-panel-kapa-root .chat-history-view, +.chat-panel.is-fullscreen #chat-panel-kapa-root .chat-input-form, +.chat-panel.is-fullscreen #chat-panel-kapa-root .disclaimer { + width: 100%; + max-width: 860px; + margin-left: auto; + margin-right: auto; +} + +/* The drawer is already full-width on small screens */ +@media (max-width: 520px) { + .chat-panel [data-chat-action="expand"] { + display: none; + } +} + +/* ——— Multiline input (Enter submits, Shift+Enter adds a line) ——— */ +#chat-panel-kapa-root .chat-input-wrapper textarea.chat-input { + resize: none; + min-height: 0; + max-height: 132px; + overflow-y: auto; + line-height: 1.5; +} + +#chat-panel-kapa-root .chat-input-wrapper .submit-button { + flex-shrink: 0; +} + +/* ——— Agent tool call cards (SDK-rendered) ——— */ +#chat-panel-kapa-root .tool-calls { + margin: 8px 0; +} + +/* ——— Sign-in gate (agent tier is signed-in only) ——— */ +#chat-panel-kapa-root .signin-screen { + flex: 1; + min-height: 0; + overflow-y: auto; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + padding: 48px 24px 24px; + text-align: center; +} + +#chat-panel-kapa-root .signin-button { + display: inline-block; + margin-top: 20px; + padding: 10px 28px; + background: var(--kapa-accent, #444ce7); + color: #fff; + border-radius: 999px; + font-weight: 600; + font-size: calc(14 / var(--rem-base) * 1rem); + text-decoration: none; +} + +#chat-panel-kapa-root .signin-button:hover { + background: var(--kapa-accent-hover, #3538cd); + text-decoration: none; +} + +#chat-panel-kapa-root .signin-quick-ask { + margin-top: 14px; + padding: 4px 8px; + background: none; + border: none; + color: var(--kapa-text-muted, #79797d); + font-size: calc(13 / var(--rem-base) * 1rem); + font-family: inherit; + cursor: pointer; + text-decoration: underline; +} + +#chat-panel-kapa-root .signin-quick-ask:hover { + color: var(--kapa-text, #181818); +} + +#chat-panel-kapa-root .signin-coming-soon { + margin: 16px 0 0; + font-size: calc(13 / var(--rem-base) * 1rem); + color: var(--kapa-text-muted, #79797d); +} + +#chat-panel-kapa-root button.signin-button { + border: none; + cursor: pointer; + font-family: inherit; +} + +.dark-theme #chat-panel-kapa-root .signin-button { + color: #0f1729; +} + +#chat-panel-kapa-root .signin-features { + margin: 4px auto 20px; + padding: 0 0 0 20px; + max-width: 320px; + text-align: left; + display: flex; + flex-direction: column; + gap: 8px; + font-size: calc(14 / var(--rem-base) * 1rem); + line-height: 1.45; + color: var(--kapa-text, #181818); +} + +/* ——— Scroll-to-input button (panel-scoped; home.css only styles it under .home) ——— */ +#chat-panel-kapa-root .scroll-down-button { + position: absolute; + top: -3rem; + left: 50%; + transform: translateX(-50%); + display: flex; + align-items: center; + justify-content: center; + background: var(--kapa-surface, #fff); + color: var(--kapa-text, #181818); + border: 1px solid var(--kapa-border, #e5e5e5); + border-radius: 50%; + padding: 8px; + z-index: 10; + box-shadow: 0 4px 12px rgba(15, 23, 42, 0.18); + cursor: pointer; +} + +#chat-panel-kapa-root .scroll-down-button:hover { + background: var(--kapa-surface-hover, #ebebeb); +} + +#chat-panel-kapa-root .scroll-down-button svg { + width: 18px; + height: 18px; +} + +.dark-theme #chat-panel-kapa-root .action-button, +.dark-theme #chat-panel-kapa-root .chat-history-toggle { + color: var(--kapa-text-subtle, #aab8ca); + background: var(--kapa-surface-elevated, #232f3e); + border-color: rgba(255, 255, 255, 0.28); +} + +.dark-theme #chat-panel-kapa-root .action-button:hover, +.dark-theme #chat-panel-kapa-root .chat-history-toggle:hover { + color: var(--kapa-text, #e8eef6); + border-color: rgba(255, 255, 255, 0.4); + background: var(--kapa-surface-hover, #2d3a53); +} diff --git a/src/css/header-bump.css b/src/css/header-bump.css index f11cc469..386366a0 100644 --- a/src/css/header-bump.css +++ b/src/css/header-bump.css @@ -896,3 +896,189 @@ html[data-theme="dark"] .sb-brand-sub { display: none; } } + +/* ——— Docs account (header sign in / user menu) ——— */ +.tb-account { + display: inline-flex; + align-items: center; +} + +.tb-signin-link { + white-space: nowrap; +} + +.tb-account-trigger { + display: inline-flex; + align-items: center; + padding: 2px; + border-radius: 50%; +} + +.tb-account-avatar { + display: inline-grid; + place-items: center; + width: 28px; + height: 28px; + border-radius: 50%; + background: var(--indigo-600-new, #444ce7); + color: #fff; + font-size: calc(13 / var(--rem-base) * 1rem); + font-weight: 600; + line-height: 1; +} + +.tb-account-dropdown { + min-width: 200px; +} + +.tb-account-email { + padding: 8px 12px; + font-size: calc(13 / var(--rem-base) * 1rem); + color: var(--grey-500, #667085); + border-bottom: 1px solid var(--grey-200, #e5e7eb); + margin-bottom: 4px; + max-width: 260px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +html[data-theme="dark"] .tb-account-email { + color: var(--grey-400, #98a2b3); + border-bottom-color: rgba(255, 255, 255, 0.08); +} + +/* The hidden attribute must win over display rules on these elements */ +.tb-account [hidden] { + display: none !important; +} + +[data-cloud-link][hidden] { + display: none !important; +} + +/* ——— Sign-in feature modal (header) ——— */ +.tb-signin-modal[hidden] { display: none; } + +.tb-signin-modal { + position: fixed; + inset: 0; + z-index: 10000000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.tb-signin-modal-backdrop { + position: absolute; + inset: 0; + background: rgba(15, 23, 42, 0.55); +} + +.tb-signin-modal-card { + position: relative; + width: 100%; + max-width: 440px; + background: #fff; + color: #181818; + border-radius: 14px; + padding: 28px 28px 24px; + box-shadow: 0 20px 60px -12px rgba(15, 23, 42, 0.4); + text-align: left; +} + +html[data-theme="dark"] .tb-signin-modal-card { + background: #161e2d; + color: #e8eef6; +} + +.tb-signin-modal-x { + position: absolute; + top: 14px; + right: 14px; + display: inline-grid; + place-items: center; + width: 30px; + height: 30px; + border: none; + background: transparent; + color: var(--grey-500, #667085); + border-radius: 6px; + cursor: pointer; +} + +.tb-signin-modal-x:hover { background: rgba(0, 0, 0, 0.06); } +html[data-theme="dark"] .tb-signin-modal-x:hover { background: rgba(255, 255, 255, 0.08); } + +.tb-signin-modal-title { + margin: 0 0 6px; + font-size: calc(20 / var(--rem-base) * 1rem); + font-weight: 700; +} + +.tb-signin-modal-sub { + margin: 0 0 16px; + font-size: calc(14 / var(--rem-base) * 1rem); + color: var(--grey-600, #475467); +} + +html[data-theme="dark"] .tb-signin-modal-sub { color: var(--grey-300, #d0d5dd); } + +.tb-signin-modal-features { + margin: 0 0 22px; + padding-left: 20px; + display: flex; + flex-direction: column; + gap: 8px; + font-size: calc(14 / var(--rem-base) * 1rem); + line-height: 1.45; +} + +.tb-signin-modal-cta { + display: block; + width: 100%; + padding: 11px 16px; + background: var(--indigo-600-new, #444ce7); + color: #fff; + border-radius: 8px; + font-weight: 600; + font-size: calc(15 / var(--rem-base) * 1rem); + text-align: center; + text-decoration: none; +} + +.tb-signin-modal-cta:hover { + background: var(--indigo-700-new, #3538cd); + text-decoration: none; +} + +.tb-signin-modal-foot { + margin: 14px 0 0; + text-align: center; + font-size: calc(13 / var(--rem-base) * 1rem); + color: var(--grey-500, #667085); +} + +.tb-signin-modal-foot a { + color: var(--indigo-600-new, #444ce7); + font-weight: 500; + text-decoration: none; +} + +.tb-signin-modal-foot a:hover { + text-decoration: underline; +} + +html[data-theme="dark"] .tb-signin-modal-foot { color: var(--grey-400, #98a2b3); } + +html[data-theme="dark"] .tb-signin-modal-foot a { color: #8098f9; } + +html[data-theme="dark"] .tb-signin-modal-cta { + background: #8098f9; + color: #0f1729; +} + +html[data-theme="dark"] .tb-signin-modal-cta:hover { + background: #a5b4fc; +} diff --git a/src/css/header.css b/src/css/header.css index f847d391..31a2cde4 100644 --- a/src/css/header.css +++ b/src/css/header.css @@ -1169,3 +1169,189 @@ html[data-theme="dark"] .tb-dropdown-item:hover { min-height: 30px; } } + +/* ——— Docs account (header sign in / user menu) ——— */ +.tb-account { + display: inline-flex; + align-items: center; +} + +.tb-signin-link { + white-space: nowrap; +} + +.tb-account-trigger { + display: inline-flex; + align-items: center; + padding: 2px; + border-radius: 50%; +} + +.tb-account-avatar { + display: inline-grid; + place-items: center; + width: 28px; + height: 28px; + border-radius: 50%; + background: var(--indigo-600-new, #444ce7); + color: #fff; + font-size: calc(13 / var(--rem-base) * 1rem); + font-weight: 600; + line-height: 1; +} + +.tb-account-dropdown { + min-width: 200px; +} + +.tb-account-email { + padding: 8px 12px; + font-size: calc(13 / var(--rem-base) * 1rem); + color: var(--grey-500, #667085); + border-bottom: 1px solid var(--grey-200, #e5e7eb); + margin-bottom: 4px; + max-width: 260px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +html[data-theme="dark"] .tb-account-email { + color: var(--grey-400, #98a2b3); + border-bottom-color: rgba(255, 255, 255, 0.08); +} + +/* The hidden attribute must win over display rules on these elements */ +.tb-account [hidden] { + display: none !important; +} + +[data-cloud-link][hidden] { + display: none !important; +} + +/* ——— Sign-in feature modal (header) ——— */ +.tb-signin-modal[hidden] { display: none; } + +.tb-signin-modal { + position: fixed; + inset: 0; + z-index: 10000000; + display: flex; + align-items: center; + justify-content: center; + padding: 20px; +} + +.tb-signin-modal-backdrop { + position: absolute; + inset: 0; + background: rgba(15, 23, 42, 0.55); +} + +.tb-signin-modal-card { + position: relative; + width: 100%; + max-width: 440px; + background: #fff; + color: #181818; + border-radius: 14px; + padding: 28px 28px 24px; + box-shadow: 0 20px 60px -12px rgba(15, 23, 42, 0.4); + text-align: left; +} + +html[data-theme="dark"] .tb-signin-modal-card { + background: #161e2d; + color: #e8eef6; +} + +.tb-signin-modal-x { + position: absolute; + top: 14px; + right: 14px; + display: inline-grid; + place-items: center; + width: 30px; + height: 30px; + border: none; + background: transparent; + color: var(--grey-500, #667085); + border-radius: 6px; + cursor: pointer; +} + +.tb-signin-modal-x:hover { background: rgba(0, 0, 0, 0.06); } +html[data-theme="dark"] .tb-signin-modal-x:hover { background: rgba(255, 255, 255, 0.08); } + +.tb-signin-modal-title { + margin: 0 0 6px; + font-size: calc(20 / var(--rem-base) * 1rem); + font-weight: 700; +} + +.tb-signin-modal-sub { + margin: 0 0 16px; + font-size: calc(14 / var(--rem-base) * 1rem); + color: var(--grey-600, #475467); +} + +html[data-theme="dark"] .tb-signin-modal-sub { color: var(--grey-300, #d0d5dd); } + +.tb-signin-modal-features { + margin: 0 0 22px; + padding-left: 20px; + display: flex; + flex-direction: column; + gap: 8px; + font-size: calc(14 / var(--rem-base) * 1rem); + line-height: 1.45; +} + +.tb-signin-modal-cta { + display: block; + width: 100%; + padding: 11px 16px; + background: var(--indigo-600-new, #444ce7); + color: #fff; + border-radius: 8px; + font-weight: 600; + font-size: calc(15 / var(--rem-base) * 1rem); + text-align: center; + text-decoration: none; +} + +.tb-signin-modal-cta:hover { + background: var(--indigo-700-new, #3538cd); + text-decoration: none; +} + +.tb-signin-modal-foot { + margin: 14px 0 0; + text-align: center; + font-size: calc(13 / var(--rem-base) * 1rem); + color: var(--grey-500, #667085); +} + +.tb-signin-modal-foot a { + color: var(--indigo-600-new, #444ce7); + font-weight: 500; + text-decoration: none; +} + +.tb-signin-modal-foot a:hover { + text-decoration: underline; +} + +html[data-theme="dark"] .tb-signin-modal-foot { color: var(--grey-400, #98a2b3); } + +html[data-theme="dark"] .tb-signin-modal-foot a { color: #8098f9; } + +html[data-theme="dark"] .tb-signin-modal-cta { + background: #8098f9; + color: #0f1729; +} + +html[data-theme="dark"] .tb-signin-modal-cta:hover { + background: #a5b4fc; +} diff --git a/src/js/19-chat-panel.js b/src/js/19-chat-panel.js index ee202bf6..0925154b 100644 --- a/src/js/19-chat-panel.js +++ b/src/js/19-chat-panel.js @@ -8,8 +8,9 @@ if (!chatPanel) return - // Storage key for persisting panel state + // Storage keys for persisting panel state var STORAGE_KEY = 'redpanda-chat-panel-open' + var FULLSCREEN_KEY = 'redpanda-chat-panel-fullscreen' // State var isOpen = false @@ -21,6 +22,17 @@ }) }) + chatPanel.querySelectorAll('[data-chat-action="expand"]').forEach(function (btn) { + btn.addEventListener('click', function () { + var fullscreen = chatPanel.classList.toggle('is-fullscreen') + try { + localStorage.setItem(FULLSCREEN_KEY, String(fullscreen)) + } catch (e) { + // localStorage not available, ignore + } + }) + }) + // Ask AI button in header (opens chat panel) document.querySelectorAll('[data-action="open-chat"]').forEach(function (btn) { btn.addEventListener('click', function () { @@ -105,6 +117,9 @@ try { var savedState = localStorage.getItem(STORAGE_KEY) var isMobile = window.innerWidth <= 520 + if (localStorage.getItem(FULLSCREEN_KEY) === 'true') { + chatPanel.classList.add('is-fullscreen') + } if (savedState === 'true' && !isMobile) { openPanel() } diff --git a/src/js/26-docs-account.js b/src/js/26-docs-account.js new file mode 100644 index 00000000..1bcd2145 --- /dev/null +++ b/src/js/26-docs-account.js @@ -0,0 +1,131 @@ +/* global sessionStorage, fetch */ +/** + * Docs account control in the header (sign in / user menu). + * + * Signed-in state comes from the JS-readable rp_docs_auth hint cookie, which + * the docs login flow sets/clears alongside the HttpOnly session cookie. The + * email shown in the menu comes from GET /auth/me (verified server-side, + * cached in sessionStorage against the hint state). Dropdown open/close is + * handled generically by 25-topbar-dropdown.js. + */ +;(function () { + 'use strict' + + var container = document.querySelector('[data-docs-account]') + if (!container) return + + var signinLink = container.querySelector('[data-account-signin]') + var menu = container.querySelector('[data-account-menu]') + var avatar = container.querySelector('[data-account-avatar]') + var emailEl = container.querySelector('[data-account-email]') + var signoutLink = container.querySelector('[data-account-signout]') + var modal = container.querySelector('[data-signin-modal]') + var modalCta = container.querySelector('[data-signin-modal-continue]') + + var CACHE_KEY = 'docs-account-me' + + function hasAuthHint () { + return /(?:^|;\s*)rp_docs_auth=1(?:;|$)/.test(document.cookie) + } + + function returnTo () { + return encodeURIComponent(window.location.pathname + window.location.search) + } + + // Feature modal shown before sending the user to /login + function openModal () { + if (!modal) return + modal.hidden = false + document.addEventListener('keydown', onModalKey) + } + function closeModal () { + if (!modal) return + modal.hidden = true + document.removeEventListener('keydown', onModalKey) + } + function onModalKey (e) { + if (e.key === 'Escape') closeModal() + } + if (modal) { + modal.querySelectorAll('[data-signin-modal-close]').forEach(function (el) { + el.addEventListener('click', closeModal) + }) + } + signinLink.addEventListener('click', function (e) { + if (!modal) return // no modal markup — let the link navigate to /login + e.preventDefault() + openModal() + }) + + function showUser (user) { + var email = user && user.email + if (email) { + emailEl.textContent = email + avatar.textContent = email.charAt(0).toUpperCase() + } else { + emailEl.textContent = 'Signed in' + avatar.textContent = '●' + } + } + + function render () { + var signedIn = hasAuthHint() + signinLink.hidden = signedIn + menu.hidden = !signedIn + container.hidden = false + signinLink.href = '/login?return_to=' + returnTo() + signoutLink.href = '/logout?return_to=' + returnTo() + if (modalCta) modalCta.href = '/login?return_to=' + returnTo() + + // Signed in: the console link lives in the account dropdown, so hide the + // standalone toolbar/overflow Cloud Console links (avoid two paths) + document.querySelectorAll('[data-cloud-link]').forEach(function (el) { + el.hidden = signedIn + }) + + if (!signedIn) return + + // Cached identity (revalidated when the hint state changes) + try { + var cached = JSON.parse(sessionStorage.getItem(CACHE_KEY) || 'null') + if (cached && cached.email !== undefined) { + showUser(cached) + return + } + } catch (e) { /* fall through */ } + + showUser(null) + fetch('/auth/me', { credentials: 'include' }) + .then(function (res) { return res.ok ? res.json() : null }) + .then(function (me) { + if (!me) return + showUser(me) + try { + sessionStorage.setItem(CACHE_KEY, JSON.stringify({ email: me.email || null })) + } catch (e) { /* private browsing */ } + }) + .catch(function () { /* header still shows generic signed-in state */ }) + } + + // Drop the cached identity whenever the login state flips (login/logout) + try { + var cachedState = sessionStorage.getItem(CACHE_KEY + '-hint') + var hint = String(hasAuthHint()) + if (cachedState !== hint) { + sessionStorage.removeItem(CACHE_KEY) + sessionStorage.setItem(CACHE_KEY + '-hint', hint) + } + } catch (e) { /* private browsing */ } + + render() + + // The Ask AI panel's session probe may learn the identity first — reuse it + window.addEventListener('kapa-session', function (e) { + if (e.detail && e.detail.authenticated && e.detail.user) { + showUser(e.detail.user) + try { + sessionStorage.setItem(CACHE_KEY, JSON.stringify({ email: e.detail.user.email || null })) + } catch (err) { /* private browsing */ } + } + }) +})() diff --git a/src/js/react/AskAI.jsx b/src/js/react/AskAI.jsx index 83e8dfd5..efe50b5a 100644 --- a/src/js/react/AskAI.jsx +++ b/src/js/react/AskAI.jsx @@ -1,68 +1,205 @@ -import React from 'react' +import React, { useEffect, useState } from 'react' import { createRoot } from 'react-dom/client' -import { KapaProvider } from '@kapaai/react-sdk' +import { AgentProvider } from '@kapaai/agent-react' import ChatInterface from './components/ChatInterface.jsx' -import { saveConversation } from './chatPersistence.js' -import { createPersistentApiService } from './persistentApiService.js' +import { agentTools } from './agentTools.js' +import { safeHeap } from './heap.js' -const safeHeap = (eventName, eventParams) => { - if (typeof window.heap === 'object' && typeof window.heap.track === 'function') { - window.heap.track(eventName, eventParams); +/** + * Fetches a Kapa Agent SDK session token from the docs backend + * (netlify/functions/kapa-session.mjs in docs-site). The agent tier is + * signed-in only: anonymous visitors get 401 auth_required, ChatInterface + * shows a sign-in prompt, and the Ask AI experience falls back to the stock + * Kapa widget. Session state is broadcast via the `kapa-session` window event + * and mirrored on window.__KAPA_AUTHENTICATED / window.__KAPA_USER so + * components mounting after the broadcast (and the feedback tool) can read it. + */ +function announceSession (authenticated, user, loginUrl) { + window.__KAPA_AUTHENTICATED = authenticated + window.__KAPA_USER = user || null + window.__KAPA_LOGIN_URL = loginUrl || null + window.dispatchEvent( + new CustomEvent('kapa-session', { + detail: { authenticated, user: user || null, loginUrl: loginUrl || null }, + }) + ) + try { + sessionStorage.setItem( + 'kapa-session-state', + JSON.stringify({ authenticated, user: user || null, loginUrl: loginUrl || null }) + ) + } catch (err) { /* private browsing */ } +} + +async function getSessionToken () { + const endpoint = window.KAPA_SESSION_ENDPOINT || '/kapa/session' + const res = await fetch(endpoint, { method: 'POST', credentials: 'include' }) + if (res.status === 401) { + const data = await res.json().catch(() => ({})) + announceSession(false, null, data.login_url) + throw new Error('Sign in to use the Redpanda AI agent') + } + if (!res.ok) { + throw new Error(`Chat session request failed (${res.status})`) + } + const data = await res.json() + announceSession(Boolean(data.authenticated), data.user, null) + return { token: data.session_token, expiresAt: Date.parse(data.expires_at) } +} + +// The SDK only fetches a session token on the first message, so ChatInterface +// wouldn't know whether to show the agent UI or the sign-in prompt until the +// user typed something. Probe once per browser session (cached) to learn the +// session state early. The cache is revalidated whenever the JS-readable +// rp_docs_auth hint cookie (set/cleared by the docs login flow alongside the +// HttpOnly session cookie) disagrees with it — i.e. right after login/logout. +function probeSession () { + const hasAuthHint = /(?:^|;\s*)rp_docs_auth=1(?:;|$)/.test(document.cookie) + let cached = null + try { + cached = sessionStorage.getItem('kapa-session-state') + } catch (err) { /* private browsing */ } + if (cached !== null) { + try { + const { authenticated, user, loginUrl } = JSON.parse(cached) + if (Boolean(authenticated) === hasAuthHint) { + announceSession(Boolean(authenticated), user, loginUrl) + return + } + // Login state changed since the cache was written — fall through + } catch (err) { /* fall through to a fresh probe */ } + } + getSessionToken().catch(() => {}) +} + +// Custom instructions are injected into the agent's system prompt server-side +// (never shown to users) and are, per Kapa's guidance, the single biggest +// quality lever. Structured into the three areas Kapa recommends: domain +// context, tool strategy, and preventing bad patterns. GROW THIS EMPIRICALLY — +// add a line each time the agent is observed doing the wrong thing. +const CUSTOM_INSTRUCTIONS = `## Domain context +- Answers often depend on which Redpanda deployment the user is on: + - Self-Managed — docs live under "Streaming", versioned (e.g. 25.2, 24.3). + - Redpanda Cloud — cluster types: BYOC, Dedicated, or Serverless. + - Agentic Data Plane (ADP) — runs on a cloud platform (e.g. AWS). +- Bloblang is Redpanda Connect's mapping language. The run_bloblang tool runs a + mapping against sample input using the real interpreter and returns the output + or the exact error. + +## Clarifying the user's context +- When a question is deployment-specific and the user hasn't said, first ask + just one simple question: are they on Redpanda Cloud or Self-Managed? +- Then ask a follow-up ONLY when the answer actually depends on it; otherwise + proceed with a sensible default: + - Self-Managed → assume the latest Streaming version unless the answer + differs by version, in which case ask which Streaming version (e.g. 25.2). + - Cloud → assume the general case unless the answer differs by cluster type, + in which case ask which: BYOC, Dedicated, or Serverless. +- Ask at most one follow-up. Skip all of this when they've already stated their + deployment, or when the answer is the same across deployments. +- Agentic Data Plane (ADP) is a separate product; if the question is about ADP + and the platform matters, ask which (e.g. AWS). + +## Tool strategy +- Bloblang: only use functions and methods that appear in the docs you + retrieved. ALWAYS verify a mapping with run_bloblang against sample input + before presenting it or opening the playground; if it errors, fix it and + verify again. Show the verified mapping with its sample input and output. +- Navigation / product switch: use when the user asks to go to, open, or be + shown a page or product. +- Feedback: call submit_docs_feedback only with the user's explicit consent; + summarize their feedback clearly first. + +## Do not +- Do not present a Bloblang mapping you have not verified with run_bloblang. +- Do not invent Bloblang functions or methods that are not in the docs. +- Do not answer a deployment-specific question with a generic guess when the + deployment is unknown — ask the clarifying question first. +- Never include passwords, tokens, or other personal data in a feedback summary. +- Do not repeat sources or restate numbers you have already shown.` + +function handleAgentEvent (event) { + switch (event.type) { + case 'response_completed': + safeHeap('answer_generated_docs_home', { + thread_id: event.data.threadId, + tool_call_count: event.data.toolCallCount, + }) + break + case 'response_error': + safeHeap('chat_error_docs_home', { + thread_id: event.data.threadId, + error: event.data.error, + }) + break + case 'thread_resumed': + safeHeap('thread_resumed_docs_home', { thread_id: event.data.threadId }) + break + case 'thread_deleted': + safeHeap('thread_deleted_docs_home', { thread_id: event.data.threadId }) + break + case 'tool_executed': + safeHeap('agent_tool_executed_docs_home', { + tool_name: event.data.toolName, + status: event.data.status, + duration_ms: event.data.durationMs, + }) + break + case 'tool_denied': + safeHeap('agent_tool_denied_docs_home', { tool_name: event.data.toolName }) + break + default: + break } -}; +} + +// Follow the site's theme toggle (html[data-theme]) rather than the OS +// preference, so the SDK-rendered history view matches the rest of the page. +function useSiteColorScheme () { + const read = () => + document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' + const [scheme, setScheme] = useState(read) -// Create singleton API service instance for conversation persistence -const persistentApiService = createPersistentApiService() + useEffect(() => { + const observer = new MutationObserver(() => setScheme(read())) + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ['data-theme'], + }) + return () => observer.disconnect() + }, []) + + return scheme +} -function App() { - const integrationId = window.UI_INTEGRATION_ID +function App () { + const colorScheme = useSiteColorScheme() return ( - <> - { - safeHeap("ask_question_docs_home", { - question: data.question, - thread_id: data.threadId, - }); - }, - onAnswerGenerationCompleted: (data) => { - // Save conversation state for cross-page persistence - // Save after answer is complete so we have the full exchange - if (data.threadId && data.conversation) { - saveConversation(data.threadId, data.conversation) - } - safeHeap("answer_generated_docs_home", { - question_id: data.questionAnswerId, - answer_length: data.answer.length, - }); - }, - onFeedbackSubmit: (data) => { - safeHeap("feedback_submitted_docs_home", { - question_id: data.questionAnswerId, - reaction: data.reaction, - }); - }, - }, - }} - > - - - + + + ) } -function mount() { +function mount () { // Mount to exactly one root to prevent duplicate App instances const homeEl = document.getElementById('kapa-chat-root') const panelEl = document.getElementById('chat-panel-kapa-root') const mountEl = homeEl || panelEl if (mountEl && !mountEl.dataset.mounted) { mountEl.dataset.mounted = 'true' + probeSession() createRoot(mountEl).render() } } diff --git a/src/js/react/agentTools.js b/src/js/react/agentTools.js new file mode 100644 index 00000000..95bed38b --- /dev/null +++ b/src/js/react/agentTools.js @@ -0,0 +1,359 @@ +/* globals window, document, fetch, WebAssembly */ +/** + * Client-side tools for the Kapa Agent SDK (registered on AgentProvider in + * AskAI.jsx). The agent decides when to call these; `execute` runs in the + * browser and its return value is streamed back into the conversation, so + * always return a plain object the model can narrate (include `url` fields so + * the agent can render a link when a popup is blocked). + * + * Tools that move the user (navigation, product switch) or contact the docs + * team require explicit approval — the chat UI renders approve/reject buttons + * via the SDK's ToolCallCard. + */ + +const DOCS_ORIGIN = 'https://docs.redpanda.com' + +// UTF-8-safe base64, matching the Bloblang playground's share-link encoding +function encodeBase64 (str) { + const utf8Bytes = new TextEncoder().encode(str) + let binaryStr = '' + for (let i = 0; i < utf8Bytes.length; i++) { + binaryStr += String.fromCharCode(utf8Bytes[i]) + } + return window.btoa(binaryStr) +} + +// Accept relative doc paths or absolute docs.redpanda.com URLs; reject the rest +function resolveDocsUrl (url) { + try { + const resolved = new URL(url, window.location.origin) + if (resolved.origin === window.location.origin || resolved.origin === DOCS_ORIGIN) { + return resolved.toString() + } + } catch (err) { /* fall through */ } + return null +} + +// Open in a new tab; a blocked popup returns null so callers can degrade to a link +function openTab (url) { + const win = window.open(url, '_blank', 'noopener') + return Boolean(win) +} + +// ——— Bloblang WASM (lazy) ——————————————————————————————————————————————— +// Same engine and load paths as the mini playground (16-bloblang-interactive.js): +// wasm_exec.js from the UI root, blobl.wasm from the site root (or UI root in +// the docs-ui preview). Exposes window.blobl(mapping, input[, metadata]). +let bloblWasmPromise = null + +function loadScript (src) { + return new Promise((resolve, reject) => { + const s = document.createElement('script') + s.src = src + s.onload = resolve + s.onerror = () => reject(new Error(`failed to load ${src}`)) + document.head.appendChild(s) + }) +} + +function loadBloblWasm () { + if (window.blobl) return Promise.resolve() + if (bloblWasmPromise) return bloblWasmPromise + + const rootPath = typeof window.uiRootPath !== 'undefined' ? window.uiRootPath : '/_' + const siteRoot = typeof window.siteRootPath !== 'undefined' ? window.siteRootPath : '' + const isPreview = typeof window.isUiPreview !== 'undefined' ? window.isUiPreview : false + const wasmPath = isPreview ? `${rootPath}/blobl.wasm` : `${siteRoot}/blobl.wasm` + + bloblWasmPromise = (typeof window.Go === 'undefined' + ? loadScript(`${rootPath}/js/vendor/wasm_exec.js`) + : Promise.resolve() + ) + .then(() => { + const go = new window.Go() + return fetch(wasmPath) + .then((response) => { + if (!response.ok) throw new Error(`WASM not found at ${wasmPath}`) + const clone = response.clone() + return WebAssembly.instantiateStreaming(response, go.importObject).catch(async () => { + const bytes = await clone.arrayBuffer() + return WebAssembly.instantiate(bytes, go.importObject) + }) + }) + .then((result) => { + go.run(result.instance) + }) + }) + .catch((err) => { + bloblWasmPromise = null // allow a retry + throw err + }) + return bloblWasmPromise +} + +const runBloblang = { + name: 'run_bloblang', + displayName: 'Run Bloblang mapping', + description: + 'Execute a Bloblang mapping against sample input JSON using the real Redpanda Connect interpreter, ' + + 'and return the output or the exact parse/runtime error. ' + + 'ALWAYS run a mapping through this tool before presenting it to the user or opening the playground — ' + + 'if it errors, fix the mapping and run it again until it works, then show the user the verified mapping ' + + 'together with the sample input and output.', + // Deliberately not approval-gated: pure sandboxed computation in page-local + // WASM — no network, DOM, or navigation side effects — and the agent may + // need several iterations to converge on a correct mapping. + needsApproval: false, + parameters: { + type: 'object', + properties: { + mapping: { + type: 'string', + description: 'The Bloblang mapping to execute.', + }, + input: { + type: 'string', + description: 'Sample input JSON to run the mapping against.', + }, + }, + required: ['mapping', 'input'], + }, + execute: async ({ mapping, input }) => { + try { + await loadBloblWasm() + } catch (err) { + return { error: 'wasm_unavailable', message: String(err?.message || err) } + } + let result + try { + result = window.blobl(String(mapping), String(input)) + } catch (err) { + return { valid: false, error: String(err?.message || err) } + } + if (typeof result === 'string' && result.startsWith('Error:')) { + return { valid: false, error: result } + } + return { valid: true, output: result } + }, +} + +const navigateToPage = { + name: 'navigate_to_page', + displayName: 'Open documentation page', + description: + 'Navigate the user to a Redpanda documentation page in the current tab, for example a page you just cited. ' + + 'Only use docs.redpanda.com URLs or absolute paths on the docs site. ' + + 'Use this when the user asks to go to, open, or be shown a page.', + needsApproval: true, + parameters: { + type: 'object', + properties: { + url: { + type: 'string', + description: 'The documentation page URL or absolute path (for example /current/get-started/quick-start/).', + }, + }, + required: ['url'], + }, + execute: async ({ url }) => { + const resolved = resolveDocsUrl(url) + if (!resolved) { + return { error: 'invalid_url', message: 'Only docs.redpanda.com pages can be opened.' } + } + window.location.assign(resolved) + return { navigated: true, url: resolved } + }, +} + +const switchProduct = { + name: 'switch_product', + displayName: 'Switch product', + description: + 'Switch the docs site to a different Redpanda product (for example the Data Platform or Agentic Data Plane) ' + + 'using the site product switcher. Call with the product name the user asked about. ' + + 'If the result lists available products, retry with one of those exact ids.', + needsApproval: true, + parameters: { + type: 'object', + properties: { + product: { + type: 'string', + description: 'The product to switch to, by name or id (for example "agentic-data-plane").', + }, + }, + required: ['product'], + }, + execute: async ({ product }) => { + const options = Array.from(document.querySelectorAll('[data-product-menu] [data-product-id]')).map((btn) => ({ + id: btn.getAttribute('data-product-id'), + label: btn.textContent.trim(), + url: btn.getAttribute('data-product-url'), + current: btn.classList.contains('is-current'), + })) + if (options.length === 0) { + return { error: 'unavailable', message: 'No product switcher on this page.' } + } + const wanted = String(product || '').toLowerCase() + const match = options.find( + (o) => o.id.toLowerCase() === wanted || + o.id.toLowerCase().includes(wanted) || + o.label.toLowerCase().includes(wanted) + ) + if (!match) { + return { error: 'not_found', available: options.map((o) => ({ id: o.id, label: o.label })) } + } + if (match.current) { + return { alreadyCurrent: true, product: match.id } + } + window.location.assign(match.url) + return { switched: true, product: match.id, url: match.url } + }, +} + +const openBloblangPlayground = { + name: 'open_bloblang_playground', + displayName: 'Open Bloblang playground', + description: + 'Open the interactive Bloblang playground in a new tab, preloaded with a mapping (and optionally sample input JSON) ' + + 'so the user can run and edit it. Only open mappings you have already verified with the run_bloblang tool.', + needsApproval: true, + parameters: { + type: 'object', + properties: { + mapping: { + type: 'string', + description: 'The Bloblang mapping to preload.', + }, + input: { + type: 'string', + description: 'Optional sample input JSON to preload.', + }, + }, + required: ['mapping'], + }, + execute: async ({ mapping, input }) => { + const base = window.BLOBLANG_PLAYGROUND_URL || `${DOCS_ORIGIN}/connect/guides/bloblang/playground/` + const url = new URL(base) + url.searchParams.set('map', encodeBase64(mapping)) + if (input) url.searchParams.set('input', encodeBase64(input)) + const opened = openTab(url.toString()) + return { + opened, + url: url.toString(), + note: opened ? 'Playground opened in a new tab.' : 'Popup blocked — give the user this link instead.', + } + }, +} + +const submitDocsFeedback = { + name: 'submit_docs_feedback', + displayName: 'Send feedback to the docs team', + description: + 'Send user feedback (bug reports, documentation gaps, incorrect or missing information, feature requests) ' + + 'to the Redpanda docs team. Ask the user before calling this and summarize their feedback clearly — ' + + 'never include passwords, tokens, or other personal data in the summary. ' + + 'The submission includes the signed-in user\'s email and a reference to this conversation so the team can ' + + 'follow up; mention that to the user when asking for consent. Never submit without their consent.', + needsApproval: true, + parameters: { + type: 'object', + properties: { + feedback: { + type: 'string', + description: 'The feedback to submit, in clear prose. Summarize the bug, gap, or request.', + }, + category: { + type: 'string', + enum: ['bug', 'documentation_gap', 'feature_request', 'other'], + description: 'The type of feedback.', + }, + page_url: { + type: 'string', + description: 'The documentation page the feedback is about. Ask the user if it is not clear from context.', + }, + }, + required: ['feedback', 'category', 'page_url'], + }, + execute: async ({ feedback, category, page_url: pageUrl }) => { + const text = String(feedback || '').trim().slice(0, 5000) + if (!text) return { error: 'missing_feedback' } + // Same Netlify form the docs MCP server uses (see docs-site mcp.mjs); + // /home/ serves without redirecting, which Netlify forms require. + // Same-origin so it also works on deploy previews and Bump.sh pages. + // Referer and User-Agent are added by the browser automatically. + // The signed-in user's email (from the session endpoint) and the thread ID + // give the docs team a contact and conversation context without copying + // the conversation text (which may contain pasted configs or PII) into + // the form. + const user = window.__KAPA_USER || {} + // On a first-turn tool call the SDK may not have committed the thread ID + // to state yet — wait briefly rather than submit without the reference + let threadId = window.__KAPA_THREAD_ID + for (let i = 0; !threadId && i < 20; i++) { + await new Promise((resolve) => setTimeout(resolve, 100)) + threadId = window.__KAPA_THREAD_ID + } + const body = new URLSearchParams({ + 'form-name': 'api-feedback', + feedback: text, + category: category || 'other', + 'page-path': pageUrl || window.location.href, + 'user-email': user.email || '', + 'user-domain': user.domain || '', + source: 'ask-ai-widget', + 'thread-id': threadId || '', + 'bot-field': '', + }) + const res = await fetch('/home/', { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: body.toString(), + redirect: 'error', + }) + if (!res.ok) { + return { error: 'submission_failed', status: res.status } + } + return { submitted: true } + }, +} + +const askCommunity = { + name: 'ask_community', + displayName: 'Ask the Redpanda community', + description: + 'Open the Redpanda community Slack in a new tab so the user can ask other engineers. ' + + 'Use when a question needs human help, opinions, or is beyond the documentation. ' + + 'Pass a suggested message the user could post.', + needsApproval: true, + parameters: { + type: 'object', + properties: { + suggested_message: { + type: 'string', + description: 'A short message the user could post in the community Slack.', + }, + }, + required: [], + }, + execute: async ({ suggested_message: suggestedMessage }) => { + const url = 'https://redpanda.com/slack' + const opened = openTab(url) + return { + opened, + url, + suggestedMessage: suggestedMessage || null, + note: opened + ? 'Slack invite opened in a new tab. Show the user the suggested message to post.' + : 'Popup blocked — give the user the link and the suggested message.', + } + }, +} + +export const agentTools = [ + navigateToPage, + switchProduct, + runBloblang, + openBloblangPlayground, + submitDocsFeedback, + askCommunity, +] diff --git a/src/js/react/chatPersistence.js b/src/js/react/chatPersistence.js deleted file mode 100644 index 7898010d..00000000 --- a/src/js/react/chatPersistence.js +++ /dev/null @@ -1,78 +0,0 @@ -/* globals localStorage */ -/** - * Chat Persistence Module - * Saves and restores conversation state to localStorage for cross-page continuity - */ - -const STORAGE_KEY = 'redpanda-chat-thread' -const EXPIRY_MS = 24 * 60 * 60 * 1000 // 24 hours - -/** - * Save conversation state to localStorage - * @param {string} threadId - The Kapa thread ID - * @param {Array} conversation - Array of {id, question, answer} objects - */ -export function saveConversation (threadId, conversation) { - if (!threadId || !conversation) return - - try { - localStorage.setItem( - STORAGE_KEY, - JSON.stringify({ - threadId, - conversation: conversation.map((qa) => ({ - id: qa.id || qa.questionAnswerId, - question: qa.question, - answer: qa.answer, - })), - timestamp: Date.now(), - }) - ) - } catch (err) { - console.warn('Failed to save chat conversation:', err) - } -} - -/** - * Load saved conversation from localStorage - * @returns {Object|null} - {threadId, conversation, timestamp} or null if not found/expired - */ -export function loadConversation () { - try { - const data = localStorage.getItem(STORAGE_KEY) - if (!data) return null - - const parsed = JSON.parse(data) - - // Check expiry - if (Date.now() - parsed.timestamp > EXPIRY_MS) { - clearConversation() - return null - } - - return parsed - } catch (err) { - console.warn('Failed to load chat conversation:', err) - return null - } -} - -/** - * Clear saved conversation from localStorage - */ -export function clearConversation () { - try { - localStorage.removeItem(STORAGE_KEY) - } catch (err) { - console.warn('Failed to clear chat conversation:', err) - } -} - -/** - * Get saved thread ID if available and not expired - * @returns {string|null} - The saved thread ID or null - */ -export function getSavedThreadId () { - const data = loadConversation() - return data?.threadId || null -} diff --git a/src/js/react/components/ChatInterface.jsx b/src/js/react/components/ChatInterface.jsx index acfd5d85..d8c59e0d 100644 --- a/src/js/react/components/ChatInterface.jsx +++ b/src/js/react/components/ChatInterface.jsx @@ -1,23 +1,29 @@ import React, { useState, useEffect, useRef, Component } from 'react' -import { useChat, useDeepThinking } from '@kapaai/react-sdk' +import { useAgentChat, AgentThreadHistory, ToolCallCard, ToolCallGroup } from '@kapaai/agent-react' import { ArrowRight, ArrowDown, - ThumbsUp, - ThumbsDown, RefreshCcw, ClipboardCopy, CircleStop, - FileSearch, + History, Check, AlertCircle, Sparkles, + X, } from 'lucide-react' import DOMPurify from 'dompurify' import { Marked } from 'marked' import { markedHighlight } from 'marked-highlight' import hljs from 'highlight.js' -import { loadConversation, clearConversation } from '../chatPersistence.js' +import { safeHeap } from '../heap.js' +import { agentTools } from '../agentTools.js' + +// Resumed threads come back without displayName on tool calls (the SDK only +// backfills icon/render), so map names to friendly labels ourselves +const TOOL_DISPLAY_NAMES = Object.fromEntries( + agentTools.map((t) => [t.name, t.displayName]) +) // ——— ErrorBoundary —————————————————————————————————————————————————— class ErrorBoundary extends Component { @@ -101,49 +107,105 @@ function Answer({ md }) { return
} -// ——— FeedbackButtons ————————————————————————————————————————————————————— -function FeedbackButtons({ questionAnswerId, showToast }) { - const { addFeedback } = useChat() - - const handleFeedback = async (reaction) => { - try { - await addFeedback(questionAnswerId, reaction) - showToast( - reaction === 'upvote' - ? 'Thanks for the feedback!' - : 'Feedback received', - 'success' - ) - } catch (err) { - console.error('Feedback error', err) - showToast('Could not send feedback', 'error') +// ——— Sources ———————————————————————————————————————————————————————————— +// Assistant messages carry sources inside tool-call blocks; collect and +// dedupe them by URL for a compact link list under the answer. +function extractSources(blocks) { + const seen = new Set() + const sources = [] + for (const block of blocks || []) { + if (block.type !== 'tool_calls') continue + for (const call of block.toolCalls || []) { + for (const source of call.sources || []) { + if (!source?.sourceUrl || seen.has(source.sourceUrl)) continue + // Only render web URLs — React doesn't block javascript: hrefs + if (!/^https?:\/\//i.test(source.sourceUrl)) continue + seen.add(source.sourceUrl) + sources.push(source) + } } } + return sources +} + +// Kapa titles can arrive pipe-joined ("Page title|Page title") or empty +function baseTitle(source) { + const title = (source.title || '').split('|').map((p) => p.trim()).filter(Boolean)[0] + if (title) return title + try { + const segs = new URL(source.sourceUrl).pathname.split('/').filter(Boolean) + const last = segs[segs.length - 1] || '' + return humanize(last) || source.sourceUrl + } catch { + return source.sourceUrl + } +} + +function humanize(slug) { + return decodeURIComponent(slug).replace(/[-_]+/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()).trim() +} + +// Friendly names for the docs product/section path segments +const PRODUCT_LABELS = { + 'redpanda-cloud': 'Cloud', + 'cloud-data-platform': 'Cloud', + 'self-managed': 'Self-Managed', + 'data-platform': 'Data Platform', + streaming: 'Streaming', + connect: 'Connect', + 'redpanda-connect': 'Connect', +} +// A short qualifier to disambiguate same-titled sources: the section (for +// same-page anchors) or the product/version (for the same page across versions). +function sourceQualifier(url) { + try { + const u = new URL(url) + if (u.hash && u.hash.length > 1) return humanize(u.hash.slice(1)) + const segs = u.pathname.split('/').filter(Boolean) + const version = segs.find((s) => /^\d+\.\d+$/.test(s) || s === 'current') + const product = PRODUCT_LABELS[segs[0]] + const ver = version === 'current' ? 'latest' : version + if (product && ver) return `${product} ${ver}` + return ver || product || '' + } catch { + return '' + } +} + +function AnswerSources({ blocks }) { + const sources = extractSources(blocks) + if (sources.length === 0) return null + // Only qualify titles that repeat, so unique sources stay clean + const titles = sources.map(baseTitle) + const counts = titles.reduce((acc, t) => ({ ...acc, [t]: (acc[t] || 0) + 1 }), {}) return ( -
-
- - -
+
+ Sources +
) } +// Grow the input with its content, capped by the CSS max-height +function autosizeTextarea(el) { + if (!el) return + el.style.height = 'auto' + el.style.height = `${el.scrollHeight}px` +} + // ——— ActionButtons ——————————————————————————————————————————————————————— function ActionButtons({ onReset, onCopy, showToast }) { const safeCopy = async () => { @@ -169,20 +231,26 @@ function ActionButtons({ onReset, onCopy, showToast }) { } /** - * Renders the main chat interface, providing a conversational UI with markdown-rendered answers, feedback and copy/reset actions, animated loading states, and responsive suggestion chips. + * Renders the main chat interface, providing a conversational UI with markdown-rendered answers, copy/reset actions, animated loading states, and responsive suggestion chips. * - * Manages user input, conversation state, and UI responsiveness for both desktop and mobile. Handles dynamic textarea resizing, scroll-to-bottom behavior, and conditional display of header/footer elements based on user interaction. Integrates with the chat backend via the `useChat` hook to submit queries, stop or reset conversations, and display AI-generated suggestions. Also manages inline toast notifications for copy and feedback actions. + * Manages user input, conversation state, and UI responsiveness for both desktop and mobile. Handles dynamic textarea resizing, scroll-to-bottom behavior, and conditional display of header/footer elements based on user interaction. Integrates with the chat backend via the `useAgentChat` hook to submit queries, stop or reset conversations, and display AI-generated suggestions. Signed-in users (detected via the `kapa-session` event from AskAI.jsx) also get a conversation-history view backed by the Kapa Agent SDK. */ export default function ChatInterface() { const [message, setMessage] = useState('') const [dots, setDots] = useState('') const [showScrollDown, setShowScrollDown] = useState(false) - const [stoppedIds, setStoppedIds] = useState(new Set()) const [suggestions, setSuggestions] = useState([]) const [hasInteracted, setHasInteracted] = useState(false) const [toast, setToast] = useState(null) - const [restoredConversation, setRestoredConversation] = useState(null) + // null = session state unknown (probe in flight), false = anonymous, true = signed in + const [authenticated, setAuthenticated] = useState(() => + window.__KAPA_AUTHENTICATED === undefined ? null : Boolean(window.__KAPA_AUTHENTICATED) + ) + // Where "Sign in" goes — supplied by the session endpoint once docs login exists + const [loginUrl, setLoginUrl] = useState(() => window.__KAPA_LOGIN_URL || null) + const [showHistory, setShowHistory] = useState(false) const textareaRef = useRef(null) + const conversationAreaRef = useRef(null) const showToast = (message, type = 'success') => { setToast({ message, type }) @@ -219,13 +287,15 @@ export default function ChatInterface() { } }, []); - // Restore conversation from localStorage on mount (cross-page persistence) + // The session endpoint reports whether the visitor is signed in; the flag + // gates the whole agent UI (AskAI.jsx broadcasts it after every token fetch). useEffect(() => { - const saved = loadConversation() - if (saved?.conversation?.length > 0) { - setRestoredConversation(saved.conversation) - setHasInteracted(true) + const handleSession = (e) => { + setAuthenticated(Boolean(e.detail?.authenticated)) + setLoginUrl(e.detail?.loginUrl || null) } + window.addEventListener('kapa-session', handleSession) + return () => window.removeEventListener('kapa-session', handleSession) }, []) // Update isMobile on resize. Close dropdown if switching breakpoints. @@ -244,33 +314,43 @@ export default function ChatInterface() { }, []) const { - conversation, - submitQuery, - isGeneratingAnswer, + messages, + threadId, + isStreaming, + sendMessage, stopGeneration, resetConversation, - isPreparingAnswer, - } = useChat() + approveToolCall, + rejectToolCall, + historyDisabled, + } = useAgentChat() - const deepThinking = useDeepThinking() + // Expose the live thread ID so the feedback tool can reference the + // conversation without pasting its contents into the form + useEffect(() => { + window.__KAPA_THREAD_ID = threadId + return () => { + delete window.__KAPA_THREAD_ID + } + }, [threadId]) - // Merge restored conversation with live conversation for display - // Show restored conversation when live is empty, otherwise show live - // (live conversation will include new queries that continue the thread) - const displayConversation = restoredConversation && conversation.length === 0 - ? restoredConversation - : conversation + // A resumed or in-flight conversation should show the conversation view + useEffect(() => { + if (messages.length > 0 && !hasInteracted) setHasInteracted(true) + }, [messages.length, hasInteracted]) - const latestQA = conversation.length > 0 ? conversation.getLatest() : null + const lastMessage = messages[messages.length - 1] + // Waiting for the first assistant tokens of the current turn + const isPreparing = isStreaming && (!lastMessage || lastMessage.role === 'user') // Show/hide "scroll down" button useEffect(() => { - if (!hasInteracted || isPreparingAnswer) return + if (!hasInteracted || isPreparing) return const THRESHOLD = 300 - // Check if we're in chat panel drawer - const chatScroll = document.querySelector('.chat-scroll') - const isInPanel = chatScroll && chatScroll.contains(document.getElementById('chat-panel-kapa-root')) + // In the panel the conversation area scrolls; on the home page the window does + const chatScroll = conversationAreaRef.current + const isInPanel = Boolean(document.getElementById('chat-panel-kapa-root')) && chatScroll const handleScroll = () => { let scrollTop, innerH, scrollH @@ -305,12 +385,12 @@ export default function ChatInterface() { scrollTarget.removeEventListener('scroll', handleScroll) window.removeEventListener('resize', handleScroll) } - }, [hasInteracted, isPreparingAnswer, isGeneratingAnswer]) + }, [hasInteracted, isPreparing, isStreaming]) const scrollToBottom = () => { - // Check if we're in the chat panel drawer - const chatScroll = document.querySelector('.chat-scroll') - if (chatScroll && chatScroll.contains(document.getElementById('chat-panel-kapa-root'))) { + // In the panel the conversation area scrolls; on the home page the window does + const chatScroll = conversationAreaRef.current + if (chatScroll && document.getElementById('chat-panel-kapa-root')) { // Scroll within the chat panel chatScroll.scrollTo({ top: chatScroll.scrollHeight, @@ -328,7 +408,7 @@ export default function ChatInterface() { // “Preparing answer…” dots animation useEffect(() => { let timer - if (isPreparingAnswer) { + if (isPreparing) { timer = setInterval(() => { setDots((d) => (d.length < 3 ? d + '.' : '')) }, 500) @@ -336,7 +416,7 @@ export default function ChatInterface() { setDots('') } return () => clearInterval(timer) - }, [isPreparingAnswer]) + }, [isPreparing]) // Hide header/footer until user interacts useEffect(() => { @@ -359,10 +439,29 @@ export default function ChatInterface() { } }, [hasInteracted]) + // Hand anonymous visitors to the stock Kapa widget (chat-SDK tier) + const openQuickAsk = () => { + if (typeof window.loadKapa !== 'function') { + showToast('Quick ask is unavailable on this page', 'error') + return + } + document.querySelector('[data-chat-action="close"]')?.click() + window.loadKapa(true) + } + const doQuery = (q) => { + if (authenticated !== true) return if (!q.trim()) return if (!hasInteracted) setHasInteracted(true) - submitQuery(q) + setShowHistory(false) + safeHeap('ask_question_docs_home', { + question: q, + thread_id: threadId, + }) + sendMessage(q).catch((err) => { + console.error('Chat error:', err) + showToast('Chat is temporarily unavailable. Try again shortly.', 'error') + }) setMessage('') setDropdownOpen(false) // close dropdown when you tap anything } @@ -384,7 +483,7 @@ export default function ChatInterface() { return () => { delete window.submitChatQuery } - }, [submitQuery, hasInteracted]) + }, [sendMessage, hasInteracted, threadId, authenticated]) const handleSubmit = (e) => { e.preventDefault() @@ -393,13 +492,11 @@ export default function ChatInterface() { } const handleReset = () => { - clearConversation() // Clear localStorage persistence resetConversation() setMessage('') - setStoppedIds(new Set()) - setRestoredConversation(null) setHasInteracted(false) setShowScrollDown(false) + setShowHistory(false) window.scrollTo({ top: 0, behavior: 'smooth' }) setDropdownOpen(false) resetTextareaHeight() @@ -408,8 +505,8 @@ export default function ChatInterface() { const handleCopy = async () => { try { await navigator.clipboard.writeText( - displayConversation - .map((q) => `Question: ${q.question}\nAnswer: ${q.answer}`) + messages + .map((m) => `${m.role === 'user' ? 'Question' : 'Answer'}: ${m.content}`) .join('\n---\n') ) } catch { @@ -417,13 +514,13 @@ export default function ChatInterface() { } } - const handleStop = () => { - stopGeneration() - const idx = conversation.length - 1 - const lastKey = conversation[idx]?.id ?? `temp-${idx}` - setStoppedIds((s) => new Set(s).add(lastKey)) + const handleThreadSelected = () => { + setShowHistory(false) + setHasInteracted(true) } + const showHistoryButton = authenticated && !historyDisabled + // ——— RENDERING FUNCTIONS ———————————————————————————————————————————————— const renderDesktopChips = () => { @@ -522,8 +619,70 @@ export default function ChatInterface() { /> )} + {/* Conversation history (signed-in users only) */} + {showHistoryButton && ( +
+ +
+ )} + {showHistory && ( +
+ +
+ )} + + {/* Sign-in prompt — the agent tier is for signed-in users; quick + questions go to the stock Kapa widget instead */} + {authenticated === false && ( +
+
+ +
+

Sign in to Redpanda docs

+

+ Free with your Redpanda Cloud account. Unlock the AI agent that can: +

+
    +
  • Save and revisit your conversations across devices
  • +
  • Search the docs and open the right page for you
  • +
  • Write and verify Bloblang mappings before you run them
  • +
  • Send feedback straight to the docs team
  • +
+ {loginUrl ? ( + <> + + Sign in + + + + ) : ( + <> +

+ Docs sign-in is coming soon. Until then: +

+ + + )} +
+ )} + {/* Welcome screen - shown before interaction */} - {!hasInteracted && ( + {authenticated === true && !hasInteracted && !showHistory && (
@@ -550,52 +709,64 @@ export default function ChatInterface() { )}
- {displayConversation.map((qa, idx) => { - const key = qa.id ?? `temp-${idx}` - const wasStopped = stoppedIds.has(key) - // For restored conversations, show action buttons on the last item - const isLast = idx === displayConversation.length - 1 - // Feedback only available for live conversation items (not restored) - const canFeedback = conversation.length > 0 && latestQA?.id === qa.id + {messages.map((m, idx) => { + const isLast = idx === messages.length - 1 + if (m.role === 'user') { + return ( +
+
+
{m.content}
+
+ ) + } + const toolCallBlocks = (m.blocks || []).filter((b) => b.type === 'tool_calls') return ( -
-
-
{qa.question}
- - {isLast && !isPreparingAnswer && !isGeneratingAnswer && ( +
+ {toolCallBlocks.map((block, bi) => ( +
+ + {block.toolCalls.map((tc) => ( + + ))} + +
+ ))} + + + {isLast && !isStreaming && (
- {!wasStopped && canFeedback && ( - - )}
)}
) })} - {isPreparingAnswer && ( + {isPreparing && (
- {deepThinking.active - ? `Running deep thinking mode up to a minute. ${deepThinking.seconds}s…` - : `Preparing answer${dots}` - } + {`Preparing answer${dots}`}
)}
-
+
{/* Optional Scroll Down Button */} {showScrollDown && (
+
+
+ {{!-- Agent SDK styles emitted by esbuild alongside the JS bundle --}} + {{!-- Footer disclaimer - Kapa SDK provides privacy policy and kapa.ai attribution --}} diff --git a/src/partials/head-scripts.hbs b/src/partials/head-scripts.hbs index be5f81f3..91a4dde6 100644 --- a/src/partials/head-scripts.hbs +++ b/src/partials/head-scripts.hbs @@ -225,7 +225,8 @@ j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= {{/if}} -{{#if (ne page.attributes.role 'home')}} +{{!-- Loaded on every page (including role=home): the signed-in-only agent + panel hands anonymous visitors to this stock widget via loadKapa() --}} -{{/if}} {{#if (and (ne page.attributes.role 'bloblang-playground') (ne isStandaloneWidget 'true'))}}
+ + {{!-- Docs account (sign in / user menu) — conventionally the LAST header + item (top-right corner). Stays visible at all breakpoints (never + folds into the overflow menu). State driven by 26-docs-account.js --}} +
From 51c5a2147816fd21b9340566b060604ded61a008 Mon Sep 17 00:00:00 2001 From: JakeSCahill Date: Tue, 7 Jul 2026 10:04:22 +0100 Subject: [PATCH 02/10] Pass signed-in user's email to Kapa for dashboard attribution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kapa is an approved processor for this PII, so set AgentProvider `user={email}` (from the session probe) — conversations are attributed to the person in Kapa's dashboard. external_owner_id stays the salted-sub hash; the SDK reads `user` reactively so setting it after the probe resolves is fine. Co-Authored-By: Claude Opus 4.8 --- src/js/react/AskAI.jsx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/js/react/AskAI.jsx b/src/js/react/AskAI.jsx index efe50b5a..7e22805a 100644 --- a/src/js/react/AskAI.jsx +++ b/src/js/react/AskAI.jsx @@ -172,8 +172,23 @@ function useSiteColorScheme () { return scheme } +// The signed-in user's verified email, learned once the session probe resolves. +// Passed to AgentProvider so Kapa attributes conversations to the user in its +// dashboard (Kapa is an approved processor for this). The SDK reads `user` +// reactively via updateOptions, so setting it after mount is fine. +function useKapaUser () { + const [user, setUser] = useState(() => window.__KAPA_USER || null) + useEffect(() => { + const handle = (e) => setUser(e.detail?.user || null) + window.addEventListener('kapa-session', handle) + return () => window.removeEventListener('kapa-session', handle) + }, []) + return user +} + function App () { const colorScheme = useSiteColorScheme() + const kapaUser = useKapaUser() return ( Date: Tue, 7 Jul 2026 10:40:45 +0100 Subject: [PATCH 03/10] Anonymous tier: our drawer via Chat SDK (not the stock widget) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Logged-out users now get the same drawer UI powered by the Chat SDK (@kapaai/react-sdk) instead of being routed to the stock Kapa widget. Signed-in users keep the Agent SDK (tools, history, email attribution). - AskAI.jsx App() picks the provider by session tier: agent (true), Chat SDK (false), brief loading (null). Probe now falls to the anonymous tier on any non-authenticated outcome (401, missing backend, network error) so the drawer never hangs. - ChatSdkInterface.jsx — anonymous drawer on useChat: welcome, chips, QA rendering, textarea input, Heap analytics, a slim sign-in upsell banner. No session backend needed (Chat SDK uses its own bot protection). - chatShared.jsx — extracted marked/Answer/Toast so both tiers render identically; ChatInterface imports them. - KAPA_CHAT_INTEGRATION_ID global (partials) for the Chat SDK integration. - Bundle +~72KB gzipped (both SDKs) — expected cost of the two-tier UX. Co-Authored-By: Claude Opus 4.8 --- package-lock.json | 93 +++++++- package.json | 3 +- src/css/chat-panel-bump.css | 53 +++++ src/css/chat-panel.css | 53 +++++ src/js/react/AskAI.jsx | 85 +++++-- src/js/react/components/ChatInterface.jsx | 65 +----- src/js/react/components/ChatSdkInterface.jsx | 229 +++++++++++++++++++ src/js/react/components/chatShared.jsx | 55 +++++ src/partials/chat-panel-bump.hbs | 2 + src/partials/chat-panel.hbs | 2 + 10 files changed, 548 insertions(+), 92 deletions(-) create mode 100644 src/js/react/components/ChatSdkInterface.jsx create mode 100644 src/js/react/components/chatShared.jsx diff --git a/package-lock.json b/package-lock.json index b41729c0..ccedcf86 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,8 @@ "name": "@redpanda-data/docs-ui", "license": "MPL-2.0", "dependencies": { - "@kapaai/agent-react": "^1.0.0" + "@kapaai/agent-react": "^1.0.0", + "@kapaai/react-sdk": "^0.9.10" }, "devDependencies": { "@algolia/autocomplete-plugin-tags": "^1.12.2", @@ -2504,6 +2505,33 @@ "node": ">=18" } }, + "node_modules/@fingerprintjs/fingerprintjs-pro": { + "version": "3.12.11", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.12.11.tgz", + "integrity": "sha512-2SbZf77yG6HxY6QDCMdk+gVKjkgHAglaS+3uTIrc+9nYMvsCgz/4DGZhtdDPpirJCmzxr1rxqiagbsQhlvYV+g==", + "license": "SEE LICENSE IN LICENSE" + }, + "node_modules/@fingerprintjs/fingerprintjs-pro-react": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-react/-/fingerprintjs-pro-react-2.7.1.tgz", + "integrity": "sha512-/vQtjd+P8C9OFU8Wvd4AScoNRP6RKDIvYQwwaY/b31PcRBNDqVV9xm7DDBg9uTdDv4KZM3ubEY4JyyVWkXs4EA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.3", + "fast-deep-equal": "3.1.3" + } + }, + "node_modules/@fingerprintjs/fingerprintjs-pro-spa": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro-spa/-/fingerprintjs-pro-spa-1.3.3.tgz", + "integrity": "sha512-jM5k30S9RT/WW6gnmNWACc7UHeK1md9NbZg8kUsdxvPtDeW8xKnA6tb58Rqfkg6kvqHTq5aHFzw9hgsTH3DbNQ==", + "license": "MIT", + "dependencies": { + "@fingerprintjs/fingerprintjs-pro": "^3.12.0", + "tslib": "^2.7.0" + } + }, "node_modules/@fontsource/roboto": { "version": "4.5.8", "resolved": "https://registry.npmjs.org/@fontsource/roboto/-/roboto-4.5.8.tgz", @@ -2596,6 +2624,26 @@ "node": ">=0.10.0" } }, + "node_modules/@hcaptcha/loader": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.3.0.tgz", + "integrity": "sha512-i4lnNxKBe+COf3R1nFZEWaZoHIoJjvDgWqvcNrdZq8ehoSNMN6KVZ56dcQ02qKie2h3+BkbkwlJA9DOIuLlK/g==", + "license": "MIT" + }, + "node_modules/@hcaptcha/react-hcaptcha": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/@hcaptcha/react-hcaptcha/-/react-hcaptcha-1.17.4.tgz", + "integrity": "sha512-rIvgesG1N7SS9sAYYHFoWm+nXqRrxq7RcA9z2pKkDWV+S1GdfmrTNYA1aPyVWVe3eowphTCwyDJvl97Swwy0mw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.17.9", + "@hcaptcha/loader": "^2.3.0" + }, + "peerDependencies": { + "react": ">= 16.3.0", + "react-dom": ">= 16.3.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -2687,6 +2735,23 @@ } } }, + "node_modules/@kapaai/react-sdk": { + "version": "0.9.10", + "resolved": "https://registry.npmjs.org/@kapaai/react-sdk/-/react-sdk-0.9.10.tgz", + "integrity": "sha512-osQyFgBJmhNM207MpB0aZbjs2kjNHjEJbNc5YEReJuyFE72Iydn9CoZGxox2GYRgMIlQ7wljHCzgQqkvR8lXqA==", + "license": "MIT", + "dependencies": { + "@fingerprintjs/fingerprintjs-pro-react": "^2.7.0", + "@fingerprintjs/fingerprintjs-pro-spa": "^1.3.0", + "@hcaptcha/react-hcaptcha": "^1.12.0", + "js-cookie": "^3.0.5", + "tldts": "^7.0.7" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -9023,7 +9088,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, "license": "MIT" }, "node_modules/fast-fifo": { @@ -12706,6 +12770,12 @@ "node": ">=6" } }, + "node_modules/js-cookie": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.8.tgz", + "integrity": "sha512-yeJd4aNAdYZQjaon2bpD/Gb0B/omw7HQOsynXXcOiWVCacbBcPlgn8S/d1X6blFSaHao7ozqtW7NZW19xpCtIw==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -22715,6 +22785,24 @@ "tlds": "bin.js" } }, + "node_modules/tldts": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.7.tgz", + "integrity": "sha512-56L0/9HELHSsG1bFCzay8UoLxzRL7kpFf7Wl5q/kSYwiSJGACvro61xnKzPNM+SadxllzdtXsKDSXE7HPeqIAw==", + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.7" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.7.tgz", + "integrity": "sha512-rNlAI8fKn/JckBMUSbNL/ES2kmDiurWaE49l+ikwEc9A6lFR7gMx9AhgQMQKBK4H5w4pKLH64JzZfB99uRsGNQ==", + "license": "MIT" + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -23022,7 +23110,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/tty-browserify": { diff --git a/package.json b/package.json index b31ea4b9..6ba76ab7 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "serve:playground": "npx serve ." }, "dependencies": { - "@kapaai/agent-react": "^1.0.0" + "@kapaai/agent-react": "^1.0.0", + "@kapaai/react-sdk": "^0.9.10" } } diff --git a/src/css/chat-panel-bump.css b/src/css/chat-panel-bump.css index 9247b7b9..7569f683 100644 --- a/src/css/chat-panel-bump.css +++ b/src/css/chat-panel-bump.css @@ -1366,3 +1366,56 @@ html[data-theme="dark"] #chat-panel-kapa-root .chat-history-toggle:hover { border-color: rgba(255, 255, 255, 0.4); background: var(--kapa-surface-hover, #2d3a53); } + +/* ——— Anonymous-tier upsell banner ——— */ +#chat-panel-kapa-root .chat-upsell { + display: flex; + align-items: center; + gap: 8px; + margin: 12px 18px 0; + padding: 9px 12px; + border-radius: 8px; + background: var(--kapa-surface-elevated, #f5f5f5); + border: 1px solid var(--kapa-border, #e5e5e5); + color: var(--kapa-text, #181818); + font-size: calc(13 / var(--rem-base) * 1rem); + font-weight: 500; + text-decoration: none; + transition: border-color 0.12s ease, background 0.12s ease; +} + +#chat-panel-kapa-root .chat-upsell:hover { + border-color: var(--kapa-accent, #444ce7); + text-decoration: none; +} + +#chat-panel-kapa-root .chat-upsell svg:first-child { + color: var(--kapa-accent, #444ce7); + flex-shrink: 0; +} + +#chat-panel-kapa-root .chat-upsell span { + flex: 1; + min-width: 0; +} + +#chat-panel-kapa-root .chat-upsell svg:last-child { + flex-shrink: 0; + opacity: 0.6; +} + +/* ——— Tier probe loading dot ——— */ +#chat-panel-kapa-root .chat-tier-loading { + width: 22px; + height: 22px; + border: 2px solid var(--kapa-border, #e5e5e5); + border-top-color: var(--kapa-accent, #444ce7); + border-radius: 50%; + animation: chat-tier-spin 0.7s linear infinite; +} + +@keyframes chat-tier-spin { to { transform: rotate(360deg); } } + +@media (prefers-reduced-motion: reduce) { + #chat-panel-kapa-root .chat-tier-loading { animation: none; } +} diff --git a/src/css/chat-panel.css b/src/css/chat-panel.css index 3dbdae66..fa81d2c1 100644 --- a/src/css/chat-panel.css +++ b/src/css/chat-panel.css @@ -1205,3 +1205,56 @@ border-color: rgba(255, 255, 255, 0.4); background: var(--kapa-surface-hover, #2d3a53); } + +/* ——— Anonymous-tier upsell banner ——— */ +#chat-panel-kapa-root .chat-upsell { + display: flex; + align-items: center; + gap: 8px; + margin: 12px 18px 0; + padding: 9px 12px; + border-radius: 8px; + background: var(--kapa-surface-elevated, #f5f5f5); + border: 1px solid var(--kapa-border, #e5e5e5); + color: var(--kapa-text, #181818); + font-size: calc(13 / var(--rem-base) * 1rem); + font-weight: 500; + text-decoration: none; + transition: border-color 0.12s ease, background 0.12s ease; +} + +#chat-panel-kapa-root .chat-upsell:hover { + border-color: var(--kapa-accent, #444ce7); + text-decoration: none; +} + +#chat-panel-kapa-root .chat-upsell svg:first-child { + color: var(--kapa-accent, #444ce7); + flex-shrink: 0; +} + +#chat-panel-kapa-root .chat-upsell span { + flex: 1; + min-width: 0; +} + +#chat-panel-kapa-root .chat-upsell svg:last-child { + flex-shrink: 0; + opacity: 0.6; +} + +/* ——— Tier probe loading dot ——— */ +#chat-panel-kapa-root .chat-tier-loading { + width: 22px; + height: 22px; + border: 2px solid var(--kapa-border, #e5e5e5); + border-top-color: var(--kapa-accent, #444ce7); + border-radius: 50%; + animation: chat-tier-spin 0.7s linear infinite; +} + +@keyframes chat-tier-spin { to { transform: rotate(360deg); } } + +@media (prefers-reduced-motion: reduce) { + #chat-panel-kapa-root .chat-tier-loading { animation: none; } +} diff --git a/src/js/react/AskAI.jsx b/src/js/react/AskAI.jsx index 7e22805a..221fdf80 100644 --- a/src/js/react/AskAI.jsx +++ b/src/js/react/AskAI.jsx @@ -1,7 +1,9 @@ import React, { useEffect, useState } from 'react' import { createRoot } from 'react-dom/client' import { AgentProvider } from '@kapaai/agent-react' +import { KapaProvider } from '@kapaai/react-sdk' import ChatInterface from './components/ChatInterface.jsx' +import ChatSdkInterface from './components/ChatSdkInterface.jsx' import { agentTools } from './agentTools.js' import { safeHeap } from './heap.js' @@ -69,7 +71,13 @@ function probeSession () { // Login state changed since the cache was written — fall through } catch (err) { /* fall through to a fresh probe */ } } - getSessionToken().catch(() => {}) + // Establish the tier. getSessionToken announces true (200) or false (clean + // 401). Any other failure — missing backend, network error, 5xx — should + // still land the user on the anonymous Chat SDK tier rather than hang the + // drawer on the loading state. + getSessionToken().catch(() => { + if (window.__KAPA_AUTHENTICATED === undefined) announceSession(false, null, null) + }) } // Custom instructions are injected into the agent's system prompt server-side @@ -172,39 +180,68 @@ function useSiteColorScheme () { return scheme } -// The signed-in user's verified email, learned once the session probe resolves. -// Passed to AgentProvider so Kapa attributes conversations to the user in its -// dashboard (Kapa is an approved processor for this). The SDK reads `user` -// reactively via updateOptions, so setting it after mount is fine. -function useKapaUser () { - const [user, setUser] = useState(() => window.__KAPA_USER || null) +// Session state drives which SDK/drawer we mount: +// authenticated === null → still probing (brief loading state) +// authenticated === false → anonymous: Chat SDK drawer (no agent quota) +// authenticated === true → Agent SDK drawer (tools, history, email) +// The kapa-session event (from getSessionToken/probeSession) carries the flag, +// the user, and the login URL. window.__KAPA_* mirror it for late mounts. +function useSession () { + const [session, setSession] = useState(() => ({ + authenticated: window.__KAPA_AUTHENTICATED === undefined ? null : Boolean(window.__KAPA_AUTHENTICATED), + user: window.__KAPA_USER || null, + loginUrl: window.__KAPA_LOGIN_URL || null, + })) useEffect(() => { - const handle = (e) => setUser(e.detail?.user || null) + const handle = (e) => setSession({ + authenticated: Boolean(e.detail?.authenticated), + user: e.detail?.user || null, + loginUrl: e.detail?.loginUrl || null, + }) window.addEventListener('kapa-session', handle) return () => window.removeEventListener('kapa-session', handle) }, []) - return user + return session } function App () { const colorScheme = useSiteColorScheme() - const kapaUser = useKapaUser() + const { authenticated, user, loginUrl } = useSession() + + // Signed-in: full Agent SDK experience (tools, history, email attribution) + if (authenticated === true) { + return ( + + + + ) + } + + // Anonymous: same drawer, Chat SDK (no session backend, no agent quota) + if (authenticated === false) { + return ( + + + + ) + } + // Probing — brief; avoids flashing the wrong tier return ( - - - +
+
+
) } diff --git a/src/js/react/components/ChatInterface.jsx b/src/js/react/components/ChatInterface.jsx index d8c59e0d..cb4d0119 100644 --- a/src/js/react/components/ChatInterface.jsx +++ b/src/js/react/components/ChatInterface.jsx @@ -7,16 +7,11 @@ import { ClipboardCopy, CircleStop, History, - Check, - AlertCircle, Sparkles, X, } from 'lucide-react' -import DOMPurify from 'dompurify' -import { Marked } from 'marked' -import { markedHighlight } from 'marked-highlight' -import hljs from 'highlight.js' import { safeHeap } from '../heap.js' +import { Answer, Toast } from './chatShared.jsx' import { agentTools } from '../agentTools.js' // Resumed threads come back without displayName on tool calls (the SDK only @@ -49,64 +44,6 @@ class ErrorBoundary extends Component { } } -const marked = new Marked( - markedHighlight({ - emptyLangClass: 'hljs', - langPrefix: 'hljs language-', - highlight(code, info = '') { - try { - return hljs.highlightAuto(code).value - } catch { - return code - } - }, - }) -) - - -// ——— Toast component ———————————————————————————————————————————————————— -function Toast({ message, type = 'success', onDismiss }) { - useEffect(() => { - const timer = setTimeout(() => { - if (onDismiss) onDismiss() - }, 3000) - return () => clearTimeout(timer) - }, [onDismiss]) - - const isError = type === 'error' - - return ( -
- - {isError ? : } - - {message} -
- ) -} - -// ——— Answer component ——————————————————————————————————————————————————— -function Answer({ md }) { - const containerRef = useRef(null) - - useEffect(() => { - try { - const rawHtml = marked.parse(md || '') - const clean = DOMPurify.sanitize(rawHtml) - if (containerRef.current) { - containerRef.current.innerHTML = clean - } - } catch (err) { - console.error('Markdown render error:', err) - if (containerRef.current) { - containerRef.current.textContent = md - } - } - }, [md]) - - return
-} - // ——— Sources ———————————————————————————————————————————————————————————— // Assistant messages carry sources inside tool-call blocks; collect and // dedupe them by URL for a compact link list under the answer. diff --git a/src/js/react/components/ChatSdkInterface.jsx b/src/js/react/components/ChatSdkInterface.jsx new file mode 100644 index 00000000..9fb4c3ee --- /dev/null +++ b/src/js/react/components/ChatSdkInterface.jsx @@ -0,0 +1,229 @@ +import React, { useState, useEffect, useRef, Component } from 'react' +import { useChat } from '@kapaai/react-sdk' +import { ArrowRight, CircleStop, RefreshCcw, ClipboardCopy, Sparkles } from 'lucide-react' +import { safeHeap } from '../heap.js' +import { Answer, Toast } from './chatShared.jsx' + +// Anonymous drawer, powered by the Chat SDK (not the Agent SDK). Renders into +// the same #chat-panel-kapa-root chrome with the same CSS classes as the +// signed-in Agent interface, so the two tiers look identical — the agent tier +// just adds tools, history, and account-scoped features on top. Needs no +// session backend (the Chat SDK uses its own bot protection). + +class ErrorBoundary extends Component { + constructor (props) { super(props); this.state = { hasError: false } } + static getDerivedStateFromError () { return { hasError: true } } + componentDidCatch (err, info) { console.error('Render error in ChatSdkInterface:', err, info) } + render () { + if (this.state.hasError) { + return
Something went wrong. Try refreshing the page.
+ } + return this.props.children + } +} + +export default function ChatSdkInterface ({ loginUrl }) { + const [message, setMessage] = useState('') + const [dots, setDots] = useState('') + const [suggestions, setSuggestions] = useState([]) + const [hasInteracted, setHasInteracted] = useState(false) + const [toast, setToast] = useState(null) + const [isMobile, setIsMobile] = useState(window.innerWidth < 1150) + const [dropdownOpen, setDropdownOpen] = useState(false) + const inputRef = useRef(null) + + const showToast = (msg, type = 'success') => setToast({ message: msg, type }) + + const { + conversation, + submitQuery, + isPreparingAnswer, + isGeneratingAnswer, + stopGeneration, + resetConversation, + } = useChat() + + const isBusy = isPreparingAnswer || isGeneratingAnswer + + useEffect(() => { + let s = window.AI_SUGGESTIONS + if (typeof s === 'string') { + try { s = JSON.parse(s) } catch (e) { /* ignore */ } + } + if (Array.isArray(s)) setSuggestions(s) + }, []) + + useEffect(() => { + const onResize = () => { + const nowMobile = window.innerWidth < 1150 + setIsMobile(nowMobile) + if (!nowMobile) setDropdownOpen(false) + } + window.addEventListener('resize', onResize) + return () => window.removeEventListener('resize', onResize) + }, []) + + useEffect(() => { + let timer + if (isPreparingAnswer) { + timer = setInterval(() => setDots((d) => (d.length < 3 ? d + '.' : '')), 500) + } else { + setDots('') + } + return () => clearInterval(timer) + }, [isPreparingAnswer]) + + const doQuery = (q) => { + if (!q.trim() || isBusy) return + if (!hasInteracted) setHasInteracted(true) + safeHeap('ask_question_docs_home', { question: q, tier: 'anonymous' }) + submitQuery(q) + setMessage('') + setDropdownOpen(false) + } + + // Same global entry point the agent interface exposes, so code-block and + // playground "Ask AI" triggers work for anonymous users too. + useEffect(() => { + window.submitChatQuery = (query, autoSubmit = true) => { + if (!query || !query.trim()) return + if (autoSubmit) { + doQuery(query) + } else { + setMessage(query) + if (inputRef.current) inputRef.current.focus() + } + } + return () => { delete window.submitChatQuery } + }, [hasInteracted, isBusy]) + + const handleSubmit = (e) => { e.preventDefault(); doQuery(message) } + + const handleReset = () => { + resetConversation() + setMessage('') + setHasInteracted(false) + setDropdownOpen(false) + } + + const handleCopy = async () => { + await navigator.clipboard.writeText( + conversation.map((qa) => `Question: ${qa.question}\nAnswer: ${qa.answer}`).join('\n---\n') + ) + showToast('Copied to clipboard', 'success') + } + + const renderChips = () => { + if (!Array.isArray(suggestions) || suggestions.length === 0) return null + const first = isMobile ? suggestions.slice(0, 1) : suggestions.slice(0, 2) + const rest = isMobile ? suggestions.slice(1) : suggestions.slice(2) + return ( +
+ {first.map((s, i) =>
doQuery(s)}>{s}
)} + {rest.length > 0 && ( + <> +
setDropdownOpen((o) => !o)}>Show more
+ {dropdownOpen && ( +
+ {rest.map((s, i) =>
doQuery(s)}>{s}
)} +
+ )} + + )} +
+ ) + } + + return ( + +
+ {toast && setToast(null)} />} + + {/* Slim upsell — chat works without signing in; this sells the agent tier */} + + + Sign in to save your conversations and unlock the AI agent + + + + {!hasInteracted && ( +
+
+

How can I help?

+

+ I can answer questions about Redpanda docs, write quickstarts, and help you troubleshoot. +

+ {suggestions.length > 0 && ( +
+ {suggestions.map((s, i) => ( + + ))} +
+ )} +
+ )} + +
+
+ {conversation.map((qa, idx) => { + const isLast = idx === conversation.length - 1 + return ( +
+
+
{qa.question}
+ + {isLast && !isBusy && qa.answer && ( +
+
+ + +
+
+ )} +
+ ) + })} + {isPreparingAnswer &&
{`Preparing answer${dots}`}
} +
+
+ +
+
+
+ +