From a979d128c46a764f6da5348889d6578ff3bfa160 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:17:58 -0600 Subject: [PATCH 01/15] Implement custom Kapa support handoff and chat codeblock UX Co-Authored-By: Warp Agent --- .env.example | 23 +- astro.config.mjs | 36 +- package-lock.json | 1064 ++++++++--------- src/components/CustomSidebar.astro | 12 +- src/components/KapaChatLauncher.css | 316 ++++- src/components/KapaChatLauncher.mount.tsx | 0 src/components/KapaChatLauncher.tsx | 586 ++++++++- .../known-issues.mdx | 48 + src/pages/api/highlight-code.ts | 86 ++ src/pages/api/support-handoff.ts | 137 +++ src/styles/warp-components.css | 12 + vercel.json | 6 +- 12 files changed, 1726 insertions(+), 600 deletions(-) delete mode 100644 src/components/KapaChatLauncher.mount.tsx create mode 100644 src/pages/api/highlight-code.ts create mode 100644 src/pages/api/support-handoff.ts diff --git a/.env.example b/.env.example index 02af3a50d..cd78fae27 100644 --- a/.env.example +++ b/.env.example @@ -4,11 +4,19 @@ # Values below are PUBLIC (they're shipped to the browser by Astro's # `envField`, and live behind rate limiting / allow-lists on the vendor side). -# Kapa Custom Frontend integration ID for the "Ask AI" button in the header. -# If unset, the Ask AI button is hidden and the site still runs normally. -# Get yours at: https://app.kapa.ai/admin +# Kapa Website Widget integration ID for the "Ask AI" button in the sidebar. +# If unset, docs falls back to the shared widget integration ID used in preview/prod. +# Get yours at: https://app.kapa.ai/admin (Integrations → Widget → Copy integration ID). +# The same value is passed to the widget as `data-website-id`. +# PUBLIC_KAPA_INTEGRATION_ID=f31c5644-dd65-4f49-9762-bf580062afa8 PUBLIC_KAPA_INTEGRATION_ID= +# Optional Kapa project ID used to build internal conversation links in +# "Create ticket" email drafts: +# https://app.kapa.ai//conversations/ +# You can find this in the Kapa dashboard URL while viewing the project. +PUBLIC_KAPA_PROJECT_ID= + # RudderStack analytics — required for docs_404 event tracking and page analytics. # Without these, no analytics events are sent and the weekly 404 monitor will # report zero data. Set both in the Vercel project environment (all environments). @@ -21,3 +29,12 @@ PUBLIC_KAPA_INTEGRATION_ID= # directive in vercel.json (a mismatch silently blocks all events in the browser). PUBLIC_RUDDERSTACK_WRITE_KEY= PUBLIC_RUDDERSTACK_DATA_PLANE_URL= + +# Server-side handoff forwarding endpoint used by /api/support-handoff. +# This should point at the DevX service endpoint that creates Front +# conversations from docs chat handoff requests. +SUPPORT_HANDOFF_ENDPOINT_URL= + +# Optional shared secret sent as an authorization bearer token when +# forwarding to SUPPORT_HANDOFF_ENDPOINT_URL. +SUPPORT_HANDOFF_SHARED_SECRET= diff --git a/astro.config.mjs b/astro.config.mjs index 12462c7b4..cfad50019 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -28,6 +28,11 @@ export default defineConfig({ access: 'public', optional: true, }), + PUBLIC_KAPA_PROJECT_ID: envField.string({ + context: 'client', + access: 'public', + optional: true, + }), PUBLIC_RUDDERSTACK_WRITE_KEY: envField.string({ context: 'client', access: 'public', @@ -43,6 +48,16 @@ export default defineConfig({ access: 'public', optional: true, }), + SUPPORT_HANDOFF_ENDPOINT_URL: envField.string({ + context: 'server', + access: 'secret', + optional: true, + }), + SUPPORT_HANDOFF_SHARED_SECRET: envField.string({ + context: 'server', + access: 'secret', + optional: true, + }), }, }, integrations: [ @@ -61,15 +76,24 @@ export default defineConfig({ baseUrl: 'https://github.com/warpdotdev/docs/edit/main/', }, lastUpdated: true, - // Soft-wrap long lines by default. Expressive Code defaults to - // `overflow-x: auto` for `
`, which combined with macOS's
-			// auto-hidden scrollbars made wide lines silently truncate.
-			// `wrap: true` adds the `.wrap` class so EC's `white-space: pre-wrap`
-			// kicks in; leading indents are preserved via its `span.indent` rule.
+			// Keep long lines unwrapped so code blocks use horizontal scrolling.
+			// This aligns docs behavior with the side chat renderer and preserves
+			// exact line shape for commands and snippets.
 			expressiveCode: {
 				defaultProps: {
-					wrap: true,
+					wrap: false,
 				},
+				// IMPORTANT: Expressive Code's Vite plugin rewrites Shiki's bundled
+				// theme registry (shiki/dist/themes.mjs) and strips every theme not
+				// listed as a *string* in its `themes` config. Starlight passes its
+				// themes as objects, so the registry is emptied for the entire Vite
+				// module graph — including the Kapa side-chat island, whose runtime
+				// createHighlighter(['github-light', 'github-dark']) then throws
+				// "theme is not included in this bundle" and falls back to plaintext.
+				// Keeping the registry intact restores chat code block highlighting.
+				// Only the requested themes are ever fetched at runtime (lazy chunks),
+				// so this does not bloat the pages served to visitors.
+				removeUnusedThemes: false,
 				// Map languages Shiki doesn't bundle to a safe fallback. PromQL
 				// blocks live in platform/self-hosting/monitoring.mdx;
 				// without this alias every build emits noisy "language could not be
diff --git a/package-lock.json b/package-lock.json
index baf52de79..5f4aff235 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,7 @@
       "hasInstallScript": true,
       "license": "MIT",
       "dependencies": {
-        "@astrojs/react": "^6.0.2",
+        "@astrojs/react": "^5.0.3",
         "@astrojs/rss": "^4.0.19",
         "@astrojs/sitemap": "^3.7.2",
         "@astrojs/starlight": "^0.41.4",
@@ -274,6 +274,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -290,6 +293,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -306,6 +312,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -322,6 +331,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -392,14 +404,14 @@
       }
     },
     "node_modules/@astrojs/internal-helpers": {
-      "version": "0.10.2",
-      "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.2.tgz",
-      "integrity": "sha512-yt7fMgPYqSM4Tmr+taTW6Per+hjJ8Pk6lA1PAcDyqzOt8HzJ6Kje5WzCxA2Sd+9wsUW7uhkLeoTMK0cXPwH9rQ==",
+      "version": "0.10.0",
+      "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.0.tgz",
+      "integrity": "sha512-Ry2R3VPeIN4uPCSA4xQc+e+vsJXkalKpEbDc07hV+a/o5Bs2N/s/uDcPJH/05L19DKh9tAy7e6JM3YZ6Cxfezw==",
       "license": "MIT",
       "dependencies": {
         "@types/hast": "^3.0.4",
         "@types/mdast": "^4.0.4",
-        "js-yaml": "^4.3.0",
+        "js-yaml": "^4.1.1",
         "picomatch": "^4.0.4",
         "retext-smartypants": "^6.2.0",
         "shiki": "^4.0.2",
@@ -481,121 +493,6 @@
         "vfile": "^6.0.3"
       }
     },
-    "node_modules/@astrojs/markdown-remark/node_modules/@astrojs/internal-helpers": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.0.tgz",
-      "integrity": "sha512-Ry2R3VPeIN4uPCSA4xQc+e+vsJXkalKpEbDc07hV+a/o5Bs2N/s/uDcPJH/05L19DKh9tAy7e6JM3YZ6Cxfezw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/hast": "^3.0.4",
-        "@types/mdast": "^4.0.4",
-        "js-yaml": "^4.1.1",
-        "picomatch": "^4.0.4",
-        "retext-smartypants": "^6.2.0",
-        "shiki": "^4.0.2",
-        "smol-toml": "^1.6.0",
-        "unified": "^11.0.5"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/core": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.3.0.tgz",
-      "integrity": "sha512-EooU3i9F6IAE8kEu+AnGf9DFZWkQBZ+hJn3tLVbsH+61mtQiva5biai66fAA6nvFPXkLgvrh7BrR7YcJU83xQQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/primitive": "4.3.0",
-        "@shikijs/types": "4.3.0",
-        "@shikijs/vscode-textmate": "^10.0.2",
-        "@types/hast": "^3.0.4",
-        "hast-util-to-html": "^9.0.5"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-javascript": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.3.0.tgz",
-      "integrity": "sha512-hTv/KiFf2tpiqlACPiztGGurEARWIutB8YUhcrA1pUC7VzzwKO+g5crUocrLztrZ5ro5Z4hbXg7bYclETn3gSQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/types": "4.3.0",
-        "@shikijs/vscode-textmate": "^10.0.2",
-        "oniguruma-to-es": "^4.3.6"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-oniguruma": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.3.0.tgz",
-      "integrity": "sha512-1vMdN3gHfnKfLYwecUI2ITJI4RhHt96xEaJumVn7Heb0IlJ8WQMIH0Voak+2j22BpSNKdnOfB/pCTPnPm2gq7A==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/types": "4.3.0",
-        "@shikijs/vscode-textmate": "^10.0.2"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/langs": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.3.0.tgz",
-      "integrity": "sha512-rnlqFbBRSys9bT4gl/5rw9RnS0W/I84ZldXPkO7cvlEMoV85TyF/aU01N7/NbSR776RNLjrJKjfFUXJR6wN1Cg==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/types": "4.3.0"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/themes": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.0.tgz",
-      "integrity": "sha512-Avgt05YiT+Y3prjIc9lmQxhJzHBcCfR6cjiFW4OyaMBbt2A6trX5rfjUzx+Vj/mE9qpArYjatnqo9XPjQNW/AQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/types": "4.3.0"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/types": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz",
-      "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/vscode-textmate": "^10.0.2",
-        "@types/hast": "^3.0.4"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@astrojs/markdown-remark/node_modules/shiki": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.3.0.tgz",
-      "integrity": "sha512-NKKjWzR6LIGL3sXBrWDw9sDS9cxx42/DkysaNqJEeOWE8Kix5gpak0bc00OfDVEO4oyXSyz8+aRaqKoBD1yo7A==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/core": "4.3.0",
-        "@shikijs/engine-javascript": "4.3.0",
-        "@shikijs/engine-oniguruma": "4.3.0",
-        "@shikijs/langs": "4.3.0",
-        "@shikijs/themes": "4.3.0",
-        "@shikijs/types": "4.3.0",
-        "@shikijs/vscode-textmate": "^10.0.2",
-        "@types/hast": "^3.0.4"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
     "node_modules/@astrojs/markdown-satteri": {
       "version": "0.3.4",
       "resolved": "https://registry.npmjs.org/@astrojs/markdown-satteri/-/markdown-satteri-0.3.4.tgz",
@@ -688,16 +585,16 @@
       }
     },
     "node_modules/@astrojs/react": {
-      "version": "6.0.2",
-      "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-6.0.2.tgz",
-      "integrity": "sha512-Fvv2UqS7ajFL2Yjd5s4s5PcCBCSSfks4r04rbCHZO5z4pUPwCygV2ketI+iC+1P/sdHANLV3tgDL1wjzty4cJg==",
+      "version": "5.0.7",
+      "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-5.0.7.tgz",
+      "integrity": "sha512-N9cCoxvnLWaP+AK1Fv4e5Mc7ktnVTpSo2nWLwvD9Ohr1dJKygwrTSm9yatqoahgb1A5Kwjg/rT2shRiIVdn3aw==",
       "license": "MIT",
       "dependencies": {
-        "@astrojs/internal-helpers": "0.10.2",
+        "@astrojs/internal-helpers": "0.10.0",
         "@vitejs/plugin-react": "^5.2.0",
         "devalue": "^5.8.1",
         "ultrahtml": "^1.6.0",
-        "vite": "^8.0.13"
+        "vite": "^7.3.2"
       },
       "engines": {
         "node": ">=22.12.0"
@@ -888,9 +785,9 @@
       }
     },
     "node_modules/@babel/code-frame/node_modules/@babel/helper-validator-identifier": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz",
-      "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+      "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
       "license": "MIT",
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
@@ -946,21 +843,21 @@
       }
     },
     "node_modules/@babel/core/node_modules/@babel/helper-validator-identifier": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz",
-      "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+      "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
       "license": "MIT",
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
       }
     },
     "node_modules/@babel/core/node_modules/@babel/parser": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0.tgz",
-      "integrity": "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz",
+      "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==",
       "license": "MIT",
       "dependencies": {
-        "@babel/types": "^8.0.0"
+        "@babel/types": "^8.0.4"
       },
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -970,13 +867,13 @@
       }
     },
     "node_modules/@babel/core/node_modules/@babel/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz",
+      "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==",
       "license": "MIT",
       "dependencies": {
         "@babel/helper-string-parser": "^8.0.0",
-        "@babel/helper-validator-identifier": "^8.0.0"
+        "@babel/helper-validator-identifier": "^8.0.4"
       },
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
@@ -1009,21 +906,21 @@
       }
     },
     "node_modules/@babel/generator/node_modules/@babel/helper-validator-identifier": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz",
-      "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+      "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
       "license": "MIT",
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
       }
     },
     "node_modules/@babel/generator/node_modules/@babel/parser": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0.tgz",
-      "integrity": "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz",
+      "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==",
       "license": "MIT",
       "dependencies": {
-        "@babel/types": "^8.0.0"
+        "@babel/types": "^8.0.4"
       },
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -1033,13 +930,13 @@
       }
     },
     "node_modules/@babel/generator/node_modules/@babel/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz",
+      "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==",
       "license": "MIT",
       "dependencies": {
         "@babel/helper-string-parser": "^8.0.0",
-        "@babel/helper-validator-identifier": "^8.0.0"
+        "@babel/helper-validator-identifier": "^8.0.4"
       },
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
@@ -1071,9 +968,9 @@
       }
     },
     "node_modules/@babel/helper-plugin-utils": {
-      "version": "7.28.6",
-      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz",
-      "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==",
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz",
+      "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==",
       "license": "MIT",
       "engines": {
         "node": ">=6.9.0"
@@ -1129,22 +1026,22 @@
       }
     },
     "node_modules/@babel/helpers/node_modules/@babel/helper-validator-identifier": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz",
-      "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+      "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
       "license": "MIT",
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
       }
     },
     "node_modules/@babel/helpers/node_modules/@babel/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz",
+      "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==",
       "license": "MIT",
       "dependencies": {
         "@babel/helper-string-parser": "^8.0.0",
-        "@babel/helper-validator-identifier": "^8.0.0"
+        "@babel/helper-validator-identifier": "^8.0.4"
       },
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
@@ -1166,12 +1063,12 @@
       }
     },
     "node_modules/@babel/plugin-transform-react-jsx-self": {
-      "version": "7.27.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz",
-      "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==",
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz",
+      "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==",
       "license": "MIT",
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.27.1"
+        "@babel/helper-plugin-utils": "^7.29.7"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1181,12 +1078,12 @@
       }
     },
     "node_modules/@babel/plugin-transform-react-jsx-source": {
-      "version": "7.27.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz",
-      "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==",
+      "version": "7.29.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz",
+      "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==",
       "license": "MIT",
       "dependencies": {
-        "@babel/helper-plugin-utils": "^7.27.1"
+        "@babel/helper-plugin-utils": "^7.29.7"
       },
       "engines": {
         "node": ">=6.9.0"
@@ -1196,9 +1093,9 @@
       }
     },
     "node_modules/@babel/runtime": {
-      "version": "7.28.6",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz",
-      "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==",
+      "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"
@@ -1228,21 +1125,21 @@
       }
     },
     "node_modules/@babel/template/node_modules/@babel/helper-validator-identifier": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz",
-      "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+      "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
       "license": "MIT",
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
       }
     },
     "node_modules/@babel/template/node_modules/@babel/parser": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0.tgz",
-      "integrity": "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz",
+      "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==",
       "license": "MIT",
       "dependencies": {
-        "@babel/types": "^8.0.0"
+        "@babel/types": "^8.0.4"
       },
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -1252,30 +1149,30 @@
       }
     },
     "node_modules/@babel/template/node_modules/@babel/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz",
+      "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==",
       "license": "MIT",
       "dependencies": {
         "@babel/helper-string-parser": "^8.0.0",
-        "@babel/helper-validator-identifier": "^8.0.0"
+        "@babel/helper-validator-identifier": "^8.0.4"
       },
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
       }
     },
     "node_modules/@babel/traverse": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.0.tgz",
-      "integrity": "sha512-bxTj/W2VclGE6CctlfQOpxg8MPDzXArRqkOBePw8EHfebcjF7fETWSS3BriEECo+UiU/Yblq+xUtSImFu7cTbw==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-8.0.4.tgz",
+      "integrity": "sha512-bZnmqzGG8UZneG1lLxBoWIH0G6Gr1D846Yu4/3XnY6FhCndMR49u26nTY08u/dAxWmLWF9vGQOuC+84FfIUoeg==",
       "license": "MIT",
       "dependencies": {
         "@babel/code-frame": "^8.0.0",
         "@babel/generator": "^8.0.0",
         "@babel/helper-globals": "^8.0.0",
-        "@babel/parser": "^8.0.0",
+        "@babel/parser": "^8.0.4",
         "@babel/template": "^8.0.0",
-        "@babel/types": "^8.0.0",
+        "@babel/types": "^8.0.4",
         "obug": "^2.1.1"
       },
       "engines": {
@@ -1292,21 +1189,21 @@
       }
     },
     "node_modules/@babel/traverse/node_modules/@babel/helper-validator-identifier": {
-      "version": "8.0.2",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.2.tgz",
-      "integrity": "sha512-9Fr9QeyCAyi1BR1jKZ6uYQ24EIhQUx5ReHfQU7drOE+TPOb+w11/dsqLkMOT2U29OdCT71XajrOT8xDc1C7orA==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-8.0.4.tgz",
+      "integrity": "sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==",
       "license": "MIT",
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
       }
     },
     "node_modules/@babel/traverse/node_modules/@babel/parser": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.0.tgz",
-      "integrity": "sha512-aLxAE+imI9bCcyaPrUDjBv3uSkWieifjLe0kuFOZF0zli0L6GCsTmsePnTr55adbIAgYz2zhN1vnFimCBUYcRQ==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-8.0.4.tgz",
+      "integrity": "sha512-srpptsAkEbbNIC/q8nT7o+m6CQe8CJUTV/t7MYc9NnWlgYVtHOb7JH6SorxMhN0kuRJjVqXbKClG6xSbPtzz+g==",
       "license": "MIT",
       "dependencies": {
-        "@babel/types": "^8.0.0"
+        "@babel/types": "^8.0.4"
       },
       "bin": {
         "parser": "bin/babel-parser.js"
@@ -1316,13 +1213,13 @@
       }
     },
     "node_modules/@babel/traverse/node_modules/@babel/types": {
-      "version": "8.0.0",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.0.tgz",
-      "integrity": "sha512-K8ponJDxBwDHigkeFqaqT5wLGl4bTlwMafR8k7b5CPxr6Ww+UG9ls8Yx6Tcpboxu97eeGVEEyKcHmEyOwN1vSw==",
+      "version": "8.0.4",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-8.0.4.tgz",
+      "integrity": "sha512-eY+Yn3dCqTGmyiq2QRU66lA5FL8lqqqvecHt0fF3uHONIa7ToYsaCiWV8lOKqAs0Rb2SjixiKFROngnulPtt2g==",
       "license": "MIT",
       "dependencies": {
         "@babel/helper-string-parser": "^8.0.0",
-        "@babel/helper-validator-identifier": "^8.0.0"
+        "@babel/helper-validator-identifier": "^8.0.4"
       },
       "engines": {
         "node": "^22.18.0 || >=24.11.0"
@@ -1374,6 +1271,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1387,6 +1287,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1400,6 +1303,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1413,6 +1319,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -1577,25 +1486,14 @@
       "license": "MIT"
     },
     "node_modules/@emnapi/core": {
-      "version": "1.11.3",
-      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz",
-      "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==",
-      "license": "MIT",
-      "optional": true,
-      "peer": true,
-      "dependencies": {
-        "@emnapi/wasi-threads": "1.2.3",
-        "tslib": "^2.4.0"
-      }
-    },
-    "node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz",
-      "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==",
+      "version": "1.11.2",
+      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.2.tgz",
+      "integrity": "sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==",
       "license": "MIT",
       "optional": true,
       "peer": true,
       "dependencies": {
+        "@emnapi/wasi-threads": "1.2.2",
         "tslib": "^2.4.0"
       }
     },
@@ -2081,9 +1979,9 @@
       }
     },
     "node_modules/@fingerprintjs/fingerprintjs-pro": {
-      "version": "3.12.8",
-      "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.12.8.tgz",
-      "integrity": "sha512-6BEMtAkfvMTnTLpHaS6q+lW11msE9vFzHheE95SD/+X21QKGVsMGlel7lBG2ClGHHdqpFNO+nNKvuIl/xdPgng==",
+      "version": "3.12.13",
+      "resolved": "https://registry.npmjs.org/@fingerprintjs/fingerprintjs-pro/-/fingerprintjs-pro-3.12.13.tgz",
+      "integrity": "sha512-l9G1jn6d9wpIG8bMW7TsrHjPwm26B4T6OB42PlLNQ9QrblbuGWvVEFb+gqdCzzPcP6J+zfCoXQ3xMPlp88SgXg==",
       "license": "SEE LICENSE IN LICENSE"
     },
     "node_modules/@fingerprintjs/fingerprintjs-pro-react": {
@@ -2108,31 +2006,31 @@
       }
     },
     "node_modules/@floating-ui/core": {
-      "version": "1.7.5",
-      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
-      "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.8.0.tgz",
+      "integrity": "sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==",
       "license": "MIT",
       "dependencies": {
-        "@floating-ui/utils": "^0.2.11"
+        "@floating-ui/utils": "^0.2.12"
       }
     },
     "node_modules/@floating-ui/dom": {
-      "version": "1.7.6",
-      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
-      "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.8.0.tgz",
+      "integrity": "sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==",
       "license": "MIT",
       "dependencies": {
-        "@floating-ui/core": "^1.7.5",
-        "@floating-ui/utils": "^0.2.11"
+        "@floating-ui/core": "^1.8.0",
+        "@floating-ui/utils": "^0.2.12"
       }
     },
     "node_modules/@floating-ui/react-dom": {
-      "version": "2.1.8",
-      "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz",
-      "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==",
+      "version": "2.1.9",
+      "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.9.tgz",
+      "integrity": "sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==",
       "license": "MIT",
       "dependencies": {
-        "@floating-ui/dom": "^1.7.6"
+        "@floating-ui/dom": "^1.8.0"
       },
       "peerDependencies": {
         "react": ">=16.8.0",
@@ -2140,15 +2038,15 @@
       }
     },
     "node_modules/@floating-ui/utils": {
-      "version": "0.2.11",
-      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
-      "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
+      "version": "0.2.12",
+      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.12.tgz",
+      "integrity": "sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==",
       "license": "MIT"
     },
     "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==",
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/@hcaptcha/loader/-/loader-2.4.2.tgz",
+      "integrity": "sha512-+Pf0Vin6iJlJj5u/mq6XMgbJT1mi/Sg5LWHxxqO4YHt2YvdZgecp5V2sbC6vRaNPJUqQGk2HOu1K/i12mqs5vw==",
       "license": "MIT"
     },
     "node_modules/@hcaptcha/react-hcaptcha": {
@@ -2276,6 +2174,9 @@
       "cpu": [
         "arm"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2292,6 +2193,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2308,6 +2212,9 @@
       "cpu": [
         "ppc64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2324,6 +2231,9 @@
       "cpu": [
         "riscv64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2340,6 +2250,9 @@
       "cpu": [
         "s390x"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2356,6 +2269,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2372,6 +2288,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2388,6 +2307,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "LGPL-3.0-or-later",
       "optional": true,
       "os": [
@@ -2404,6 +2326,9 @@
       "cpu": [
         "arm"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2426,6 +2351,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2448,6 +2376,9 @@
       "cpu": [
         "ppc64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2470,6 +2401,9 @@
       "cpu": [
         "riscv64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2492,6 +2426,9 @@
       "cpu": [
         "s390x"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2514,6 +2451,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2536,6 +2476,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2558,6 +2501,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "Apache-2.0",
       "optional": true,
       "os": [
@@ -2713,14 +2659,14 @@
       }
     },
     "node_modules/@kapaai/react-sdk": {
-      "version": "0.9.2",
-      "resolved": "https://registry.npmjs.org/@kapaai/react-sdk/-/react-sdk-0.9.2.tgz",
-      "integrity": "sha512-PeqgKL6d0yIkkmPn+1O8TBjH7KGx5HNiH7fhGl0FEV2MfJZBzWNvAOdOm/34VLdpb2Nawe3H1gSURdJ0DG6z7Q==",
+      "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",
-        "@tanstack/react-query": "^5.74.3",
         "js-cookie": "^3.0.5",
         "tldts": "^7.0.7"
       },
@@ -2794,21 +2740,24 @@
       "license": "BSD-2-Clause"
     },
     "node_modules/@napi-rs/wasm-runtime": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz",
-      "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.1.tgz",
+      "integrity": "sha512-KjZdi8Q1wh89gsVmghvbrMgWl6ZWmRmHV6wjB7/g4Zf0dyO+hH3neZUtuDNPO00qq5YE5RITVWvrIZKRaAmzGQ==",
       "license": "MIT",
       "optional": true,
       "dependencies": {
         "@tybys/wasm-util": "^0.10.3"
       },
+      "engines": {
+        "node": "^20.19.0 || ^22.13.0 || >=23.5.0"
+      },
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/Brooooooklyn"
       },
       "peerDependencies": {
-        "@emnapi/core": "^1.7.1",
-        "@emnapi/runtime": "^1.7.1"
+        "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.3",
+        "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.3"
       }
     },
     "node_modules/@nodable/entities": {
@@ -2830,9 +2779,9 @@
       "license": "MIT"
     },
     "node_modules/@oxc-project/types": {
-      "version": "0.139.0",
-      "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.139.0.tgz",
-      "integrity": "sha512-r9gHphtCs+1M7J0pw6Sn/hh/Wpa/iQrOOkrNAlVLF/gHq+/CJmHIWKKUUhdWjcD6CIa8idarspCsASiXCXvFUw==",
+      "version": "0.142.0",
+      "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.142.0.tgz",
+      "integrity": "sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==",
       "license": "MIT",
       "funding": {
         "url": "https://github.com/sponsors/Boshen"
@@ -2936,18 +2885,18 @@
       ]
     },
     "node_modules/@radix-ui/primitive": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
-      "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.7.tgz",
+      "integrity": "sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==",
       "license": "MIT"
     },
     "node_modules/@radix-ui/react-arrow": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
-      "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+      "version": "1.1.15",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.15.tgz",
+      "integrity": "sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-primitive": "2.1.3"
+        "@radix-ui/react-primitive": "2.1.10"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -2965,9 +2914,9 @@
       }
     },
     "node_modules/@radix-ui/react-compose-refs": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
-      "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.5.tgz",
+      "integrity": "sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==",
       "license": "MIT",
       "peerDependencies": {
         "@types/react": "*",
@@ -2980,9 +2929,9 @@
       }
     },
     "node_modules/@radix-ui/react-context": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
-      "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.2.2.tgz",
+      "integrity": "sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==",
       "license": "MIT",
       "peerDependencies": {
         "@types/react": "*",
@@ -2995,16 +2944,16 @@
       }
     },
     "node_modules/@radix-ui/react-dismissable-layer": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
-      "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
+      "version": "1.1.19",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.19.tgz",
+      "integrity": "sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/primitive": "1.1.3",
-        "@radix-ui/react-compose-refs": "1.1.2",
-        "@radix-ui/react-primitive": "2.1.3",
-        "@radix-ui/react-use-callback-ref": "1.1.1",
-        "@radix-ui/react-use-escape-keydown": "1.1.1"
+        "@radix-ui/primitive": "1.1.7",
+        "@radix-ui/react-compose-refs": "1.1.5",
+        "@radix-ui/react-primitive": "2.1.10",
+        "@radix-ui/react-use-callback-ref": "1.1.4",
+        "@radix-ui/react-use-effect-event": "0.0.5"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3022,9 +2971,9 @@
       }
     },
     "node_modules/@radix-ui/react-focus-guards": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
-      "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.6.tgz",
+      "integrity": "sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==",
       "license": "MIT",
       "peerDependencies": {
         "@types/react": "*",
@@ -3037,14 +2986,14 @@
       }
     },
     "node_modules/@radix-ui/react-focus-scope": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
-      "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
+      "version": "1.1.16",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.16.tgz",
+      "integrity": "sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-compose-refs": "1.1.2",
-        "@radix-ui/react-primitive": "2.1.3",
-        "@radix-ui/react-use-callback-ref": "1.1.1"
+        "@radix-ui/react-compose-refs": "1.1.5",
+        "@radix-ui/react-primitive": "2.1.10",
+        "@radix-ui/react-use-callback-ref": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3062,12 +3011,12 @@
       }
     },
     "node_modules/@radix-ui/react-id": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
-      "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.4.tgz",
+      "integrity": "sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-use-layout-effect": "1.1.1"
+        "@radix-ui/react-use-layout-effect": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3080,26 +3029,26 @@
       }
     },
     "node_modules/@radix-ui/react-popover": {
-      "version": "1.1.15",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
-      "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
-      "license": "MIT",
-      "dependencies": {
-        "@radix-ui/primitive": "1.1.3",
-        "@radix-ui/react-compose-refs": "1.1.2",
-        "@radix-ui/react-context": "1.1.2",
-        "@radix-ui/react-dismissable-layer": "1.1.11",
-        "@radix-ui/react-focus-guards": "1.1.3",
-        "@radix-ui/react-focus-scope": "1.1.7",
-        "@radix-ui/react-id": "1.1.1",
-        "@radix-ui/react-popper": "1.2.8",
-        "@radix-ui/react-portal": "1.1.9",
-        "@radix-ui/react-presence": "1.1.5",
-        "@radix-ui/react-primitive": "2.1.3",
-        "@radix-ui/react-slot": "1.2.3",
-        "@radix-ui/react-use-controllable-state": "1.2.2",
+      "version": "1.1.23",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.23.tgz",
+      "integrity": "sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.7",
+        "@radix-ui/react-compose-refs": "1.1.5",
+        "@radix-ui/react-context": "1.2.2",
+        "@radix-ui/react-dismissable-layer": "1.1.19",
+        "@radix-ui/react-focus-guards": "1.1.6",
+        "@radix-ui/react-focus-scope": "1.1.16",
+        "@radix-ui/react-id": "1.1.4",
+        "@radix-ui/react-popper": "1.3.7",
+        "@radix-ui/react-portal": "1.1.17",
+        "@radix-ui/react-presence": "1.1.10",
+        "@radix-ui/react-primitive": "2.1.10",
+        "@radix-ui/react-slot": "1.3.3",
+        "@radix-ui/react-use-controllable-state": "1.2.6",
         "aria-hidden": "^1.2.4",
-        "react-remove-scroll": "^2.6.3"
+        "react-remove-scroll": "^2.7.2"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3117,21 +3066,21 @@
       }
     },
     "node_modules/@radix-ui/react-popper": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
-      "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.3.7.tgz",
+      "integrity": "sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==",
       "license": "MIT",
       "dependencies": {
         "@floating-ui/react-dom": "^2.0.0",
-        "@radix-ui/react-arrow": "1.1.7",
-        "@radix-ui/react-compose-refs": "1.1.2",
-        "@radix-ui/react-context": "1.1.2",
-        "@radix-ui/react-primitive": "2.1.3",
-        "@radix-ui/react-use-callback-ref": "1.1.1",
-        "@radix-ui/react-use-layout-effect": "1.1.1",
-        "@radix-ui/react-use-rect": "1.1.1",
-        "@radix-ui/react-use-size": "1.1.1",
-        "@radix-ui/rect": "1.1.1"
+        "@radix-ui/react-arrow": "1.1.15",
+        "@radix-ui/react-compose-refs": "1.1.5",
+        "@radix-ui/react-context": "1.2.2",
+        "@radix-ui/react-primitive": "2.1.10",
+        "@radix-ui/react-use-callback-ref": "1.1.4",
+        "@radix-ui/react-use-layout-effect": "1.1.4",
+        "@radix-ui/react-use-rect": "1.1.4",
+        "@radix-ui/react-use-size": "1.1.4",
+        "@radix-ui/rect": "1.1.3"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3149,13 +3098,13 @@
       }
     },
     "node_modules/@radix-ui/react-portal": {
-      "version": "1.1.9",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
-      "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
+      "version": "1.1.17",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.17.tgz",
+      "integrity": "sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-primitive": "2.1.3",
-        "@radix-ui/react-use-layout-effect": "1.1.1"
+        "@radix-ui/react-primitive": "2.1.10",
+        "@radix-ui/react-use-layout-effect": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3173,13 +3122,12 @@
       }
     },
     "node_modules/@radix-ui/react-presence": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
-      "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
+      "version": "1.1.10",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.10.tgz",
+      "integrity": "sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-compose-refs": "1.1.2",
-        "@radix-ui/react-use-layout-effect": "1.1.1"
+        "@radix-ui/react-use-layout-effect": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3197,12 +3145,12 @@
       }
     },
     "node_modules/@radix-ui/react-primitive": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
-      "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+      "version": "2.1.10",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.10.tgz",
+      "integrity": "sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-slot": "1.2.3"
+        "@radix-ui/react-slot": "1.3.3"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3220,12 +3168,12 @@
       }
     },
     "node_modules/@radix-ui/react-slot": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
-      "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.3.3.tgz",
+      "integrity": "sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-compose-refs": "1.1.2"
+        "@radix-ui/react-compose-refs": "1.1.5"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3238,9 +3186,9 @@
       }
     },
     "node_modules/@radix-ui/react-use-callback-ref": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
-      "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.4.tgz",
+      "integrity": "sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==",
       "license": "MIT",
       "peerDependencies": {
         "@types/react": "*",
@@ -3253,13 +3201,14 @@
       }
     },
     "node_modules/@radix-ui/react-use-controllable-state": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
-      "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+      "version": "1.2.6",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.6.tgz",
+      "integrity": "sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-use-effect-event": "0.0.2",
-        "@radix-ui/react-use-layout-effect": "1.1.1"
+        "@radix-ui/primitive": "1.1.7",
+        "@radix-ui/react-use-effect-event": "0.0.5",
+        "@radix-ui/react-use-layout-effect": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3272,30 +3221,12 @@
       }
     },
     "node_modules/@radix-ui/react-use-effect-event": {
-      "version": "0.0.2",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz",
-      "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==",
-      "license": "MIT",
-      "dependencies": {
-        "@radix-ui/react-use-layout-effect": "1.1.1"
-      },
-      "peerDependencies": {
-        "@types/react": "*",
-        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
-      },
-      "peerDependenciesMeta": {
-        "@types/react": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@radix-ui/react-use-escape-keydown": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
-      "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+      "version": "0.0.5",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.5.tgz",
+      "integrity": "sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-use-callback-ref": "1.1.1"
+        "@radix-ui/react-use-layout-effect": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3308,9 +3239,9 @@
       }
     },
     "node_modules/@radix-ui/react-use-layout-effect": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
-      "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.4.tgz",
+      "integrity": "sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==",
       "license": "MIT",
       "peerDependencies": {
         "@types/react": "*",
@@ -3323,12 +3254,12 @@
       }
     },
     "node_modules/@radix-ui/react-use-rect": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
-      "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.4.tgz",
+      "integrity": "sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/rect": "1.1.1"
+        "@radix-ui/rect": "1.1.3"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3341,12 +3272,12 @@
       }
     },
     "node_modules/@radix-ui/react-use-size": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
-      "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.4.tgz",
+      "integrity": "sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==",
       "license": "MIT",
       "dependencies": {
-        "@radix-ui/react-use-layout-effect": "1.1.1"
+        "@radix-ui/react-use-layout-effect": "1.1.4"
       },
       "peerDependencies": {
         "@types/react": "*",
@@ -3359,15 +3290,15 @@
       }
     },
     "node_modules/@radix-ui/rect": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
-      "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.3.tgz",
+      "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==",
       "license": "MIT"
     },
     "node_modules/@rolldown/binding-android-arm64": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.1.5.tgz",
-      "integrity": "sha512-lZg8fqIv2v7FF237bwMgzGZEJvGL79/s5knJ/i6FmsGF4XXlzccZ4jb+TrFIxtSSxFtIpdsgrPZeMk1I9AFcyQ==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.1.tgz",
+      "integrity": "sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==",
       "cpu": [
         "arm64"
       ],
@@ -3381,9 +3312,9 @@
       }
     },
     "node_modules/@rolldown/binding-darwin-arm64": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.1.5.tgz",
-      "integrity": "sha512-51Bnx9pNiMRKSUNtBfySkNJ9vMU9Hh3I1ozDd6gyPPYzaXCfnptUcEZxXGYFn+ul2dtcMUiqGR1Yai2K10uoTw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.1.tgz",
+      "integrity": "sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==",
       "cpu": [
         "arm64"
       ],
@@ -3397,9 +3328,9 @@
       }
     },
     "node_modules/@rolldown/binding-darwin-x64": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.1.5.tgz",
-      "integrity": "sha512-Tm+gbfC0aHu1tBA/JvKQh32S0K6YgCHkiAF4/W6xX0K0RmNuc94VeK419dJoE65R5aRxmo+noZQSWrAMF6yb6g==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.1.tgz",
+      "integrity": "sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==",
       "cpu": [
         "x64"
       ],
@@ -3413,9 +3344,9 @@
       }
     },
     "node_modules/@rolldown/binding-freebsd-x64": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.1.5.tgz",
-      "integrity": "sha512-JMzDKCCXq93YccG5gz3hvOs1oXRKAf0XYpfOS88e+wZrC8Iugj6j68867vrYZkvpDDpKn/KoKORThmchMpF6TA==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.1.tgz",
+      "integrity": "sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==",
       "cpu": [
         "x64"
       ],
@@ -3429,9 +3360,9 @@
       }
     },
     "node_modules/@rolldown/binding-linux-arm-gnueabihf": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.1.5.tgz",
-      "integrity": "sha512-uML21j2K5TfPGutKxub+M+nLjZIrWjXQ5Grx4lCe/nimTj9B4L63zHpjXLl4y0L3mcm2htEQIb06oCG/szerNw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.1.tgz",
+      "integrity": "sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==",
       "cpu": [
         "arm"
       ],
@@ -3445,12 +3376,15 @@
       }
     },
     "node_modules/@rolldown/binding-linux-arm64-gnu": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.1.5.tgz",
-      "integrity": "sha512-navSiuTMogvnQoZoM/v+l3ZWo50/NTwSHSzheABx/RCnmUPaKwq9qSo4Br2OYRs21+Fz8uFqITZM3H4opOB0/Q==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.1.tgz",
+      "integrity": "sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==",
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3461,12 +3395,15 @@
       }
     },
     "node_modules/@rolldown/binding-linux-arm64-musl": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.1.5.tgz",
-      "integrity": "sha512-lAryqH7IteztmCXQXk0etKj4wBQ7Gx5S6LjKhsgp9zb8I5bsuvU/2llH1hDQcjsFeqIsovMVN339/8pUDDBXxA==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.1.tgz",
+      "integrity": "sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==",
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3477,12 +3414,15 @@
       }
     },
     "node_modules/@rolldown/binding-linux-ppc64-gnu": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.1.5.tgz",
-      "integrity": "sha512-fsK/sNBnxzBlL4O1JNrZakVQxPspqpED5dLtNsZS9oOKmtSpdNIzxH2kkol5HYTWJN47sE20ztMJPxfZ89qGOg==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.1.tgz",
+      "integrity": "sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==",
       "cpu": [
         "ppc64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3493,12 +3433,15 @@
       }
     },
     "node_modules/@rolldown/binding-linux-s390x-gnu": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.1.5.tgz",
-      "integrity": "sha512-gLYb4BIadlfTOYT5gO503n8zQjXflgzpD0FcyKh0Mzx3rqCZKnHoJWV9xe1KXUJ5lx2JfcSHr/mhzS0PC/McAA==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.1.tgz",
+      "integrity": "sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==",
       "cpu": [
         "s390x"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3509,12 +3452,15 @@
       }
     },
     "node_modules/@rolldown/binding-linux-x64-gnu": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.1.5.tgz",
-      "integrity": "sha512-FjcpEKUyJygHgs1o50VYNvkt5+7Le/VEdYt0AkRpkL33MnyQfwr8l5mXwMmfmTbyMPr5vJLC+8/Gd9gXnwU1QQ==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.1.tgz",
+      "integrity": "sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==",
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3525,12 +3471,15 @@
       }
     },
     "node_modules/@rolldown/binding-linux-x64-musl": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.1.5.tgz",
-      "integrity": "sha512-Me+PfPI2TMeOQk0gYWfLQZtTktrmzbr8cDboqX83XKc7UrgAi55gF+2dUkWdxd19n55Essp2yeca+O9N5rBxHg==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.1.tgz",
+      "integrity": "sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==",
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MIT",
       "optional": true,
       "os": [
@@ -3541,9 +3490,9 @@
       }
     },
     "node_modules/@rolldown/binding-openharmony-arm64": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.1.5.tgz",
-      "integrity": "sha512-yc5WrLzXks6zCQfn9Oxr8pORKyl/pF+QjHmW/Qx3qu0oyrrNC+y2JLTU1E2rcWYAmzlnqngWXHQjy51VzW70Vw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.1.tgz",
+      "integrity": "sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==",
       "cpu": [
         "arm64"
       ],
@@ -3557,38 +3506,55 @@
       }
     },
     "node_modules/@rolldown/binding-wasm32-wasi": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.1.5.tgz",
-      "integrity": "sha512-VbQGPX2b4r48TAMIM2cjgluIM1HYutm4pcTEJsle7iEP7sB1dFqtPLBVbdLAZCxy1txCcPxf4QFf4v8uvltPqA==",
-      "cpu": [
-        "wasm32"
-      ],
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.2.1.tgz",
+      "integrity": "sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==",
       "license": "MIT",
       "optional": true,
       "dependencies": {
-        "@emnapi/core": "1.11.1",
-        "@emnapi/runtime": "1.11.1",
-        "@napi-rs/wasm-runtime": "^1.1.6"
+        "@emnapi/core": "2.0.0-alpha.3",
+        "@emnapi/runtime": "2.0.0-alpha.3",
+        "@napi-rs/wasm-runtime": "^1.2.0"
       },
       "engines": {
-        "node": "^20.19.0 || >=22.12.0"
+        "node": "^20.19.0 || ^22.13.0 || >=23.5.0"
       }
     },
     "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz",
-      "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==",
+      "version": "2.0.0-alpha.3",
+      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-2.0.0-alpha.3.tgz",
+      "integrity": "sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/wasi-threads": "2.0.1",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": {
+      "version": "2.0.0-alpha.3",
+      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-2.0.0-alpha.3.tgz",
+      "integrity": "sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==",
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-2.0.1.tgz",
+      "integrity": "sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==",
       "license": "MIT",
       "optional": true,
       "dependencies": {
-        "@emnapi/wasi-threads": "1.2.2",
         "tslib": "^2.4.0"
       }
     },
     "node_modules/@rolldown/binding-win32-arm64-msvc": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.1.5.tgz",
-      "integrity": "sha512-gHv82k63z4qpV5+Q1y/12KrK0ltWBukVDI8nZcbT7Tt/ZlOIVwppazneq0F93oDxTo3IgAMEDIoQh3E2n6mVsw==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.1.tgz",
+      "integrity": "sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==",
       "cpu": [
         "arm64"
       ],
@@ -3602,9 +3568,9 @@
       }
     },
     "node_modules/@rolldown/binding-win32-x64-msvc": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.1.5.tgz",
-      "integrity": "sha512-tTZuDBPw85tEN5PQi1pnEBzDy0Z49HtScLAbD5t6hyeU92A95pRWaSMw1GZZi/RwgSgUIl0xrSlXIT/9QzvYSA==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.1.tgz",
+      "integrity": "sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==",
       "cpu": [
         "x64"
       ],
@@ -3720,33 +3686,6 @@
         "node": ">=20"
       }
     },
-    "node_modules/@shikijs/primitive": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.3.0.tgz",
-      "integrity": "sha512-CPkz64PTa5diRW1ggzMZH9VM/du4RNChYgVtgqrFcgruvIybmCvySv8GkiHSczUHXYuuR8TdKEwFx+UnZMpgdg==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/types": "4.3.0",
-        "@shikijs/vscode-textmate": "^10.0.2",
-        "@types/hast": "^3.0.4"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
-    "node_modules/@shikijs/primitive/node_modules/@shikijs/types": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.3.0.tgz",
-      "integrity": "sha512-oc8b9U2SYvofKZk8e/737nIX0qwf6eV2vHFATeObAu7r+mUVpLs8Re0BmVkIjAWAYgkmG/CzLNo7rzuBzRu/wQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@shikijs/vscode-textmate": "^10.0.2",
-        "@types/hast": "^3.0.4"
-      },
-      "engines": {
-        "node": ">=20"
-      }
-    },
     "node_modules/@shikijs/themes": {
       "version": "4.3.1",
       "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.3.1.tgz",
@@ -3778,32 +3717,6 @@
       "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==",
       "license": "MIT"
     },
-    "node_modules/@tanstack/query-core": {
-      "version": "5.90.20",
-      "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.20.tgz",
-      "integrity": "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg==",
-      "license": "MIT",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/tannerlinsley"
-      }
-    },
-    "node_modules/@tanstack/react-query": {
-      "version": "5.90.21",
-      "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.21.tgz",
-      "integrity": "sha512-0Lu6y5t+tvlTJMTO7oh5NSpJfpg/5D41LlThfepTixPYkJ0sE2Jj0m0f6yYqujBwIXlId87e234+MxG3D3g7kg==",
-      "license": "MIT",
-      "dependencies": {
-        "@tanstack/query-core": "5.90.20"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/tannerlinsley"
-      },
-      "peerDependencies": {
-        "react": "^18 || ^19"
-      }
-    },
     "node_modules/@tybys/wasm-util": {
       "version": "0.10.3",
       "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.3.tgz",
@@ -3961,9 +3874,9 @@
       }
     },
     "node_modules/@types/react": {
-      "version": "19.2.15",
-      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz",
-      "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==",
+      "version": "19.2.18",
+      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz",
+      "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==",
       "license": "MIT",
       "peer": true,
       "dependencies": {
@@ -3971,9 +3884,9 @@
       }
     },
     "node_modules/@types/react-dom": {
-      "version": "19.2.3",
-      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz",
-      "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==",
+      "version": "19.2.4",
+      "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz",
+      "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==",
       "license": "MIT",
       "peer": true,
       "peerDependencies": {
@@ -4642,9 +4555,9 @@
       }
     },
     "node_modules/baseline-browser-mapping": {
-      "version": "2.10.40",
-      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz",
-      "integrity": "sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==",
+      "version": "2.11.12",
+      "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.12.tgz",
+      "integrity": "sha512-r7WnVImvVCeFpf2DOXfy41aPWzeNg3H/A2X4dKmy1QL0MSyyk/e7z8ihJ3N6Nn2PsdhkVlqnEfnUE4a05P2aTA==",
       "license": "Apache-2.0",
       "bin": {
         "baseline-browser-mapping": "dist/cli.cjs"
@@ -4694,15 +4607,15 @@
       "license": "ISC"
     },
     "node_modules/brace-expansion": {
-      "version": "5.0.9",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
-      "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
+      "version": "5.0.7",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
+      "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
       "license": "MIT",
       "dependencies": {
         "balanced-match": "^4.0.2"
       },
       "engines": {
-        "node": "20 || >=22"
+        "node": "18 || 20 || >=22"
       }
     },
     "node_modules/braces": {
@@ -4718,9 +4631,9 @@
       }
     },
     "node_modules/browserslist": {
-      "version": "4.28.4",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.4.tgz",
-      "integrity": "sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==",
+      "version": "4.28.7",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz",
+      "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==",
       "funding": [
         {
           "type": "opencollective",
@@ -4737,10 +4650,10 @@
       ],
       "license": "MIT",
       "dependencies": {
-        "baseline-browser-mapping": "^2.10.38",
-        "caniuse-lite": "^1.0.30001799",
-        "electron-to-chromium": "^1.5.376",
-        "node-releases": "^2.0.48",
+        "baseline-browser-mapping": "^2.10.44",
+        "caniuse-lite": "^1.0.30001806",
+        "electron-to-chromium": "^1.5.393",
+        "node-releases": "^2.0.51",
         "update-browserslist-db": "^1.2.3"
       },
       "bin": {
@@ -4801,9 +4714,9 @@
       }
     },
     "node_modules/caniuse-lite": {
-      "version": "1.0.30001799",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz",
-      "integrity": "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==",
+      "version": "1.0.30001806",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz",
+      "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==",
       "funding": [
         {
           "type": "opencollective",
@@ -5426,9 +5339,9 @@
       }
     },
     "node_modules/electron-to-chromium": {
-      "version": "1.5.379",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.379.tgz",
-      "integrity": "sha512-v/qV5aV5EUA2pGilzUCq5/eyOloZAqDZBu9UMBIzgPpLlprjSR6zswsWBTv0KpqxLGUAZEwhO95ZCt7srymNVA==",
+      "version": "1.5.399",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.399.tgz",
+      "integrity": "sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==",
       "license": "ISC"
     },
     "node_modules/emmet": {
@@ -5731,9 +5644,9 @@
       "optional": true
     },
     "node_modules/fast-uri": {
-      "version": "3.1.5",
-      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz",
-      "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==",
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz",
+      "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==",
       "dev": true,
       "funding": [
         {
@@ -6692,13 +6605,10 @@
       }
     },
     "node_modules/js-cookie": {
-      "version": "3.0.7",
-      "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.7.tgz",
-      "integrity": "sha512-z/wZZgDrkNV1eA0ULjM/F9/50Ya8fbzgKneSpoPsXSGd0KnpdtHfOZWK+GcwLk+EZbS4F9RBhU+K2RgzuDaItw==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=20"
-      }
+      "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": "10.0.0",
@@ -6707,9 +6617,9 @@
       "license": "MIT"
     },
     "node_modules/js-yaml": {
-      "version": "4.3.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
-      "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz",
+      "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==",
       "funding": [
         {
           "type": "github",
@@ -6987,6 +6897,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MPL-2.0",
       "optional": true,
       "os": [
@@ -7007,6 +6920,9 @@
       "cpu": [
         "arm64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MPL-2.0",
       "optional": true,
       "os": [
@@ -7027,6 +6943,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "glibc"
+      ],
       "license": "MPL-2.0",
       "optional": true,
       "os": [
@@ -7047,6 +6966,9 @@
       "cpu": [
         "x64"
       ],
+      "libc": [
+        "musl"
+      ],
       "license": "MPL-2.0",
       "optional": true,
       "os": [
@@ -8422,9 +8344,9 @@
       "license": "MIT"
     },
     "node_modules/node-releases": {
-      "version": "2.0.50",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.50.tgz",
-      "integrity": "sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==",
+      "version": "2.0.51",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz",
+      "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==",
       "license": "MIT",
       "engines": {
         "node": ">=18"
@@ -8814,9 +8736,9 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.5.23",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz",
-      "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==",
+      "version": "8.5.25",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.25.tgz",
+      "integrity": "sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==",
       "funding": [
         {
           "type": "opencollective",
@@ -8940,30 +8862,30 @@
       "license": "MIT"
     },
     "node_modules/react": {
-      "version": "19.2.4",
-      "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz",
-      "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==",
+      "version": "19.2.8",
+      "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
+      "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
       "license": "MIT",
       "engines": {
         "node": ">=0.10.0"
       }
     },
     "node_modules/react-dom": {
-      "version": "19.2.4",
-      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz",
-      "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==",
+      "version": "19.2.8",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
+      "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
       "license": "MIT",
       "dependencies": {
         "scheduler": "^0.27.0"
       },
       "peerDependencies": {
-        "react": "^19.2.4"
+        "react": "^19.2.8"
       }
     },
     "node_modules/react-icons": {
-      "version": "5.6.0",
-      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.6.0.tgz",
-      "integrity": "sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==",
+      "version": "5.7.0",
+      "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.7.0.tgz",
+      "integrity": "sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw==",
       "license": "MIT",
       "peerDependencies": {
         "react": "*"
@@ -9526,12 +9448,12 @@
       }
     },
     "node_modules/rolldown": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.1.5.tgz",
-      "integrity": "sha512-t9z29cJjXf/vxQ8dyhCSpt6H6aSwHTk8cT5I3iy6SMXuFpk5mB6PL6XfC8PCwrPTx93udwKUm9HRteAlTGBLiA==",
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.1.tgz",
+      "integrity": "sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==",
       "license": "MIT",
       "dependencies": {
-        "@oxc-project/types": "=0.139.0",
+        "@oxc-project/types": "=0.142.0",
         "@rolldown/pluginutils": "^1.0.0"
       },
       "bin": {
@@ -9541,21 +9463,21 @@
         "node": "^20.19.0 || >=22.12.0"
       },
       "optionalDependencies": {
-        "@rolldown/binding-android-arm64": "1.1.5",
-        "@rolldown/binding-darwin-arm64": "1.1.5",
-        "@rolldown/binding-darwin-x64": "1.1.5",
-        "@rolldown/binding-freebsd-x64": "1.1.5",
-        "@rolldown/binding-linux-arm-gnueabihf": "1.1.5",
-        "@rolldown/binding-linux-arm64-gnu": "1.1.5",
-        "@rolldown/binding-linux-arm64-musl": "1.1.5",
-        "@rolldown/binding-linux-ppc64-gnu": "1.1.5",
-        "@rolldown/binding-linux-s390x-gnu": "1.1.5",
-        "@rolldown/binding-linux-x64-gnu": "1.1.5",
-        "@rolldown/binding-linux-x64-musl": "1.1.5",
-        "@rolldown/binding-openharmony-arm64": "1.1.5",
-        "@rolldown/binding-wasm32-wasi": "1.1.5",
-        "@rolldown/binding-win32-arm64-msvc": "1.1.5",
-        "@rolldown/binding-win32-x64-msvc": "1.1.5"
+        "@rolldown/binding-android-arm64": "1.2.1",
+        "@rolldown/binding-darwin-arm64": "1.2.1",
+        "@rolldown/binding-darwin-x64": "1.2.1",
+        "@rolldown/binding-freebsd-x64": "1.2.1",
+        "@rolldown/binding-linux-arm-gnueabihf": "1.2.1",
+        "@rolldown/binding-linux-arm64-gnu": "1.2.1",
+        "@rolldown/binding-linux-arm64-musl": "1.2.1",
+        "@rolldown/binding-linux-ppc64-gnu": "1.2.1",
+        "@rolldown/binding-linux-s390x-gnu": "1.2.1",
+        "@rolldown/binding-linux-x64-gnu": "1.2.1",
+        "@rolldown/binding-linux-x64-musl": "1.2.1",
+        "@rolldown/binding-openharmony-arm64": "1.2.1",
+        "@rolldown/binding-wasm32-wasi": "1.2.1",
+        "@rolldown/binding-win32-arm64-msvc": "1.2.1",
+        "@rolldown/binding-win32-x64-msvc": "1.2.1"
       }
     },
     "node_modules/satteri": {
@@ -9962,21 +9884,21 @@
       }
     },
     "node_modules/tldts": {
-      "version": "7.0.25",
-      "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.25.tgz",
-      "integrity": "sha512-keinCnPbwXEUG3ilrWQZU+CqcTTzHq9m2HhoUP2l7Xmi8l1LuijAXLpAJ5zRW+ifKTNscs4NdCkfkDCBYm352w==",
+      "version": "7.4.10",
+      "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz",
+      "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==",
       "license": "MIT",
       "dependencies": {
-        "tldts-core": "^7.0.25"
+        "tldts-core": "^7.4.10"
       },
       "bin": {
         "tldts": "bin/cli.js"
       }
     },
     "node_modules/tldts-core": {
-      "version": "7.0.25",
-      "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.25.tgz",
-      "integrity": "sha512-ZjCZK0rppSBu7rjHYDYsEaMOIbbT+nWF57hKkv4IUmZWBNrBWBOjIElc0mKRgLM8bm7x/BBlof6t2gi/Oq/Asw==",
+      "version": "7.4.10",
+      "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz",
+      "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==",
       "license": "MIT"
     },
     "node_modules/tmp": {
@@ -10550,15 +10472,15 @@
       }
     },
     "node_modules/vite": {
-      "version": "8.1.5",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-8.1.5.tgz",
-      "integrity": "sha512-7ULLwsCdYx/nRyrpiEwvqb5TFHrMVZyBt+rg/OAXT7rgj/z+DtTDyKFeLAdDkubDVDKD8jOsndmy7m55XcfUsw==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.0.tgz",
+      "integrity": "sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==",
       "license": "MIT",
       "dependencies": {
-        "lightningcss": "^1.32.0",
+        "lightningcss": "^1.33.0",
         "picomatch": "^4.0.5",
-        "postcss": "^8.5.17",
-        "rolldown": "~1.1.5",
+        "postcss": "^8.5.23",
+        "rolldown": "~1.2.0",
         "tinyglobby": "^0.2.17"
       },
       "bin": {
@@ -10575,7 +10497,7 @@
       },
       "peerDependencies": {
         "@types/node": "^20.19.0 || >=22.12.0",
-        "@vitejs/devtools": "^0.3.0",
+        "@vitejs/devtools": "^0.4.0",
         "esbuild": "^0.27.0 || ^0.28.0",
         "jiti": ">=1.21.0",
         "less": "^4.0.0",
diff --git a/src/components/CustomSidebar.astro b/src/components/CustomSidebar.astro
index 6ab218ca8..954f822f7 100644
--- a/src/components/CustomSidebar.astro
+++ b/src/components/CustomSidebar.astro
@@ -77,9 +77,9 @@ import KapaLauncher from './KapaLauncher.astro';
 			'api': 'API',
 		};
 
-		// Detect Apple platforms once so the Ask AI kbd reads ⌘+I on Macs and
-		// Ctrl+I elsewhere. Mirrors KapaChatLauncher.tsx which binds the same
-		// shortcut via keymatch's `CmdOrCtrl+I`.
+// Detect Apple platforms once so the Ask AI kbd reads ⌘+I on Macs and
+		// Ctrl+I elsewhere. Mirrors KapaLauncher.astro which binds the same
+		// shortcut for opening the Kapa Website Widget.
 		var isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform || '');
 		var modKey = isMac ? '\u2318' : 'Ctrl';
 
@@ -143,9 +143,9 @@ import KapaLauncher from './KapaLauncher.astro';
 				+ ''
 				+ 'Ask AI'
 				+ '';
-			askAi.addEventListener('click', function () {
-				// openPanel() in KapaChatLauncher reads the live search input and
-				// closes the search dialog itself, so we just route the click.
+askAi.addEventListener('click', function () {
+				// KapaLauncher reads the live search input and closes the search
+				// dialog itself, then opens the widget with that query prefilled.
 				var kapaBtn = document.querySelector('.warp-kapa-button');
 				if (kapaBtn) kapaBtn.click();
 			});
diff --git a/src/components/KapaChatLauncher.css b/src/components/KapaChatLauncher.css
index 3aca6dc6c..e33362c08 100644
--- a/src/components/KapaChatLauncher.css
+++ b/src/components/KapaChatLauncher.css
@@ -200,6 +200,39 @@
 	padding: 0.1rem 0.3rem;
 }
 
+.sl-kapa-codeblock {
+	position: relative;
+	margin: 0.85rem 0;
+	max-width: 100%;
+}
+
+.sl-kapa-codeblock .copy {
+	position: absolute;
+	top: 0.5rem;
+	right: 0.5rem;
+	z-index: 1;
+}
+
+.sl-kapa-codeblock pre {
+	margin: 0;
+	padding: var(--ec-codePadBlk) var(--ec-codePadInl);
+	overflow-x: auto;
+	overflow-y: hidden;
+	white-space: pre;
+}
+
+.sl-kapa-codeblock code {
+	font-family: var(--__sl-font-mono, 'JetBrains Mono', 'SFMono-Regular', monospace);
+	display: block;
+	min-width: max-content;
+}
+
+/* Shiki separates `.line` spans with literal newline characters, which
+   `white-space: pre` (set on the pre above) already renders as line
+   breaks. The spans must stay inline — giving them `display: block`
+   would add a second break per line and double-space the code. */
+
+
 .sl-kapa-thinking {
 	display: flex;
 	align-items: center;
@@ -249,18 +282,73 @@
 
 .sl-kapa-feedback {
 	display: flex;
+	flex-wrap: wrap;
+	align-items: center;
 	gap: 0.5rem;
 	margin-top: 0.875rem;
 }
+.sl-kapa-feedback__handoff {
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	height: 2.25rem;
+	padding: 0 0.75rem;
+	border: 1px solid var(--sl-color-gray-5);
+	border-radius: var(--sl-radius-sm);
+	background: var(--sl-color-black);
+	color: var(--sl-color-gray-1);
+	font: inherit;
+	font-size: var(--sl-text-xs);
+	font-weight: 500;
+	cursor: pointer;
+	transition:
+		border-color 0.15s ease,
+		background-color 0.15s ease,
+		color 0.15s ease;
+}
+
+.sl-kapa-feedback__handoff:hover {
+	border-color: var(--warp-control-border-hover);
+	background: var(--warp-control-bg-hover);
+	color: var(--sl-color-white);
+}
+
+.sl-kapa-feedback__handoff:focus-visible {
+	outline: 2px solid var(--sl-color-accent-high);
+	outline-offset: 2px;
+}
+.sl-kapa-feedback__handoff--submit {
+	background: var(--sl-color-text-accent);
+	border-color: var(--sl-color-text-accent);
+	color: var(--sl-color-black);
+}
+
+.sl-kapa-feedback__handoff--submit:hover:not(:disabled) {
+	border-color: color-mix(in srgb, var(--sl-color-text-accent), var(--sl-color-white) 18%);
+	background: color-mix(in srgb, var(--sl-color-text-accent), var(--sl-color-white) 8%);
+	color: var(--sl-color-black);
+}
+
+.sl-kapa-feedback__handoff--ghost {
+	background: transparent;
+}
 
 .sl-kapa-error {
-	border: 1px solid color-mix(in srgb, #ef4444, var(--sl-color-black) 35%);
-	background: rgb(127 29 29 / 0.2);
-	color: #fecaca;
+	border: 1px solid rgb(248 113 113 / 0.8);
+	background: rgb(254 226 226 / 0.9);
+	color: #991b1b;
 	border-radius: var(--sl-radius-lg);
 	padding: 0.875rem 1rem;
 }
 
+@media (prefers-color-scheme: dark) {
+	.sl-kapa-error {
+		border: 1px solid color-mix(in srgb, #ef4444, var(--sl-color-black) 35%);
+		background: rgb(127 29 29 / 0.2);
+		color: #fecaca;
+	}
+}
+
 .sl-kapa-panel__footer {
 	position: relative;
 	padding: 1rem;
@@ -337,6 +425,228 @@
 	opacity: 0.5;
 	cursor: not-allowed;
 }
+.sl-kapa-handoff-inline {
+	margin-top: 0.75rem;
+	padding-top: 0.75rem;
+	border-top: 1px solid var(--sl-color-gray-5);
+	display: flex;
+	flex-direction: column;
+	gap: 0.5rem;
+}
+
+.sl-kapa-handoff-inline label {
+	font-size: var(--sl-text-xs);
+	font-weight: 600;
+	color: var(--sl-color-gray-2);
+}
+
+.sl-kapa-handoff-inline__row {
+	display: grid;
+	grid-template-columns: minmax(0, 1fr) auto auto;
+	gap: 0.5rem;
+}
+
+.sl-kapa-handoff-inline input {
+	width: 100%;
+	min-width: 0;
+	height: 2.25rem;
+	border: 1px solid var(--sl-color-gray-5);
+	border-radius: var(--sl-radius-sm);
+	background: var(--sl-color-black);
+	color: var(--sl-color-white);
+	padding: 0 0.625rem;
+	font: inherit;
+	font-size: var(--sl-text-sm);
+}
+
+.sl-kapa-handoff-inline input::placeholder {
+	color: var(--sl-color-gray-3);
+}
+
+.sl-kapa-handoff-inline input:focus-visible {
+	outline: 2px solid var(--sl-color-accent-high);
+	outline-offset: 2px;
+}
+
+.sl-kapa-handoff-inline__status {
+	margin: 0;
+	font-size: var(--sl-text-xs);
+	line-height: 1.4;
+}
+
+.sl-kapa-handoff-inline__status--success {
+	color: #14532d;
+	background: rgb(220 252 231 / 0.9);
+	border: 1px solid rgb(74 222 128 / 0.7);
+	padding: 0.375rem 0.5rem;
+	border-radius: var(--sl-radius-sm);
+}
+
+.sl-kapa-handoff-inline__status--error {
+	color: #b91c1c;
+	background: rgb(254 226 226 / 0.9);
+	border: 1px solid rgb(248 113 113 / 0.8);
+	padding: 0.375rem 0.5rem;
+	border-radius: var(--sl-radius-sm);
+}
+
+.sl-kapa-handoff-inline__status a {
+	color: inherit;
+	text-decoration: underline;
+}
+
+@media (prefers-color-scheme: dark) {
+	.sl-kapa-handoff-inline__status--success {
+		color: #86efac;
+		background: rgb(20 83 45 / 0.35);
+		border-color: rgb(74 222 128 / 0.45);
+	}
+	.sl-kapa-handoff-inline__status--error {
+		color: #fecaca;
+		background: rgb(127 29 29 / 0.3);
+		border-color: rgb(248 113 113 / 0.5);
+	}
+}
+
+.sl-kapa-handoff {
+	margin-top: 0.75rem;
+	display: flex;
+	flex-direction: column;
+	gap: 0.625rem;
+}
+
+.sl-kapa-handoff__toggle {
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	gap: 0.5rem;
+	width: 100%;
+	height: 2.5rem;
+	padding: 0 0.875rem;
+	border: 1px solid var(--sl-color-gray-5);
+	border-radius: var(--sl-radius-sm);
+	background: var(--sl-color-black);
+	color: var(--sl-color-gray-1);
+	font: inherit;
+	font-size: var(--sl-text-sm);
+	font-weight: 500;
+	cursor: pointer;
+	transition:
+		border-color 0.15s ease,
+		background-color 0.15s ease,
+		color 0.15s ease;
+}
+
+.sl-kapa-handoff__toggle svg {
+	width: 0.95rem;
+	height: 0.95rem;
+	flex: none;
+}
+
+.sl-kapa-handoff__toggle:hover {
+	border-color: var(--warp-control-border-hover);
+	background: var(--warp-control-bg-hover);
+	color: var(--sl-color-white);
+}
+
+.sl-kapa-handoff__toggle:focus-visible {
+	outline: 2px solid var(--sl-color-accent-high);
+	outline-offset: 2px;
+}
+
+.sl-kapa-handoff__form {
+	display: flex;
+	flex-direction: column;
+	gap: 0.5rem;
+	padding: 0.75rem;
+	border: 1px solid var(--sl-color-gray-5);
+	border-radius: var(--sl-radius-lg);
+	background: color-mix(in srgb, var(--sl-color-black), var(--sl-color-gray-6) 28%);
+}
+
+.sl-kapa-handoff__form label {
+	display: flex;
+	flex-direction: column;
+	gap: 0.25rem;
+}
+
+.sl-kapa-handoff__form label span {
+	font-size: var(--sl-text-2xs);
+	color: var(--sl-color-gray-3);
+}
+
+.sl-kapa-handoff__form input,
+.sl-kapa-handoff__form textarea {
+	width: 100%;
+	border: 1px solid var(--sl-color-gray-5);
+	border-radius: var(--sl-radius-sm);
+	background: var(--sl-color-black);
+	color: var(--sl-color-white);
+	padding: 0.5rem 0.625rem;
+	font: inherit;
+	font-size: var(--sl-text-sm);
+}
+
+.sl-kapa-handoff__form textarea {
+	resize: vertical;
+	min-height: 4rem;
+}
+
+.sl-kapa-handoff__form input::placeholder,
+.sl-kapa-handoff__form textarea::placeholder {
+	color: var(--sl-color-gray-3);
+}
+
+.sl-kapa-handoff__form input:focus-visible,
+.sl-kapa-handoff__form textarea:focus-visible {
+	outline: 2px solid var(--sl-color-accent-high);
+	outline-offset: 2px;
+}
+
+.sl-kapa-handoff__submit {
+	margin-top: 0.25rem;
+	height: 2.5rem;
+	border: 1px solid var(--sl-color-text-accent);
+	border-radius: var(--sl-radius-sm);
+	background: var(--sl-color-text-accent);
+	color: var(--sl-color-black);
+	font: inherit;
+	font-size: var(--sl-text-sm);
+	font-weight: 600;
+	cursor: pointer;
+	transition:
+		border-color 0.15s ease,
+		background-color 0.15s ease;
+}
+
+.sl-kapa-handoff__submit:hover:not(:disabled) {
+	border-color: color-mix(in srgb, var(--sl-color-text-accent), var(--sl-color-white) 18%);
+	background: color-mix(in srgb, var(--sl-color-text-accent), var(--sl-color-white) 8%);
+}
+
+.sl-kapa-handoff__submit:focus-visible {
+	outline: 2px solid var(--sl-color-accent-high);
+	outline-offset: 2px;
+}
+
+.sl-kapa-handoff__submit:disabled {
+	opacity: 0.55;
+	cursor: not-allowed;
+}
+
+.sl-kapa-handoff__status {
+	margin: 0;
+	font-size: var(--sl-text-xs);
+	line-height: 1.4;
+}
+
+.sl-kapa-handoff__status--success {
+	color: #86efac;
+}
+
+.sl-kapa-handoff__status--error {
+	color: #fecaca;
+}
 
 /* Hide the reCAPTCHA badge */
 .grecaptcha-badge {
diff --git a/src/components/KapaChatLauncher.mount.tsx b/src/components/KapaChatLauncher.mount.tsx
deleted file mode 100644
index e69de29bb..000000000
diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx
index d4e1bcb9b..fdd5a540b 100644
--- a/src/components/KapaChatLauncher.tsx
+++ b/src/components/KapaChatLauncher.tsx
@@ -1,8 +1,8 @@
-import type { FormEvent, MouseEvent } from 'react';
+import type { FormEvent, MouseEvent, ReactElement, ReactNode } from 'react';
 import * as Popover from '@radix-ui/react-popover';
-import { useEffect, useMemo, useRef, useState } from 'react';
+import { isValidElement, useEffect, useMemo, useRef, useState } from 'react';
 import { KapaProvider, useChat } from '@kapaai/react-sdk';
-import { PUBLIC_KAPA_INTEGRATION_ID } from 'astro:env/client';
+import { PUBLIC_KAPA_INTEGRATION_ID, PUBLIC_KAPA_PROJECT_ID } from 'astro:env/client';
 import { isMac, keymatch } from 'keymatch';
 import ReactMarkdown from 'react-markdown';
 import {
@@ -18,10 +18,315 @@ import {
 import './KapaChatLauncher.css';
 
 const integrationId = PUBLIC_KAPA_INTEGRATION_ID;
+const projectId = PUBLIC_KAPA_PROJECT_ID?.trim() || '';
 const title = 'Ask Warp';
 const welcomeMessage = 'What do you want to know about Warp?';
+const uncertaintyThreshold = 0.15;
+const conversationLengthThreshold = 3;
+const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
 
 type FeedbackReaction = 'upvote' | 'downvote';
+type GenericRecord = Record;
+type HandoffApiSuccess = {
+	message?: string;
+};
+
+function isObject(value: unknown): value is GenericRecord {
+	return typeof value === 'object' && value !== null;
+}
+
+function readNumberField(record: GenericRecord, key: string) {
+	const value = record[key];
+	if (typeof value === 'number' && Number.isFinite(value)) return value;
+	if (typeof value === 'string') {
+		const parsed = Number(value);
+		if (Number.isFinite(parsed)) return parsed;
+	}
+	return null;
+}
+
+function readBooleanField(record: GenericRecord, key: string) {
+	const value = record[key];
+	if (typeof value === 'boolean') return value;
+	if (typeof value === 'string') {
+		const normalized = value.trim().toLowerCase();
+		if (normalized === 'true') return true;
+		if (normalized === 'false') return false;
+	}
+	return null;
+}
+
+function getUncertaintyScore(metadata: unknown) {
+	if (!isObject(metadata)) return null;
+	return (
+		readNumberField(metadata, 'uncertainty') ??
+		readNumberField(metadata, 'uncertainty_score') ??
+		readNumberField(metadata, 'uncertaintyScore')
+	);
+}
+
+function isAnswerUncertain(metadata: unknown) {
+	if (!isObject(metadata)) return false;
+	const flag =
+		readBooleanField(metadata, 'is_uncertain') ??
+		readBooleanField(metadata, 'isUncertain');
+	if (flag === true) return true;
+	const score = getUncertaintyScore(metadata);
+	return score !== null ? score >= uncertaintyThreshold : false;
+}
+
+function isValidEmailAddress(value: string) {
+	return emailPattern.test(value.trim());
+}
+
+
+const CHAT_LANGUAGE_ALIASES: Record = {
+	shell: 'bash',
+	zsh: 'bash',
+	pwsh: 'powershell',
+	plaintext: 'text',
+};
+
+function normalizeChatLanguage(language: string): string {
+	return CHAT_LANGUAGE_ALIASES[language.toLowerCase()] ?? language.toLowerCase();
+}
+
+function inferLanguageFromCode(codeText: string, fallbackLanguage: string): string {
+	if (fallbackLanguage !== 'text') return fallbackLanguage;
+	const sample = codeText.trim();
+	if (!sample) return fallbackLanguage;
+	const commandLikePattern =
+		/^(sudo|apt|apt-get|dnf|yum|zypper|pacman|curl|wget|git|npm|pnpm|yarn|cargo|python|node|brew|sh|bash)\b/m;
+	if (commandLikePattern.test(sample)) return 'bash';
+	return fallbackLanguage;
+}
+
+function escapeHtml(value: string): string {
+	return value.replace(/&/g, '&').replace(//g, '>');
+}
+
+type MarkdownCodeProps = { className?: string; children?: ReactNode };
+
+// react-markdown v9+ no longer passes an `inline` flag to the `code`
+// component. The reliable way to tell fenced blocks apart from inline
+// code is nesting: fenced blocks are always rendered as 
, so
+// we intercept `pre` (block) and leave bare `code` (inline) untouched.
+function extractCodeElement(children: ReactNode): ReactElement | null {
+	const items = Array.isArray(children) ? children : [children];
+	for (const item of items) {
+		if (isValidElement(item)) return item;
+	}
+	return null;
+}
+
+function markdownChildrenToText(children: ReactNode): string {
+	return (Array.isArray(children) ? children.join('') : String(children ?? '')).replace(/\n$/, '');
+}
+
+const highlightCache = new Map();
+const highlightInFlight = new Map>();
+let highlightRequestQueue: Promise = Promise.resolve();
+type ShikiModule = typeof import('shiki');
+type ShikiHighlighter = Awaited>;
+let shikiHighlighterPromise: Promise | null = null;
+const SHIKI_LANGUAGES = new Set([
+	'bash',
+	'powershell',
+	'json',
+	'javascript',
+	'typescript',
+	'tsx',
+	'jsx',
+	'python',
+	'go',
+	'rust',
+	'yaml',
+	'markdown',
+	'html',
+	'css',
+	'text',
+]);
+
+async function getShikiHighlighter(): Promise {
+	if (!shikiHighlighterPromise) {
+		shikiHighlighterPromise = import('shiki/bundle/full').then(({ createHighlighter }) =>
+			createHighlighter({
+				themes: ['github-light', 'github-dark'],
+				langs: [...SHIKI_LANGUAGES],
+			})
+		);
+	}
+	return shikiHighlighterPromise;
+}
+
+async function requestHighlightedPre({
+	code,
+	language,
+	theme,
+}: {
+	code: string;
+	language: string;
+	theme: 'dark' | 'light';
+}): Promise {
+	const cacheKey = `${theme}:${language}:${code}`;
+	if (highlightCache.has(cacheKey)) {
+		return highlightCache.get(cacheKey) ?? null;
+	}
+	const existing = highlightInFlight.get(cacheKey);
+	if (existing) return existing;
+
+	const requestPromise = new Promise((resolve, reject) => {
+		const run = async () => {
+			try {
+				const highlighter = await getShikiHighlighter();
+				const shikiLanguage = SHIKI_LANGUAGES.has(language) ? language : 'text';
+				const html = highlighter.codeToHtml(code, {
+					lang: shikiLanguage,
+					theme: theme === 'light' ? 'github-light' : 'github-dark',
+				});
+				const preMatch = html.match(/]*>[\s\S]*?<\/pre>/i);
+				const preHtml = preMatch?.[0] ?? null;
+				highlightCache.set(cacheKey, preHtml);
+				resolve(preHtml);
+			} catch (error) {
+				reject(error);
+			}
+		};
+
+		highlightRequestQueue = highlightRequestQueue
+			.then(run)
+			.catch(() => run())
+			.then(() => undefined, () => undefined);
+	});
+
+	highlightInFlight.set(cacheKey, requestPromise);
+	requestPromise.finally(() => {
+		highlightInFlight.delete(cacheKey);
+	});
+	return requestPromise;
+}
+
+function ChatCodeBlock({
+	className,
+	codeText,
+	copyKey,
+	copiedCodeKey,
+	onCopy,
+	deferHighlight,
+}: {
+	className?: string;
+	codeText: string;
+	copyKey: string;
+	copiedCodeKey: string | null;
+	onCopy: () => void;
+	deferHighlight?: boolean;
+}) {
+	const language = className?.replace('language-', '') ?? 'text';
+	const normalizedLanguage = inferLanguageFromCode(
+		codeText,
+		normalizeChatLanguage(language)
+	);
+	const isTerminalLanguage = ['bash', 'sh', 'shell', 'zsh', 'powershell'].includes(normalizedLanguage);
+	const [highlighted, setHighlighted] = useState<{ key: string; preHtml: string } | null>(null);
+	const [isDarkTheme, setIsDarkTheme] = useState(true);
+
+	useEffect(() => {
+		const root = document.documentElement;
+		const updateTheme = () => {
+			const explicitTheme = root.dataset.theme;
+			if (explicitTheme === 'light') {
+				setIsDarkTheme(false);
+				return;
+			}
+			if (explicitTheme === 'dark') {
+				setIsDarkTheme(true);
+				return;
+			}
+			setIsDarkTheme(window.matchMedia('(prefers-color-scheme: dark)').matches);
+		};
+
+		updateTheme();
+		const observer = new MutationObserver(updateTheme);
+		observer.observe(root, { attributes: true, attributeFilter: ['data-theme'] });
+		return () => observer.disconnect();
+	}, []);
+
+	const theme = isDarkTheme ? 'dark' : 'light';
+	const highlightKey = `${theme}:${normalizedLanguage}:${codeText}`;
+
+	useEffect(() => {
+		// While the answer is still streaming, the code text changes on every
+		// token. Requesting a highlight per token causes the block to churn
+		// between plaintext and highlighted DOM (visible flicker), so wait
+		// until streaming settles and highlight the final text once.
+		if (deferHighlight) return;
+		const controller = new AbortController();
+		(async (): Promise => {
+			try {
+				const preHtml = await requestHighlightedPre({
+					code: codeText,
+					language: normalizedLanguage,
+					theme,
+				});
+				if (!controller.signal.aborted && preHtml) {
+					setHighlighted({ key: `${theme}:${normalizedLanguage}:${codeText}`, preHtml });
+				}
+			} catch (error) {
+				if (!controller.signal.aborted) {
+					console.warn('[kapa-chat] code highlighting failed; using plaintext fallback', error);
+				}
+			}
+		})();
+
+		return () => {
+			controller.abort();
+		};
+	}, [codeText, deferHighlight, theme, normalizedLanguage]);
+
+	// Only use highlighted HTML that matches the *current* code text and
+	// theme; otherwise render the plaintext fallback. This prevents stale
+	// highlighted content from flashing while new text is streaming in.
+	const highlightedPreHtml = highlighted?.key === highlightKey ? highlighted.preHtml : null;
+
+	return (
+		
+
+
+ + {isTerminalLanguage ? Terminal window : null} +
+ {highlightedPreHtml ? ( +
+ ) : ( +
+						
+					
+ )} +
+
{copiedCodeKey === copyKey ? 'Copied!' : ''}
+ +
+
+
+ ); +} function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversation }: { title: string; @@ -33,6 +338,14 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio const [query, setQuery] = useState(''); const [hasStartedConversation, setHasStartedConversation] = useState(false); const [isAppleDevice, setIsAppleDevice] = useState(false); + const [storedThreadId, setStoredThreadId] = useState(null); + const [downvotedAnswerIds, setDownvotedAnswerIds] = useState>({}); + const [handoffEmailInput, setHandoffEmailInput] = useState(''); + const [handoffQaId, setHandoffQaId] = useState(null); + const [handoffErrorMessage, setHandoffErrorMessage] = useState(null); + const [handoffSuccessMessage, setHandoffSuccessMessage] = useState(null); + const [isSubmittingHandoff, setIsSubmittingHandoff] = useState(false); + const [copiedCodeKey, setCopiedCodeKey] = useState(null); const messagesRef = useRef(null); const dialogRef = useRef(null); const triggerRef = useRef(null); @@ -45,16 +358,54 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio isGeneratingAnswer, isPreparingAnswer, submitQuery, + threadId, } = useChat(); + useEffect(() => { setIsAppleDevice(isMac()); }, []); + useEffect(() => { + const savedThreadId = localStorage.getItem('warp_docs_kapa_thread_id'); + if (savedThreadId) { + setStoredThreadId(savedThreadId); + } + }, []); + + useEffect(() => { + if (!threadId) return; + setStoredThreadId(threadId); + localStorage.setItem('warp_docs_kapa_thread_id', threadId); + }, [threadId]); + useEffect(() => { if (!isOpen || !messagesRef.current) return; messagesRef.current.scrollTop = messagesRef.current.scrollHeight; }, [conversation.length, isOpen]); + useEffect(() => { + if (!isOpen || !messagesRef.current) return; + if (!isGeneratingAnswer && !isPreparingAnswer) return; + messagesRef.current.scrollTop = messagesRef.current.scrollHeight; + }, [conversation, isGeneratingAnswer, isOpen, isPreparingAnswer]); + + useEffect(() => { + if (!handoffQaId || !isOpen) return; + const frame = window.requestAnimationFrame(() => { + const inlineForm = document.getElementById(`sl-kapa-handoff-inline-${handoffQaId}`); + if (!inlineForm) return; + inlineForm.scrollIntoView({ + behavior: 'smooth', + block: 'nearest', + }); + const emailInput = inlineForm.querySelector('input[type="email"]'); + emailInput?.focus(); + }); + return () => { + window.cancelAnimationFrame(frame); + }; + }, [handoffQaId, isOpen, conversation.length]); + useEffect(() => { const dialog = dialogRef.current; if (!dialog) return; @@ -107,6 +458,7 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio const submit = () => { const value = query.trim(); if (!value || isBusy) return; + closeHandoffForm(); submitQuery(value); setHasStartedConversation(true); setQuery(''); @@ -119,6 +471,120 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio const feedback = (questionAnswerId: string, reaction: FeedbackReaction) => { addFeedback(questionAnswerId, reaction); + if (reaction === 'downvote') { + setDownvotedAnswerIds((current) => ({ ...current, [questionAnswerId]: true })); + } + }; + + const isDownvoted = (qaId: string | null | undefined, reaction: string | null | undefined) => { + if (!qaId) return false; + return reaction === 'downvote' || downvotedAnswerIds[qaId] === true; + }; + + const shouldShowHandoffForAnswer = (qa: { + id?: string | null; + answer?: string | null; + metadata?: unknown; + reaction?: string | null; + }) => { + if (!qa.answer?.trim()) return false; + const conversationLengthTriggered = conversation.length >= conversationLengthThreshold; + const downvoteTriggered = isDownvoted(qa.id ?? null, qa.reaction ?? null); + const uncertaintyTriggered = isAnswerUncertain(qa.metadata); + return conversationLengthTriggered || downvoteTriggered || uncertaintyTriggered; + }; + + const buildConversationTranscript = () => { + if (!conversation.length) return 'No conversation history yet.'; + return conversation + .map((qa, index) => { + const sources = qa.sources?.length + ? `\nSources:\n${qa.sources.map((source) => `- ${source.title}: ${source.source_url}`).join('\n')}` + : ''; + return `Q${index + 1}: ${qa.question}\nA${index + 1}: ${qa.answer || '(no answer generated yet)'}${sources}`; + }) + .join('\n\n'); + }; + + const buildConversationLink = (currentThreadId: string | null) => { + if (!projectId || !currentThreadId) return null; + return `https://app.kapa.ai/${projectId}/conversations/${currentThreadId}`; + }; + + const copyCodeBlock = async (code: string, copyKey: string) => { + try { + await navigator.clipboard.writeText(code); + setCopiedCodeKey(copyKey); + window.setTimeout(() => { + setCopiedCodeKey((currentKey) => (currentKey === copyKey ? null : currentKey)); + }, 1400); + } catch { + setCopiedCodeKey(null); + } + }; + const openHandoffForm = (qaId: string) => { + setHandoffQaId(qaId); + setHandoffErrorMessage(null); + setHandoffSuccessMessage(null); + }; + + const closeHandoffForm = () => { + setHandoffQaId(null); + setHandoffErrorMessage(null); + setHandoffSuccessMessage(null); + }; + + const submitSupportHandoff = async (qa: { id?: string | null; question?: string }) => { + const userEmail = handoffEmailInput.trim().toLowerCase(); + if (!isValidEmailAddress(userEmail)) { + setHandoffErrorMessage('Enter a valid email address to continue.'); + return; + } + const localStorageThreadId = localStorage.getItem('warp_docs_kapa_thread_id'); + const activeThreadId = threadId || storedThreadId || localStorageThreadId; + if (!activeThreadId) { + setHandoffErrorMessage('Missing Kapa thread context; please send another message and try again.'); + return; + } + + const question = qa.question?.trim(); + if (!question) { + setHandoffErrorMessage('Missing question context for handoff.'); + return; + } + + const conversationLink = buildConversationLink(activeThreadId); + + setIsSubmittingHandoff(true); + setHandoffErrorMessage(null); + setHandoffSuccessMessage(null); + try { + const response = await fetch('/api/support-handoff', { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ + user_email: userEmail, + question, + page_url: window.location.href, + conversation_transcript: buildConversationTranscript(), + kapa_project_id: projectId || null, + kapa_thread_id: activeThreadId, + kapa_conversation_url: conversationLink || null, + }), + }); + const payload: HandoffApiSuccess & { message?: string } = await response.json().catch(() => ({})); + if (!response.ok) { + setHandoffErrorMessage(payload.message || 'Could not create support ticket. Please try again.'); + return; + } + setHandoffSuccessMessage(payload.message || 'Support ticket created successfully.'); + } catch { + setHandoffErrorMessage('Could not reach support handoff service. Please try again.'); + } finally { + setIsSubmittingHandoff(false); + } }; const openPanel = () => { @@ -137,9 +603,10 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio // Legacy fallback: earlier callers stashed the query on window before // triggering us. Kept as a belt-and-braces guard in case any path // still uses it. - if (!pendingQuery && (window as any).__warpAskAiQuery) { - pendingQuery = (window as any).__warpAskAiQuery; - delete (window as any).__warpAskAiQuery; + const windowWithAskQuery = window as Window & { __warpAskAiQuery?: string }; + if (!pendingQuery && windowWithAskQuery.__warpAskAiQuery) { + pendingQuery = windowWithAskQuery.__warpAskAiQuery; + delete windowWithAskQuery.__warpAskAiQuery; } setIsOpen(true); @@ -236,7 +703,44 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio
{qa.question}
{qa.answer ? ( - {qa.answer} + ; inline code + // arrives as a bare . react-markdown v9+ removed the + // `inline` prop, so nesting is the only reliable signal. + pre({ children }) { + const codeElement = extractCodeElement(children); + if (!codeElement) { + return
{children}
; + } + const codeClassName = + typeof codeElement.props.className === 'string' + ? codeElement.props.className + : undefined; + const codeText = markdownChildrenToText(codeElement.props.children); + const language = codeClassName?.replace('language-', '') ?? 'text'; + const qaKey = qa.id ?? qa.question ?? 'qa'; + const isStreamingAnswer = + isBusy && conversation[conversation.length - 1]?.id === qa.id; + const copyKey = `${qaKey}:${language}:${codeText.slice(0, 64)}`; + return ( + void copyCodeBlock(codeText, copyKey)} + /> + ); + }, + code({ className, children }) { + return {children}; + }, + }} + > + {qa.answer} +
) : (
+ ) : null} + {handoffQaId === qa.id && !isBusy && shouldShowHandoffForAnswer(qa) ? ( +
+ +
{ + event.preventDefault(); + void submitSupportHandoff(qa); + }} + > + setHandoffEmailInput(event.target.value)} + required + /> + + +
+ {handoffErrorMessage ? ( +

+ {handoffErrorMessage} +

+ ) : null} + {handoffSuccessMessage ? ( +

+ {handoffSuccessMessage} +

+ ) : null}
) : null}
@@ -353,7 +917,13 @@ export default function KapaChatLauncher({ autoOpen = false }: { autoOpen?: bool const [sessionAutoOpen, setSessionAutoOpen] = useState(autoOpen); const callbacks = useMemo( () => ({ - askAI: {}, + askAI: { + onAnswerGenerationCompleted: (data: { threadId?: string | null }) => { + if (data.threadId) { + localStorage.setItem('warp_docs_kapa_thread_id', data.threadId); + } + }, + }, }), [] ); diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx index 02f8464ad..6aa4886d2 100644 --- a/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx +++ b/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx @@ -93,6 +93,54 @@ To try and resolve the issue of Warp not rendering a window, rename the SQLite d * Agents do not have up-to-date information on several commands’ completion specs * Agent Mode works better with Warp's default prompt settings, where the prompt starts on a new line, than it does with a same-line prompt. If you are using the same-line prompt, the cursor will jump from the end of the single line to the start of the input box when you switch to Agent Mode. +## MCP + +### MCP OAuth 2.0 and 2.1 authentication may fail with certain servers + +Warp's direct Streamable HTTP and SSE connections do not currently interoperate with every MCP server's OAuth 2.0 or 2.1 implementation. You may encounter one or more of these symptoms: + +* **Authorization page does not open** - The browser never opens after dynamic client registration (DCR). +* **OAuth callback fails** - Warp does not process the browser redirect and logs `No active OAuth flow found`. +* **Dynamic client registration fails** - The server rejects registration with `invalid_redirect_uri`. +* **Resource parameter is missing** - Warp omits the RFC 8707 `resource` parameter from `/authorize` and `/token` requests, so servers such as Atlassian and Natoma reject the flow. + +#### Workaround + +Configure the server as a **CLI Server (Command)** through the `mcp-remote` STDIO proxy instead of connecting to its HTTP or SSE URL directly. This workaround requires Node.js because it uses `npx`. The proxy communicates with Warp over STDIO and forwards requests to the remote HTTP endpoint. + +In the Warp app, [add an MCP server](/agent-platform/capabilities/mcp/#adding-an-mcp-server) and paste a JSON configuration. For example, connect to Unblocked with: + +```json +{ + "unblocked": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://getunblocked.com/api/mcpsse"] + } +} +``` + +For a server that accepts a bearer token, use an environment variable so the token is not embedded in the command: + +```json +{ + "bearer-token-server": { + "command": "npx", + "args": [ + "-y", + "mcp-remote", + "https://your.mcp.server/url", + "--header", + "Authorization: Bearer ${YOUR_API_KEY}" + ], + "env": { + "YOUR_API_KEY": "REPLACE_WITH_YOUR_API_KEY" + } + } +} +``` + +Replace `REPLACE_WITH_YOUR_API_KEY` with the server's API key. Warp tracks these limitations in the [OAuth flow stopping after dynamic client registration issue](https://github.com/warpdotdev/warp/issues/8020), [MCP OAuth 2.0 browser login issue](https://github.com/warpdotdev/warp/issues/7595), [Miro MCP OAuth callback issue](https://github.com/warpdotdev/warp/issues/8624), [MCP authorization header issue](https://github.com/warpdotdev/warp/issues/8356), and [Atlassian MCP RFC 8707 resource parameter issue](https://github.com/warpdotdev/warp/issues/9462). + ## Shells ### fish shell `read` command diff --git a/src/pages/api/highlight-code.ts b/src/pages/api/highlight-code.ts new file mode 100644 index 000000000..af1071eb4 --- /dev/null +++ b/src/pages/api/highlight-code.ts @@ -0,0 +1,86 @@ +import type { APIRoute } from 'astro'; +import { createHighlighter } from 'shiki'; + +type ThemeMode = 'light' | 'dark'; + +const LANGUAGE_ALIASES: Record = { + shell: 'bash', + zsh: 'bash', + pwsh: 'powershell', + plaintext: 'text', +}; + +const SUPPORTED_LANGUAGES = new Set([ + 'bash', + 'powershell', + 'json', + 'javascript', + 'typescript', + 'tsx', + 'jsx', + 'python', + 'go', + 'rust', + 'yaml', + 'markdown', + 'html', + 'css', + 'text', +]); + +const highlighterPromise = createHighlighter({ + themes: ['github-light', 'github-dark'], + langs: [...SUPPORTED_LANGUAGES], +}); + +function normalizeLanguage(language: unknown): string { + if (typeof language !== 'string') return 'text'; + const normalized = language.toLowerCase(); + return LANGUAGE_ALIASES[normalized] ?? normalized; +} + +function normalizeTheme(theme: unknown): ThemeMode { + return theme === 'light' ? 'light' : 'dark'; +} + +export const POST: APIRoute = async ({ request }) => { + try { + const payload = (await request.json()) as { + code?: unknown; + language?: unknown; + theme?: unknown; + }; + const code = typeof payload.code === 'string' ? payload.code : ''; + if (!code.trim()) { + return new Response(JSON.stringify({ preHtml: null }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }); + } + + const requestedLanguage = normalizeLanguage(payload.language); + const language = SUPPORTED_LANGUAGES.has(requestedLanguage) ? requestedLanguage : 'text'; + const theme = normalizeTheme(payload.theme) === 'light' ? 'github-light' : 'github-dark'; + + const highlighter = await highlighterPromise; + const html = highlighter.codeToHtml(code, { + lang: language, + theme, + }); + const preMatch = html.match(/]*>[\s\S]*?<\/pre>/i); + + return new Response(JSON.stringify({ preHtml: preMatch?.[0] ?? null }), { + status: 200, + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-store', + }, + }); + } catch (error) { + console.error('[highlight-code] Failed to highlight code', error); + return new Response(JSON.stringify({ error: 'Failed to highlight code' }), { + status: 500, + headers: { 'Content-Type': 'application/json' }, + }); + } +}; diff --git a/src/pages/api/support-handoff.ts b/src/pages/api/support-handoff.ts new file mode 100644 index 000000000..137e8fe20 --- /dev/null +++ b/src/pages/api/support-handoff.ts @@ -0,0 +1,137 @@ +import type { APIRoute } from 'astro'; +import { SUPPORT_HANDOFF_ENDPOINT_URL, SUPPORT_HANDOFF_SHARED_SECRET } from 'astro:env/server'; + +export const prerender = false; +const DEFAULT_SUPPORT_HANDOFF_ENDPOINT_URL = + 'https://hkdk.events/mf45jvgj0ojuu2'; + +type HandoffPayload = { + user_email?: unknown; + question?: unknown; + page_url?: unknown; + conversation_transcript?: unknown; + kapa_project_id?: unknown; + kapa_thread_id?: unknown; + kapa_conversation_url?: unknown; +}; + +const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + +function asTrimmedString(value: unknown) { + return typeof value === 'string' ? value.trim() : ''; +} + +function jsonError(message: string, status = 400) { + return new Response(JSON.stringify({ message }), { + status, + headers: { 'content-type': 'application/json' }, + }); +} + +function buildKapaConversationUrl(kapaProjectId: string, kapaThreadId: string) { + return `https://app.kapa.ai/${kapaProjectId}/conversations/${kapaThreadId}`; +} + +export const POST: APIRoute = async ({ request }) => { + const supportHandoffEndpointUrl = + SUPPORT_HANDOFF_ENDPOINT_URL || DEFAULT_SUPPORT_HANDOFF_ENDPOINT_URL; + const supportHandoffSharedSecret = SUPPORT_HANDOFF_SHARED_SECRET?.trim() || ''; + if (!supportHandoffEndpointUrl) { + return jsonError('Support handoff is not configured.', 503); + } + + let payload: HandoffPayload; + try { + payload = (await request.json()) as HandoffPayload; + } catch { + return jsonError('Invalid JSON payload.'); + } + + const userEmail = asTrimmedString(payload.user_email).toLowerCase(); + if (!EMAIL_PATTERN.test(userEmail)) { + return jsonError('Please enter a valid email address.'); + } + + const question = asTrimmedString(payload.question); + const pageUrl = asTrimmedString(payload.page_url); + const conversationTranscript = asTrimmedString(payload.conversation_transcript); + const kapaProjectId = asTrimmedString(payload.kapa_project_id); + const kapaThreadId = asTrimmedString(payload.kapa_thread_id); + const suppliedKapaConversationUrl = asTrimmedString(payload.kapa_conversation_url); + + if (!question) return jsonError('A question is required.'); + if (!pageUrl) return jsonError('The current page URL is required.'); + if (!conversationTranscript) return jsonError('Conversation transcript is required.'); + if (!kapaThreadId) return jsonError('Kapa thread ID is required.'); + const derivedKapaConversationUrl = + kapaProjectId && kapaThreadId + ? buildKapaConversationUrl(kapaProjectId, kapaThreadId) + : ''; + if (kapaProjectId) { + if ( + suppliedKapaConversationUrl && + suppliedKapaConversationUrl !== derivedKapaConversationUrl + ) { + return jsonError('Kapa conversation URL does not match project/thread values.'); + } + } else if (suppliedKapaConversationUrl) { + return jsonError('Kapa project ID is required when a Kapa conversation URL is supplied.'); + } + + const forwardPayload = { + user_email: userEmail, + question, + page_url: pageUrl, + conversation_transcript: conversationTranscript, + kapa_project_id: kapaProjectId || null, + kapa_thread_id: kapaThreadId, + kapa_conversation_url: derivedKapaConversationUrl || null, + source: 'docs-kapa-custom-chat', + }; + + const forwardHeaders: HeadersInit = { + 'content-type': 'application/json', + }; + if (supportHandoffSharedSecret) { + forwardHeaders.authorization = `Bearer ${supportHandoffSharedSecret}`; + } + + let upstreamResponse: Response; + try { + upstreamResponse = await fetch(supportHandoffEndpointUrl, { + method: 'POST', + headers: forwardHeaders, + body: JSON.stringify(forwardPayload), + }); + } catch { + return jsonError('Failed to reach support handoff service.', 502); + } + + let upstreamData: unknown = null; + try { + upstreamData = await upstreamResponse.json(); + } catch { + upstreamData = null; + } + + if (!upstreamResponse.ok) { + const upstreamMessage = + upstreamData && + typeof upstreamData === 'object' && + 'message' in upstreamData && + typeof upstreamData.message === 'string' + ? upstreamData.message + : 'Support handoff failed.'; + return jsonError(upstreamMessage, upstreamResponse.status); + } + + return new Response( + JSON.stringify({ + message: 'Message sent to Warp Support.', + }), + { + status: 200, + headers: { 'content-type': 'application/json' }, + } + ); +}; diff --git a/src/styles/warp-components.css b/src/styles/warp-components.css index 38e3ce3e5..2169c61c0 100644 --- a/src/styles/warp-components.css +++ b/src/styles/warp-components.css @@ -179,6 +179,18 @@ pre.astro-code, .sl-markdown-content pre { overflow-x: auto; + overflow-y: hidden; + white-space: pre; +} + +.expressive-code pre code, +.sl-kapa-codeblock pre code { + display: block; + min-width: max-content; +} + +.expressive-code pre { + scrollbar-width: thin; } /* Code block copy button — frosted glass effect (Scalar pattern) */ diff --git a/vercel.json b/vercel.json index e8c2eeefd..8d4b8f3f5 100644 --- a/vercel.json +++ b/vercel.json @@ -29,7 +29,7 @@ }, { "key": "Content-Security-Policy", - "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://www.google.com https://app.warp.dev https://api.rudderstack.com; frame-ancestors 'none'" + "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://vercel.live https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://vercel.live https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" } ] }, @@ -38,7 +38,7 @@ "headers": [ { "key": "Content-Security-Policy", - "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://www.google.com https://app.warp.dev https://api.rudderstack.com; frame-ancestors 'none'" + "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://vercel.live https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://vercel.live https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" } ] }, @@ -47,7 +47,7 @@ "headers": [ { "key": "Content-Security-Policy", - "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://www.google.com https://app.warp.dev https://api.rudderstack.com; frame-ancestors 'none'" + "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://vercel.live https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://vercel.live https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" } ] }, From 3c2557c610d4e66f80ee40ab830070684be7bf91 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:33:03 -0600 Subject: [PATCH 02/15] Sync lockfile to fix Vercel npm ci Co-Authored-By: Warp Agent --- package-lock.json | 42 +++++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f4aff235..689fb35d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "MIT", "dependencies": { - "@astrojs/react": "^5.0.3", + "@astrojs/react": "^6.0.2", "@astrojs/rss": "^4.0.19", "@astrojs/sitemap": "^3.7.2", "@astrojs/starlight": "^0.41.4", @@ -585,16 +585,16 @@ } }, "node_modules/@astrojs/react": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-5.0.7.tgz", - "integrity": "sha512-N9cCoxvnLWaP+AK1Fv4e5Mc7ktnVTpSo2nWLwvD9Ohr1dJKygwrTSm9yatqoahgb1A5Kwjg/rT2shRiIVdn3aw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@astrojs/react/-/react-6.0.2.tgz", + "integrity": "sha512-Fvv2UqS7ajFL2Yjd5s4s5PcCBCSSfks4r04rbCHZO5z4pUPwCygV2ketI+iC+1P/sdHANLV3tgDL1wjzty4cJg==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.10.0", + "@astrojs/internal-helpers": "0.10.2", "@vitejs/plugin-react": "^5.2.0", "devalue": "^5.8.1", "ultrahtml": "^1.6.0", - "vite": "^7.3.2" + "vite": "^8.0.13" }, "engines": { "node": ">=22.12.0" @@ -606,6 +606,22 @@ "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0" } }, + "node_modules/@astrojs/react/node_modules/@astrojs/internal-helpers": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.10.2.tgz", + "integrity": "sha512-yt7fMgPYqSM4Tmr+taTW6Per+hjJ8Pk6lA1PAcDyqzOt8HzJ6Kje5WzCxA2Sd+9wsUW7uhkLeoTMK0cXPwH9rQ==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.4", + "@types/mdast": "^4.0.4", + "js-yaml": "^4.3.0", + "picomatch": "^4.0.4", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.2", + "smol-toml": "^1.6.0", + "unified": "^11.0.5" + } + }, "node_modules/@astrojs/rss": { "version": "4.0.19", "resolved": "https://registry.npmjs.org/@astrojs/rss/-/rss-4.0.19.tgz", @@ -4607,15 +4623,15 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", - "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/braces": { @@ -6617,9 +6633,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "funding": [ { "type": "github", From c39dd8f3515daf2f0676e64d7a4e6452268fe785 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 14:52:16 -0600 Subject: [PATCH 03/15] Harden support handoff and highlight endpoints Co-Authored-By: Warp Agent --- src/pages/api/highlight-code.ts | 8 +++++++ src/pages/api/support-handoff.ts | 39 +++++++++++++++++++++++++------- vercel.json | 6 ++--- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/pages/api/highlight-code.ts b/src/pages/api/highlight-code.ts index af1071eb4..974d9ef53 100644 --- a/src/pages/api/highlight-code.ts +++ b/src/pages/api/highlight-code.ts @@ -32,6 +32,7 @@ const highlighterPromise = createHighlighter({ themes: ['github-light', 'github-dark'], langs: [...SUPPORTED_LANGUAGES], }); +const MAX_CODE_SIZE_BYTES = 64 * 1024; function normalizeLanguage(language: unknown): string { if (typeof language !== 'string') return 'text'; @@ -51,6 +52,13 @@ export const POST: APIRoute = async ({ request }) => { theme?: unknown; }; const code = typeof payload.code === 'string' ? payload.code : ''; + const codeSizeBytes = new TextEncoder().encode(code).length; + if (codeSizeBytes > MAX_CODE_SIZE_BYTES) { + return new Response(JSON.stringify({ error: 'Code payload is too large' }), { + status: 413, + headers: { 'Content-Type': 'application/json' }, + }); + } if (!code.trim()) { return new Response(JSON.stringify({ preHtml: null }), { status: 200, diff --git a/src/pages/api/support-handoff.ts b/src/pages/api/support-handoff.ts index 137e8fe20..3e6f77009 100644 --- a/src/pages/api/support-handoff.ts +++ b/src/pages/api/support-handoff.ts @@ -2,8 +2,6 @@ import type { APIRoute } from 'astro'; import { SUPPORT_HANDOFF_ENDPOINT_URL, SUPPORT_HANDOFF_SHARED_SECRET } from 'astro:env/server'; export const prerender = false; -const DEFAULT_SUPPORT_HANDOFF_ENDPOINT_URL = - 'https://hkdk.events/mf45jvgj0ojuu2'; type HandoffPayload = { user_email?: unknown; @@ -16,6 +14,12 @@ type HandoffPayload = { }; const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; +const KAPA_ID_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/; +const MAX_QUESTION_LENGTH = 4_000; +const MAX_TRANSCRIPT_LENGTH = 50_000; +const MAX_PAGE_URL_LENGTH = 2_048; +const ALLOWED_PAGE_URL_HOSTS = new Set(['docs.warp.dev', 'localhost']); +const ALLOWED_PAGE_URL_SUFFIXES = ['.vercel.app']; function asTrimmedString(value: unknown) { return typeof value === 'string' ? value.trim() : ''; @@ -32,11 +36,23 @@ function buildKapaConversationUrl(kapaProjectId: string, kapaThreadId: string) { return `https://app.kapa.ai/${kapaProjectId}/conversations/${kapaThreadId}`; } +function isAllowedPageUrl(url: string) { + if (url.length > MAX_PAGE_URL_LENGTH) return false; + try { + const parsed = new URL(url); + if (!['http:', 'https:'].includes(parsed.protocol)) return false; + const hostname = parsed.hostname.toLowerCase(); + if (ALLOWED_PAGE_URL_HOSTS.has(hostname)) return true; + return ALLOWED_PAGE_URL_SUFFIXES.some((suffix) => hostname.endsWith(suffix)); + } catch { + return false; + } +} + export const POST: APIRoute = async ({ request }) => { - const supportHandoffEndpointUrl = - SUPPORT_HANDOFF_ENDPOINT_URL || DEFAULT_SUPPORT_HANDOFF_ENDPOINT_URL; + const supportHandoffEndpointUrl = SUPPORT_HANDOFF_ENDPOINT_URL?.trim() || ''; const supportHandoffSharedSecret = SUPPORT_HANDOFF_SHARED_SECRET?.trim() || ''; - if (!supportHandoffEndpointUrl) { + if (!supportHandoffEndpointUrl || !supportHandoffSharedSecret) { return jsonError('Support handoff is not configured.', 503); } @@ -60,9 +76,18 @@ export const POST: APIRoute = async ({ request }) => { const suppliedKapaConversationUrl = asTrimmedString(payload.kapa_conversation_url); if (!question) return jsonError('A question is required.'); + if (question.length > MAX_QUESTION_LENGTH) return jsonError('Question is too long.'); if (!pageUrl) return jsonError('The current page URL is required.'); + if (!isAllowedPageUrl(pageUrl)) return jsonError('Page URL is invalid or not allowed.'); if (!conversationTranscript) return jsonError('Conversation transcript is required.'); + if (conversationTranscript.length > MAX_TRANSCRIPT_LENGTH) { + return jsonError('Conversation transcript is too long.'); + } if (!kapaThreadId) return jsonError('Kapa thread ID is required.'); + if (!KAPA_ID_PATTERN.test(kapaThreadId)) return jsonError('Kapa thread ID is invalid.'); + if (kapaProjectId && !KAPA_ID_PATTERN.test(kapaProjectId)) { + return jsonError('Kapa project ID is invalid.'); + } const derivedKapaConversationUrl = kapaProjectId && kapaThreadId ? buildKapaConversationUrl(kapaProjectId, kapaThreadId) @@ -91,10 +116,8 @@ export const POST: APIRoute = async ({ request }) => { const forwardHeaders: HeadersInit = { 'content-type': 'application/json', + authorization: `Bearer ${supportHandoffSharedSecret}`, }; - if (supportHandoffSharedSecret) { - forwardHeaders.authorization = `Bearer ${supportHandoffSharedSecret}`; - } let upstreamResponse: Response; try { diff --git a/vercel.json b/vercel.json index 8d4b8f3f5..ea16be4aa 100644 --- a/vercel.json +++ b/vercel.json @@ -29,7 +29,7 @@ }, { "key": "Content-Security-Policy", - "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://vercel.live https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://vercel.live https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" + "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'wasm-unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" } ] }, @@ -38,7 +38,7 @@ "headers": [ { "key": "Content-Security-Policy", - "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://vercel.live https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://vercel.live https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" + "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" } ] }, @@ -47,7 +47,7 @@ "headers": [ { "key": "Content-Security-Policy", - "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://vercel.live https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://vercel.live https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" + "value": "default-src 'self'; base-uri 'self'; form-action 'self'; object-src 'none'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://www.google.com https://www.gstatic.com https://cdn.jsdelivr.net https://cdn.rudderlabs.com https://polyfill-fastly.io https://widget.kapa.ai https://hcaptcha.com https://*.hcaptcha.com https://js.hcaptcha.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net; font-src 'self' https://fonts.gstatic.com https://cdn.jsdelivr.net; img-src 'self' data: https:; frame-src https://www.youtube-nocookie.com https://www.loom.com https://drive.google.com https://www.google.com https://hcaptcha.com https://*.hcaptcha.com; connect-src 'self' https://va.vercel-scripts.com https://vitals.vercel-insights.com https://*.kapa.ai https://kapa-widget-proxy-la7dkmplpq-uc.a.run.app https://www.google.com https://app.warp.dev https://api.rudderstack.com https://cdn.rudderlabs.com https://hcaptcha.com https://*.hcaptcha.com; frame-ancestors 'none'" } ] }, From 92581fd3c34f640e66bd1394f4c631cc3296e2f6 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:21:27 -0600 Subject: [PATCH 04/15] Reduce Vercel route load and API warning noise Co-Authored-By: Warp Agent --- src/pages/api/highlight-code.ts | 9 +++++++++ vercel.json | 15 --------------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/pages/api/highlight-code.ts b/src/pages/api/highlight-code.ts index 974d9ef53..a13efaba5 100644 --- a/src/pages/api/highlight-code.ts +++ b/src/pages/api/highlight-code.ts @@ -44,6 +44,15 @@ function normalizeTheme(theme: unknown): ThemeMode { return theme === 'light' ? 'light' : 'dark'; } +export const GET: APIRoute = async () => + new Response(JSON.stringify({ error: 'Method not allowed' }), { + status: 405, + headers: { + Allow: 'POST', + 'Content-Type': 'application/json', + }, + }); + export const POST: APIRoute = async ({ request }) => { try { const payload = (await request.json()) as { diff --git a/vercel.json b/vercel.json index ea16be4aa..b3462d7b6 100644 --- a/vercel.json +++ b/vercel.json @@ -390,11 +390,6 @@ "destination": "/guides/devops/how-to-analyze-cloud-run-logs-gcloud/", "statusCode": 308 }, - { - "source": "/knowledge-and-collaboration/session-sharingentials1", - "destination": "/knowledge-and-collaboration/session-sharing/", - "statusCode": 308 - }, { "source": "/advanced/command-line-flags", "destination": "/terminal/sessions/launch-configurations/", @@ -1390,11 +1385,6 @@ "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, - { - "source": "/agent-platform/features/warp-ai/agent-modea", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, { "source": "/agent-platform/features/warp-ai/ai-command-search", "destination": "/agent-platform/local-agents/overview/", @@ -5680,11 +5670,6 @@ "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, - { - "source": "/agent-platform/features/warp-ai/agent-modea/", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, { "source": "/agent-platform/features/warp-ai/ai-command-search/", "destination": "/agent-platform/local-agents/overview/", From d9fb548e11d224b63995509d21a11877c1b7296b Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 15:42:56 -0600 Subject: [PATCH 05/15] Prune unused legacy redirects to reduce route count Co-Authored-By: Warp Agent --- vercel.json | 1771 ++------------------------------------------------- 1 file changed, 43 insertions(+), 1728 deletions(-) diff --git a/vercel.json b/vercel.json index b3462d7b6..7ea3fe3a4 100644 --- a/vercel.json +++ b/vercel.json @@ -365,11 +365,6 @@ "destination": "/terminal/input/classic-input/", "statusCode": 308 }, - { - "source": "/~/revisions/pyklxx5pdxve9wvizjl3/features/entry", - "destination": "/terminal/entry/", - "statusCode": 308 - }, { "source": "/platform/api-sdk", "destination": "/reference/api-and-sdk/", @@ -565,281 +560,6 @@ "destination": "/agent-platform/capabilities/web-search/", "statusCode": 308 }, - { - "source": "/agent-platform/agent-platform/active-ai", - "destination": "/agent-platform/local-agents/active-ai/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/active-ai#next-command", - "destination": "/agent-platform/local-agents/active-ai/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/active-ai#suggested-code-diffs", - "destination": "/agent-platform/local-agents/active-ai/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/agent-modality-beta", - "destination": "/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/agent/agents-overview", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/agent/using-agents/agent-profiles-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/agents-md", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/agents-overview", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/ai", - "destination": "/agent-platform/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/ai-faqs", - "destination": "/agent-platform/getting-started/faqs/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/ai-faqs#gathering-ai-debugging-id", - "destination": "/agent-platform/getting-started/faqs/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/ai-model-choice", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/ambient-agents/ambient-agents-overview", - "destination": "/platform/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/autonomy", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/autonomy/agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/autonomy/run-to-completion", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/cloud-agents/cloud-agents-platform", - "destination": "/platform/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/cloud-agents/warp-platform", - "destination": "/platform/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/conversation-forking", - "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/full-terminal-use", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/full-terminal-use#session-level-approvals", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/generate", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/integrations/github-actions/readme", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/integrations/integrations-overview", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/model-choice", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/slash-commands", - "destination": "/agent-platform/capabilities/slash-commands/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents#codebase-context", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents#windows", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context", - "destination": "/agent-platform/local-agents/agent-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context#attaching-blocks-as-context", - "destination": "/agent-platform/local-agents/agent-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/blocks-as-context", - "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/blocks-as-context#attaching-blocks-as-context", - "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/images-as-context", - "destination": "/agent-platform/local-agents/agent-context/images-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/selection-as-context", - "destination": "/agent-platform/local-agents/agent-context/selection-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/urls-as-context", - "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/using-to-add-context", - "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-conversations", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-conversations/conversation-forking", - "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions#agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions#agent-profiles", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-tasklists", - "destination": "/agent-platform/capabilities/task-lists/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/managing-agents", - "destination": "/platform/managing-cloud-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/managing-agents#in-app-agent-notifications", - "destination": "/platform/managing-cloud-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/model-choice", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/model-choice#available-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/model-choice#configuring-models-per-agent-profile", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/model-choice#how-to-change-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/planning", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/third-party-cli-agents", - "destination": "/agent-platform/cli-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/web-search", - "destination": "/agent-platform/capabilities/web-search/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/voice", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/warp-ai", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, { "source": "/agent-platform/agents/active-ai", "destination": "/agent-platform/local-agents/active-ai/", @@ -1180,11 +900,6 @@ "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, - { - "source": "/agent-platform/features/ai-and-ask-warp", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, { "source": "/agent-platform/features/ai-and-ask-warp-ai", "destination": "/agent-platform/local-agents/overview/", @@ -1380,11 +1095,6 @@ "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, - { - "source": "/agent-platform/features/warp-ai/agent-mode#examples-of-coding-capabilities", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, { "source": "/agent-platform/features/warp-ai/ai-command-search", "destination": "/agent-platform/local-agents/overview/", @@ -1805,11 +1515,6 @@ "destination": "/terminal/appearance/custom-themes/", "statusCode": 308 }, - { - "source": "/appearance/custom-themes.git", - "destination": "/terminal/appearance/custom-themes/", - "statusCode": 308 - }, { "source": "/appearance/input-position", "destination": "/terminal/appearance/input-position/", @@ -1825,11 +1530,6 @@ "destination": "/terminal/appearance/prompt/", "statusCode": 308 }, - { - "source": "/appearance/prompt#custom-prompt-compatibility-table", - "destination": "/terminal/appearance/prompt/#shell-prompt-compatibility-table", - "statusCode": 308 - }, { "source": "/appearance/size-opacity-blurring", "destination": "/terminal/appearance/size-opacity-blurring/", @@ -1885,11 +1585,6 @@ "destination": "/changelog/rss.xml", "statusCode": 308 }, - { - "source": "/changelog/url/docs.warp.dev/getting-started/changelog", - "destination": "/changelog/", - "statusCode": 308 - }, { "source": "/changelog/warp/getting-started/changelog", "destination": "/changelog/", @@ -2050,16 +1745,6 @@ "destination": "/terminal/command-completions/completions/", "statusCode": 308 }, - { - "source": "/features/completions#how-to-access-it", - "destination": "/terminal/command-completions/completions/", - "statusCode": 308 - }, - { - "source": "/features/completions#supported-completion-specs", - "destination": "/terminal/command-completions/completions/", - "statusCode": 308 - }, { "source": "/features/customize/custom-keyboard-shortcuts", "destination": "/getting-started/keyboard-shortcuts/", @@ -2221,28 +1906,8 @@ "statusCode": 308 }, { - "source": "/features/prompt#custom-prompt", - "destination": "/terminal/appearance/prompt/", - "statusCode": 308 - }, - { - "source": "/features/prompt#custom-prompt-compatibility-table", - "destination": "/terminal/appearance/prompt/", - "statusCode": 308 - }, - { - "source": "/features/prompt#how-it-works", - "destination": "/terminal/appearance/prompt/", - "statusCode": 308 - }, - { - "source": "/features/prompt#how-to-access-it", - "destination": "/terminal/appearance/prompt/", - "statusCode": 308 - }, - { - "source": "/features/quit-warning", - "destination": "/terminal/more-features/quit-warning/", + "source": "/features/quit-warning", + "destination": "/terminal/more-features/quit-warning/", "statusCode": 308 }, { @@ -2275,11 +1940,6 @@ "destination": "/terminal/sessions/", "statusCode": 308 }, - { - "source": "/features/sessions/README", - "destination": "/terminal/sessions/", - "statusCode": 308 - }, { "source": "/features/sessions/launch-configurations", "destination": "/terminal/sessions/launch-configurations/", @@ -2465,11 +2125,6 @@ "destination": "/terminal/windows/global-hotkey/", "statusCode": 308 }, - { - "source": "/features/windows/hotkey-window#dedicated-window", - "destination": "/terminal/windows/global-hotkey/", - "statusCode": 308 - }, { "source": "/features/windows/split-panes", "destination": "/terminal/windows/split-panes/", @@ -2545,26 +2200,6 @@ "destination": "/getting-started/quickstart/installation-and-setup/", "statusCode": 308 }, - { - "source": "/getting-started/getting-started-with-warp#appimage", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, - { - "source": "/getting-started/getting-started-with-warp#arch-linux-based-distributions", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, - { - "source": "/getting-started/getting-started-with-warp#logging-into-warp", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, - { - "source": "/getting-started/getting-started-with-warp#logging-into-warp-required", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, { "source": "/getting-started/getting-started-with-warp-on-linux", "destination": "/getting-started/quickstart/installation-and-setup/", @@ -2635,11 +2270,6 @@ "destination": "/getting-started/quickstart/installation-and-setup/", "statusCode": 308 }, - { - "source": "/getting-started/quickstart-guide/README", - "destination": "/quickstart/", - "statusCode": 308 - }, { "source": "/getting-started/quickstart-guide/agents-in-warp", "destination": "/agent-platform/getting-started/agents-in-warp/", @@ -2745,11 +2375,6 @@ "destination": "/quickstart/", "statusCode": 308 }, - { - "source": "/readme", - "destination": "/", - "statusCode": 308 - }, { "source": "/reference/agent-api-and-sdk", "destination": "/reference/api-and-sdk/", @@ -2860,21 +2485,6 @@ "destination": "/reference/api-and-sdk/troubleshooting/errors/resource-unavailable/", "statusCode": 308 }, - { - "source": "/reference/cli#api-key-authentication", - "destination": "/reference/cli/api-keys/", - "statusCode": 308 - }, - { - "source": "/reference/cli#quickstart-guide", - "destination": "/reference/cli/quickstart/", - "statusCode": 308 - }, - { - "source": "/reference/cli/README.md#api-key-authentication", - "destination": "/reference/cli/api-keys/", - "statusCode": 308 - }, { "source": "/reference/cli/integrations-and-environments", "destination": "/reference/cli/integration-setup/", @@ -2895,31 +2505,11 @@ "destination": "/reference/cli/", "statusCode": 308 }, - { - "source": "/reference/developers/cli#api-key-authentication", - "destination": "/reference/cli/api-keys/#authenticating-with-api-keys", - "statusCode": 308 - }, - { - "source": "/reference/developers/cli#generating-api-keys", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/reference/developers/cli#linux", - "destination": "/reference/cli/", - "statusCode": 308 - }, { "source": "/reference/integrations/integrations-overview/integrations-and-environments", "destination": "/reference/cli/integration-setup/", "statusCode": 308 }, - { - "source": "/reference/integrations/integrations-overview/integrations-and-environments#creating-an-environment", - "destination": "/reference/cli/integration-setup/#step-1-creating-an-environment", - "statusCode": 308 - }, { "source": "/reference/keybindings", "destination": "/getting-started/keyboard-shortcuts/", @@ -2935,11 +2525,6 @@ "destination": "/reference/api-and-sdk/", "statusCode": 308 }, - { - "source": "/reference/platform/agent-api-and-sdk#agent-sdk", - "destination": "/reference/api-and-sdk/", - "statusCode": 308 - }, { "source": "/reference/platform/agent-api-and-sdk/agent", "destination": "/reference/api-and-sdk/", @@ -2960,11 +2545,6 @@ "destination": "/reference/cli/", "statusCode": 308 }, - { - "source": "/reference/platform/cli#api-key-authentication", - "destination": "/reference/cli/api-keys/", - "statusCode": 308 - }, { "source": "/reference/platform/cli/api-keys", "destination": "/reference/cli/api-keys/", @@ -3025,11 +2605,6 @@ "destination": "/getting-started/keyboard-shortcuts/", "statusCode": 308 }, - { - "source": "/support-and-community/community/refer-a-friend#referral-program-terms-and-conditions", - "destination": "/support-and-community/community/refer-a-friend/", - "statusCode": 308 - }, { "source": "/support-and-community/features/network-log", "destination": "/support-and-community/privacy-and-security/network-log/", @@ -3075,31 +2650,6 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, - { - "source": "/support-and-community/help/known-issues#auto-update-on-macos-ventura", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/help/known-issues#debugging", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/help/known-issues#linux-workarounds", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/help/known-issues#list-of-incompatible-tools", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/help/known-issues#ssh-to-local-network-device-is-denied", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, { "source": "/support-and-community/help/licenses", "destination": "/support-and-community/community/open-source-licenses/", @@ -3120,41 +2670,21 @@ "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", "statusCode": 308 }, - { - "source": "/support-and-community/help/sending-us-feedback#gathering-warp-logs", - "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", - "statusCode": 308 - }, { "source": "/support-and-community/help/troubleshooting-login-issues", "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", "statusCode": 308 }, - { - "source": "/support-and-community/help/troubleshooting-login-issues#how-to-get-an-auth-token-to-login", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, { "source": "/support-and-community/help/uninstalling-warp", "destination": "/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/", "statusCode": 308 }, - { - "source": "/support-and-community/help/uninstalling-warp#removing-warp-login-settings-files-log-and-database-1", - "destination": "/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/", - "statusCode": 308 - }, { "source": "/support-and-community/help/updating-warp", "destination": "/support-and-community/troubleshooting-and-support/updating-warp/", "statusCode": 308 }, - { - "source": "/support-and-community/help/updating-warp#auto-update-issues", - "destination": "/support-and-community/troubleshooting-and-support/updating-warp/", - "statusCode": 308 - }, { "source": "/support-and-community/help/using-warp-offline", "destination": "/support-and-community/troubleshooting-and-support/using-warp-offline/", @@ -3220,16 +2750,6 @@ "destination": "/support-and-community/privacy-and-security/privacy/", "statusCode": 308 }, - { - "source": "/support-and-community/privacy/privacy#exhaustive-telemetry-table", - "destination": "/support-and-community/privacy-and-security/privacy/", - "statusCode": 308 - }, - { - "source": "/support-and-community/privacy/privacy#telemetry-what-usage-data-are-you-collecting-and-why", - "destination": "/support-and-community/privacy-and-security/privacy/", - "statusCode": 308 - }, { "source": "/support-and-community/privacy/secret-redaction", "destination": "/support-and-community/privacy-and-security/secret-redaction/", @@ -3255,36 +2775,6 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/known-issues#debugging", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/known-issues#linux-1", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/known-issues#list-of-incompatible-tools", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/known-issues#pwsh", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/known-issues#shells", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/known-issues#windows-1", - "destination": "/support-and-community/troubleshooting-and-support/known-issues/", - "statusCode": 308 - }, { "source": "/support-and-community/support-and-billing/licenses", "destination": "/support-and-community/community/open-source-licenses/", @@ -3310,11 +2800,6 @@ "destination": "/support-and-community/plans-and-billing/add-on-credits/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/plans-and-pricing/add-on-credits#id-2.-enable-auto-reload", - "destination": "/support-and-community/plans-and-billing/add-on-credits/", - "statusCode": 308 - }, { "source": "/support-and-community/support-and-billing/plans-and-pricing/ai-credits", "destination": "/support-and-community/plans-and-billing/credits/", @@ -3325,11 +2810,6 @@ "destination": "/support-and-community/plans-and-billing/credits/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/plans-and-pricing/ai-requests#how-are-warp-ai-requests-calculated", - "destination": "/support-and-community/plans-and-billing/credits/", - "statusCode": 308 - }, { "source": "/support-and-community/plans-and-billing/bring-your-own-api-key/:path*", "destination": "/agent-platform/inference/bring-your-own-api-key/", @@ -3340,31 +2820,11 @@ "destination": "/agent-platform/inference/bring-your-own-api-key/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/plans-and-pricing/bring-your-own-api-key#enabling-byok", - "destination": "/agent-platform/inference/bring-your-own-api-key/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/plans-and-pricing/bring-your-own-api-key#how-does-byok-work", - "destination": "/agent-platform/inference/bring-your-own-api-key/", - "statusCode": 308 - }, { "source": "/support-and-community/support-and-billing/plans-and-pricing/pricing-faqs", "destination": "/support-and-community/plans-and-billing/pricing-faqs/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/plans-and-pricing/pricing-faqs#how-can-i-subscribe-to-a-warp-enterprise-plan", - "destination": "/support-and-community/plans-and-billing/pricing-faqs/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/plans-and-pricing/pricing-faqs#how-can-i-upgrade-and-subscribe-to-a-warp-plan", - "destination": "/support-and-community/plans-and-billing/pricing-faqs/", - "statusCode": 308 - }, { "source": "/support-and-community/support-and-billing/plans-and-pricing/reload-credits-add-on-credits", "destination": "/support-and-community/plans-and-billing/add-on-credits/", @@ -3390,21 +2850,6 @@ "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/sending-us-feedback#gathering-ai-debugging-id", - "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/sending-us-feedback#gathering-warp-logs", - "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/sending-us-feedback#windows", - "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", - "statusCode": 308 - }, { "source": "/support-and-community/support-and-billing/subscription-management", "destination": "/support-and-community/plans-and-billing/plans-pricing-refunds/", @@ -3415,21 +2860,6 @@ "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", "statusCode": 308 }, - { - "source": "/support-and-community/support-and-billing/troubleshooting-login-issues#blocked-for-terms-of-service-violation", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/troubleshooting-login-issues#flagged-as-fraudulent", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/support-and-community/support-and-billing/troubleshooting-login-issues#how-to-get-an-auth-token-to-login", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, { "source": "/support-and-community/support-and-billing/uninstalling-warp", "destination": "/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/", @@ -3505,11 +2935,6 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, - { - "source": "/terminal/appearance/prompt#custom-prompt", - "destination": "/terminal/appearance/prompt/", - "statusCode": 308 - }, { "source": "/terminal/command-input/command-suggestions", "destination": "/terminal/command-completions/completions/", @@ -4675,41 +4100,6 @@ "destination": "/platform/managing-cloud-agents/", "statusCode": 308 }, - { - "source": "/getting-started/readme", - "destination": "/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme-1/coding-in-warp", - "destination": "/getting-started/quickstart/coding-in-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme-1/customizing-warp", - "destination": "/getting-started/quickstart/customizing-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme-1/installation-and-setup", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme/coding-in-warp", - "destination": "/getting-started/quickstart/coding-in-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme/customizing-warp", - "destination": "/getting-started/quickstart/customizing-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme/installation-and-setup", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, { "source": "/platform/warp-platform", "destination": "/reference/", @@ -4956,267 +4346,62 @@ "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/active-ai/", + "source": "/agent-platform/agents/active-ai/", "destination": "/agent-platform/local-agents/active-ai/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/agent-modality-beta/", + "source": "/agent-platform/agents/agent-modality-beta/", "destination": "/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/agent/agents-overview/", + "source": "/agent-platform/agents/agents-md/", "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/agent/using-agents/agent-profiles-permissions/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "source": "/agent-platform/agents/agents-overview/", + "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/agents-md/", - "destination": "/agent-platform/local-agents/overview/", + "source": "/agent-platform/agents/ai/", + "destination": "/agent-platform/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/agents-overview/", + "source": "/agent-platform/agents/ai-commander/", "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/ai/", - "destination": "/agent-platform/", + "source": "/agent-platform/agents/ai-commands/", + "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/ai-faqs/", + "source": "/agent-platform/agents/ai-faqs/", "destination": "/agent-platform/getting-started/faqs/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/ai-model-choice/", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/ambient-agents/ambient-agents-overview/", - "destination": "/platform/", + "source": "/agent-platform/agents/ai-getting-started/", + "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/autonomy/", + "source": "/agent-platform/agents/autonomy/", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/autonomy/agent-permissions/", + "source": "/agent-platform/agents/autonomy/agent-permissions/", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agent-platform/agent-platform/autonomy/run-to-completion/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/cloud-agents/cloud-agents-platform/", - "destination": "/platform/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/cloud-agents/warp-platform/", - "destination": "/platform/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/conversation-forking/", - "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/full-terminal-use/", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/generate/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/integrations/github-actions/readme/", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/integrations/integrations-overview/", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/model-choice/", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/slash-commands/", - "destination": "/agent-platform/capabilities/slash-commands/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/", - "destination": "/agent-platform/local-agents/agent-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/blocks-as-context/", - "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/images-as-context/", - "destination": "/agent-platform/local-agents/agent-context/images-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/selection-as-context/", - "destination": "/agent-platform/local-agents/agent-context/selection-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/urls-as-context/", - "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-context/using-to-add-context/", - "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-conversations/", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-conversations/conversation-forking/", - "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-permissions/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/agent-tasklists/", - "destination": "/agent-platform/capabilities/task-lists/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/managing-agents/", - "destination": "/platform/managing-cloud-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/model-choice/", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/planning/", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/third-party-cli-agents/", - "destination": "/agent-platform/cli-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/using-agents/web-search/", - "destination": "/agent-platform/capabilities/web-search/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/voice/", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent-platform/warp-ai/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/active-ai/", - "destination": "/agent-platform/local-agents/active-ai/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/agent-modality-beta/", - "destination": "/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/agents-md/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/agents-overview/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/ai/", - "destination": "/agent-platform/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/ai-commander/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/ai-commands/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/ai-faqs/", - "destination": "/agent-platform/getting-started/faqs/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/ai-getting-started/", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/autonomy/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/autonomy/agent-permissions/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agents/autonomy/run-to-completion/", + "source": "/agent-platform/agents/autonomy/run-to-completion/", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, @@ -6015,11 +5200,6 @@ "destination": "/changelog/rss.xml", "statusCode": 308 }, - { - "source": "/changelog/url/docs.warp.dev/getting-started/changelog/", - "destination": "/changelog/", - "statusCode": 308 - }, { "source": "/changelog/warp/getting-started/changelog/", "destination": "/changelog/", @@ -8330,41 +7510,6 @@ "destination": "/platform/managing-cloud-agents/", "statusCode": 308 }, - { - "source": "/getting-started/readme/", - "destination": "/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme-1/coding-in-warp/", - "destination": "/getting-started/quickstart/coding-in-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme-1/customizing-warp/", - "destination": "/getting-started/quickstart/customizing-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme-1/installation-and-setup/", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme/coding-in-warp/", - "destination": "/getting-started/quickstart/coding-in-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme/customizing-warp/", - "destination": "/getting-started/quickstart/customizing-warp/", - "statusCode": 308 - }, - { - "source": "/getting-started/readme/installation-and-setup/", - "destination": "/getting-started/quickstart/installation-and-setup/", - "statusCode": 308 - }, { "source": "/platform/warp-platform/", "destination": "/reference/", @@ -8475,11 +7620,6 @@ "destination": "/agent-platform/capabilities/mcp/", "statusCode": 308 }, - { - "source": "/getting-started/readme-1", - "destination": "/quickstart/", - "statusCode": 308 - }, { "source": "/support-and-billing/plans-and-pricing/ai-credits", "destination": "/support-and-community/plans-and-billing/", @@ -8510,11 +7650,6 @@ "destination": "/agent-platform/inference/model-choice/", "statusCode": 308 }, - { - "source": "/getting-started/readme/agents-in-warp", - "destination": "/agent-platform/local-agents/overview/", - "statusCode": 308 - }, { "source": "/privacy/privacy", "destination": "/support-and-community/privacy-and-security/privacy/", @@ -8940,16 +8075,6 @@ "destination": "/agent-platform/capabilities/planning/", "statusCode": 308 }, - { - "source": "/agents/using-agents/model-choice#available-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/model-choice#how-to-change-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, { "source": "/guides/agent-workflows", "destination": "/guides/agent-workflows/how-to-review-ai-generated-code/", @@ -8961,578 +8086,68 @@ "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents#agents-in-warp", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/agent-platform/cloud-agents-and-orchestration/team-access-billing-and-identity", + "destination": "/platform/team-access-billing-and-identity/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents#entering-agent-mode", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/agent-platform/warps-agent/agent-context/blocks-as-context", + "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents#what-is-agent-mode", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/agent-platform/warps-agent/agent-context/urls-as-context", + "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-conversations#conversations-with-warps-agent", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/agent-platform/warps-agent/agent-context/using-to-add-context", + "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-conversations#starting-a-new-conversation", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/agent-platform/warps-agent/capabilities-overview/web-search", + "destination": "/agent-platform/capabilities/web-search/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-conversations#staying-in-a-conversation-follow-ups", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/agent-platform/warps-agent/interacting-with-agents/conversation-forking", + "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "source": "/agent-platform/warps-agent/interactive-code-review", + "destination": "/agent-platform/local-agents/interactive-code-review/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#agent-profiles", + "source": "/agents/using-agents/agent-permissions", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#command-allowlist", + "source": "/agents/using-agents/agent-permissions/", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#command-denylist", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "source": "/developers/cli", + "destination": "/reference/cli/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/managing-agents#agent-management-panel", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/enterprise/enterprise-features", + "destination": "/enterprise/enterprise-features/architecture-and-deployment/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/managing-agents#agent-status-indicators", - "destination": "/agent-platform/local-agents/interacting-with-agents/", + "source": "/features/ai", + "destination": "/agent-platform/", "statusCode": 308 }, { - "source": "/agent-platform/agent/using-agents/managing-agents#in-app-agent-notifications", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/model-choice#auto-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/model-choice#available-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/model-choice#how-to-change-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/model-choice#model-fallback", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/planning#creating-a-plan", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/planning#executing-a-plan", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/planning#monitoring-progress", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/using-agents/planning#reviewing-and-editing", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/voice#initial-setup", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/voice#sample-use-cases", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/agent/voice#using-voice", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/cloud-agents-and-orchestration/team-access-billing-and-identity", - "destination": "/platform/team-access-billing-and-identity/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/blocks-as-context", - "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#adding-an-mcp-server", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#adding-multiple-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#authentication-in-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#debugging-mcp", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#file-based-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#how-to-access-mcp-server-settings", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#sharing-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/mcp#where-mcp-logs-are-stored", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/urls-as-context", - "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/agent-context/using-to-add-context", - "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#agent-profiles", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#command-allowlist", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#command-denylist", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#codebase-indexing-states", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#ignore-files", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#indexing-your-codebase", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#when-does-codebase-syncing-happen", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/full-terminal-use#configuring-agent-permissions-and-autonomy", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/full-terminal-use#how-full-terminal-use-works", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/full-terminal-use#overview", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/model-choice#auto-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/model-choice#how-to-change-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/model-choice#model-fallback", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/rules#how-to-access-rules", - "destination": "/agent-platform/capabilities/rules/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/rules#project-rules", - "destination": "/agent-platform/capabilities/rules/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/session-sharing#key-capabilities", - "destination": "/agent-platform/local-agents/session-sharing/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/session-sharing#sharing-a-session", - "destination": "/agent-platform/local-agents/session-sharing/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/session-sharing#viewing-shared-sessions", - "destination": "/agent-platform/local-agents/session-sharing/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-interactions", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-skill-file", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-skill-with-arguments", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-skill-without-arguments", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#how-argument-substitution-works", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#how-skills-work", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#key-features", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#project-skills", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#project-vs-root-directory-skills", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#root-directory-skills-global", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#skill-name-conflicts", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#step-1-choose-a-location", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/skills#step-4-add-content", - "destination": "/agent-platform/capabilities/skills/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/capabilities-overview/web-search", - "destination": "/agent-platform/capabilities/web-search/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents#conversations-with-warps-agent", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents#panel-layout", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents#starting-a-new-conversation", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents#staying-in-a-conversation-follow-ups", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents/conversation-forking", - "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents/voice#initial-setup", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents/voice#sample-use-cases", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interacting-with-agents/voice#using-voice", - "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", - "statusCode": 308 - }, - { - "source": "/agent-platform/warps-agent/interactive-code-review", - "destination": "/agent-platform/local-agents/interactive-code-review/", - "statusCode": 308 - }, - { - "source": "/agents/active-ai#next-command", - "destination": "/agent-platform/local-agents/active-ai/", - "statusCode": 308 - }, - { - "source": "/agents/active-ai#prompt-suggestions", - "destination": "/agent-platform/local-agents/active-ai/", - "statusCode": 308 - }, - { - "source": "/agents/full-terminal-use#configuring-agent-permissions-and-autonomy", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agents/full-terminal-use#how-full-terminal-use-works", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agents/full-terminal-use#overview", - "destination": "/agent-platform/capabilities/full-terminal-use/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents#agents-in-warp", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents#entering-agent-mode", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents#what-is-agent-mode", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-conversations#conversations-with-warps-agent", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-conversations#starting-a-new-conversation", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-conversations#staying-in-a-conversation-follow-ups", - "destination": "/agent-platform/local-agents/interacting-with-agents/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-profiles-permissions#agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-profiles-permissions#agent-profiles", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-profiles-permissions#command-allowlist", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-profiles-permissions#command-denylist", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-permissions", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/agent-permissions/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/model-choice#auto-models", - "destination": "/agent-platform/inference/model-choice/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/planning#creating-a-plan", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/planning#executing-a-plan", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/planning#reviewing-and-editing", - "destination": "/agent-platform/capabilities/planning/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/web-search#how-web-search-works-in-warp", - "destination": "/agent-platform/capabilities/web-search/", - "statusCode": 308 - }, - { - "source": "/agents/using-agents/web-search#when-the-agent-uses-web-search", - "destination": "/agent-platform/capabilities/web-search/", - "statusCode": 308 - }, - { - "source": "/code/codebase-context#codebase-indexing-states", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/code/codebase-context#indexing-your-codebase", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/code/codebase-context#when-does-codebase-syncing-happen", - "destination": "/agent-platform/capabilities/codebase-context/", - "statusCode": 308 - }, - { - "source": "/community/refer-a-friend#all-other-referral-tiers", - "destination": "/support-and-community/community/refer-a-friend/", - "statusCode": 308 - }, - { - "source": "/community/refer-a-friend#international-users", - "destination": "/support-and-community/community/refer-a-friend/", - "statusCode": 308 - }, - { - "source": "/community/refer-a-friend#referral-rewards-program", - "destination": "/support-and-community/community/refer-a-friend/", - "statusCode": 308 - }, - { - "source": "/community/refer-a-friend#shipping-time-frame", - "destination": "/support-and-community/community/refer-a-friend/", - "statusCode": 308 - }, - { - "source": "/community/warp-preview-and-alpha-program#getting-started-with-warp-preview", - "destination": "/support-and-community/community/warp-preview-and-alpha-program/", - "statusCode": 308 - }, - { - "source": "/community/warp-preview-and-alpha-program#important-notes", - "destination": "/support-and-community/community/warp-preview-and-alpha-program/", - "statusCode": 308 - }, - { - "source": "/community/warp-preview-and-alpha-program#key-warp-preview-features", - "destination": "/support-and-community/community/warp-preview-and-alpha-program/", - "statusCode": 308 - }, - { - "source": "/developers/cli", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/enterprise/enterprise-features", - "destination": "/enterprise/enterprise-features/architecture-and-deployment/", - "statusCode": 308 - }, - { - "source": "/features/ai", - "destination": "/agent-platform/", - "statusCode": 308 - }, - { - "source": "/features/warp-ai/agent-mode", - "destination": "/agent-platform/", + "source": "/features/warp-ai/agent-mode", + "destination": "/agent-platform/", "statusCode": 308 }, { @@ -9545,166 +8160,11 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, - { - "source": "/help/troubleshooting-login-issues#all-browsers", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/help/troubleshooting-login-issues#cant-open-warp-from-sso", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/help/troubleshooting-login-issues#cant-sign-up-for-or-log-into-warp", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/help/troubleshooting-login-issues#proxies", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/help/troubleshooting-login-issues#safari", - "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", - "statusCode": 308 - }, - { - "source": "/integrations/github-actions#id-1.-responding-to-comments-with-mentions", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/integrations/github-actions#id-2.-automated-pull-request-review", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/integrations/github-actions#id-3.-automatically-fix-issues", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/integrations/github-actions#quickstart", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/integrations/github-actions#requirements", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, - { - "source": "/integrations/github-actions#what-the-github-actions-integration-does", - "destination": "/platform/integrations/github-actions/", - "statusCode": 308 - }, { "source": "/integrations/integrations-and-plugins", "destination": "/platform/integrations/", "statusCode": 308 }, - { - "source": "/integrations/linear#how-to-configure-the-integration", - "destination": "/platform/integrations/linear/", - "statusCode": 308 - }, - { - "source": "/integrations/linear#requirements", - "destination": "/platform/integrations/linear/", - "statusCode": 308 - }, - { - "source": "/integrations/linear#using-warp-inside-linear", - "destination": "/platform/integrations/linear/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#joining-the-live-remote-session", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#monitoring-agent-progress", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#overview", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#pull-requests-and-output", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#requirements", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#triggering-an-agent", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/integrations/slack#using-warp-inside-slack", - "destination": "/platform/integrations/slack/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#adding-an-mcp-server", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#adding-multiple-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#authentication-in-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#debugging-mcp", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#how-to-access-mcp-server-settings", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#model-context-protocol-mcp", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#sharing-mcp-servers", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/mcp#where-mcp-logs-are-stored", - "destination": "/agent-platform/capabilities/mcp/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/rules#how-to-access-rules", - "destination": "/agent-platform/capabilities/rules/", - "statusCode": 308 - }, - { - "source": "/knowledge-and-collaboration/rules#project-rules", - "destination": "/agent-platform/capabilities/rules/", - "statusCode": 308 - }, { "source": "/platform/agent-api-and-sdk/agent", "destination": "/reference/api-and-sdk/", @@ -9715,156 +8175,11 @@ "destination": "/reference/api-and-sdk/", "statusCode": 308 }, - { - "source": "/platform/cli#api-key-authentication", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#bundled-with-warp", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#id-2.-authenticate", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#id-3.-run-an-agent", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#id-4.-add-github-context-optional", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#id-5.-next-steps", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#interactive-login-local-machines", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#running-agents", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#running-locally-warp-agent-run", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#running-the-cli", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#standalone-package", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli#what-is-the-warp-cli", - "destination": "/reference/cli/", - "statusCode": 308 - }, - { - "source": "/platform/cli/integrations-and-environments#how-integrations-and-environments-work", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/platform/cli/integrations-and-environments#option-1-guided-environment-setup-recommended", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/platform/cli/integrations-and-environments#option-2-create-an-environment-with-the-cli", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/platform/cli/integrations-and-environments#step-1-creating-an-environment", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/platform/cli/integrations-and-environments#step-2-authorizing-github", - "destination": "/platform/integrations/", - "statusCode": 308 - }, - { - "source": "/platform/environments#about-environments", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#create-an-environment-with-guided-setup-recommended", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#hosts-and-environments", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#how-environments-fit-into-the-warp-platform", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#key-features", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#what-happens-at-runtime", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#when-to-use-environments", - "destination": "/platform/environments/", - "statusCode": 308 - }, - { - "source": "/platform/environments#where-to-configure-environments", - "destination": "/platform/environments/", - "statusCode": 308 - }, { "source": "/platform/team-access-billing-and-identity-permissions", "destination": "/agent-platform/", "statusCode": 308 }, - { - "source": "/privacy/privacy#how-to-disable-telemetry-and-crash-reporting", - "destination": "/support-and-community/privacy-and-security/privacy/", - "statusCode": 308 - }, - { - "source": "/privacy/privacy#what-telemetry-data-does-warp-collect-and-why", - "destination": "/support-and-community/privacy-and-security/privacy/", - "statusCode": 308 - }, - { - "source": "/privacy/secret-redaction#how-it-works", - "destination": "/support-and-community/privacy-and-security/secret-redaction/", - "statusCode": 308 - }, - { - "source": "/privacy/secret-redaction#visually-hiding-secrets", - "destination": "/support-and-community/privacy-and-security/secret-redaction/", - "statusCode": 308 - }, { "source": "/support-and-community/troubleshooting-and-support", "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", @@ -10226,4 +8541,4 @@ "statusCode": 308 } ] -} \ No newline at end of file +} From af23837aa0986e64cf6069dcbf12f3aeae1919bc Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:10:28 -0600 Subject: [PATCH 06/15] Fix CI link check and harden Kapa network errors Co-Authored-By: Warp Agent --- src/components/KapaChatLauncher.tsx | 14 +++++++++++++- .../troubleshooting-and-support/known-issues.mdx | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx index fdd5a540b..5dbcf308d 100644 --- a/src/components/KapaChatLauncher.tsx +++ b/src/components/KapaChatLauncher.tsx @@ -78,6 +78,18 @@ function isAnswerUncertain(metadata: unknown) { function isValidEmailAddress(value: string) { return emailPattern.test(value.trim()); } +function getChatErrorMessage(error: unknown) { + const message = typeof error === 'string' ? error : String(error ?? ''); + const normalized = message.toLowerCase(); + const looksLikeBlockedNetworkError = + normalized.includes('network error while fetching answer') || + normalized.includes('failed to fetch') || + normalized.includes('err_blocked_by_client'); + if (looksLikeBlockedNetworkError) { + return "Couldn't reach the chat service. If you use an ad blocker or privacy extension, allow kapa.ai and proxy.kapa.ai, then try again."; + } + return message; +} const CHAT_LANGUAGE_ALIASES: Record = { @@ -848,7 +860,7 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio ))} - {error ?
{error}
: null} + {error ?
{getChatErrorMessage(error)}
: null}
diff --git a/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx b/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx index 6aa4886d2..90584ef4b 100644 --- a/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx +++ b/src/content/docs/support-and-community/troubleshooting-and-support/known-issues.mdx @@ -108,7 +108,7 @@ Warp's direct Streamable HTTP and SSE connections do not currently interoperate Configure the server as a **CLI Server (Command)** through the `mcp-remote` STDIO proxy instead of connecting to its HTTP or SSE URL directly. This workaround requires Node.js because it uses `npx`. The proxy communicates with Warp over STDIO and forwards requests to the remote HTTP endpoint. -In the Warp app, [add an MCP server](/agent-platform/capabilities/mcp/#adding-an-mcp-server) and paste a JSON configuration. For example, connect to Unblocked with: +In the Warp app, [add an MCP server](/agents/capabilities/mcp/#adding-an-mcp-server) and paste a JSON configuration. For example, connect to Unblocked with: ```json { From 56602dcd1cbe6be1ef868d9ff5f246025ef543b0 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:36:21 -0600 Subject: [PATCH 07/15] Restore conservative redirect set in vercel config Co-Authored-By: Warp Agent --- vercel.json | 1773 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 1729 insertions(+), 44 deletions(-) diff --git a/vercel.json b/vercel.json index 7ea3fe3a4..b3462d7b6 100644 --- a/vercel.json +++ b/vercel.json @@ -365,6 +365,11 @@ "destination": "/terminal/input/classic-input/", "statusCode": 308 }, + { + "source": "/~/revisions/pyklxx5pdxve9wvizjl3/features/entry", + "destination": "/terminal/entry/", + "statusCode": 308 + }, { "source": "/platform/api-sdk", "destination": "/reference/api-and-sdk/", @@ -560,6 +565,281 @@ "destination": "/agent-platform/capabilities/web-search/", "statusCode": 308 }, + { + "source": "/agent-platform/agent-platform/active-ai", + "destination": "/agent-platform/local-agents/active-ai/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/active-ai#next-command", + "destination": "/agent-platform/local-agents/active-ai/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/active-ai#suggested-code-diffs", + "destination": "/agent-platform/local-agents/active-ai/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/agent-modality-beta", + "destination": "/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/agent/agents-overview", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/agent/using-agents/agent-profiles-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/agents-md", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/agents-overview", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/ai", + "destination": "/agent-platform/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/ai-faqs", + "destination": "/agent-platform/getting-started/faqs/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/ai-faqs#gathering-ai-debugging-id", + "destination": "/agent-platform/getting-started/faqs/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/ai-model-choice", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/ambient-agents/ambient-agents-overview", + "destination": "/platform/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/autonomy", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/autonomy/agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/autonomy/run-to-completion", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/cloud-agents/cloud-agents-platform", + "destination": "/platform/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/cloud-agents/warp-platform", + "destination": "/platform/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/conversation-forking", + "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/full-terminal-use", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/full-terminal-use#session-level-approvals", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/generate", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/integrations/github-actions/readme", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/integrations/integrations-overview", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/model-choice", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/slash-commands", + "destination": "/agent-platform/capabilities/slash-commands/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents#codebase-context", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents#windows", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context", + "destination": "/agent-platform/local-agents/agent-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context#attaching-blocks-as-context", + "destination": "/agent-platform/local-agents/agent-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/blocks-as-context", + "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/blocks-as-context#attaching-blocks-as-context", + "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/images-as-context", + "destination": "/agent-platform/local-agents/agent-context/images-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/selection-as-context", + "destination": "/agent-platform/local-agents/agent-context/selection-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/urls-as-context", + "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/using-to-add-context", + "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-conversations", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-conversations/conversation-forking", + "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions#agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions#agent-profiles", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-tasklists", + "destination": "/agent-platform/capabilities/task-lists/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/managing-agents", + "destination": "/platform/managing-cloud-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/managing-agents#in-app-agent-notifications", + "destination": "/platform/managing-cloud-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/model-choice", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/model-choice#available-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/model-choice#configuring-models-per-agent-profile", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/model-choice#how-to-change-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/planning", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/third-party-cli-agents", + "destination": "/agent-platform/cli-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/web-search", + "destination": "/agent-platform/capabilities/web-search/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/voice", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/warp-ai", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, { "source": "/agent-platform/agents/active-ai", "destination": "/agent-platform/local-agents/active-ai/", @@ -900,6 +1180,11 @@ "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, + { + "source": "/agent-platform/features/ai-and-ask-warp", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, { "source": "/agent-platform/features/ai-and-ask-warp-ai", "destination": "/agent-platform/local-agents/overview/", @@ -1095,6 +1380,11 @@ "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, + { + "source": "/agent-platform/features/warp-ai/agent-mode#examples-of-coding-capabilities", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, { "source": "/agent-platform/features/warp-ai/ai-command-search", "destination": "/agent-platform/local-agents/overview/", @@ -1515,6 +1805,11 @@ "destination": "/terminal/appearance/custom-themes/", "statusCode": 308 }, + { + "source": "/appearance/custom-themes.git", + "destination": "/terminal/appearance/custom-themes/", + "statusCode": 308 + }, { "source": "/appearance/input-position", "destination": "/terminal/appearance/input-position/", @@ -1530,6 +1825,11 @@ "destination": "/terminal/appearance/prompt/", "statusCode": 308 }, + { + "source": "/appearance/prompt#custom-prompt-compatibility-table", + "destination": "/terminal/appearance/prompt/#shell-prompt-compatibility-table", + "statusCode": 308 + }, { "source": "/appearance/size-opacity-blurring", "destination": "/terminal/appearance/size-opacity-blurring/", @@ -1585,6 +1885,11 @@ "destination": "/changelog/rss.xml", "statusCode": 308 }, + { + "source": "/changelog/url/docs.warp.dev/getting-started/changelog", + "destination": "/changelog/", + "statusCode": 308 + }, { "source": "/changelog/warp/getting-started/changelog", "destination": "/changelog/", @@ -1745,6 +2050,16 @@ "destination": "/terminal/command-completions/completions/", "statusCode": 308 }, + { + "source": "/features/completions#how-to-access-it", + "destination": "/terminal/command-completions/completions/", + "statusCode": 308 + }, + { + "source": "/features/completions#supported-completion-specs", + "destination": "/terminal/command-completions/completions/", + "statusCode": 308 + }, { "source": "/features/customize/custom-keyboard-shortcuts", "destination": "/getting-started/keyboard-shortcuts/", @@ -1906,13 +2221,33 @@ "statusCode": 308 }, { - "source": "/features/quit-warning", - "destination": "/terminal/more-features/quit-warning/", + "source": "/features/prompt#custom-prompt", + "destination": "/terminal/appearance/prompt/", "statusCode": 308 }, { - "source": "/features/session-management-and-restoration", - "destination": "/terminal/sessions/", + "source": "/features/prompt#custom-prompt-compatibility-table", + "destination": "/terminal/appearance/prompt/", + "statusCode": 308 + }, + { + "source": "/features/prompt#how-it-works", + "destination": "/terminal/appearance/prompt/", + "statusCode": 308 + }, + { + "source": "/features/prompt#how-to-access-it", + "destination": "/terminal/appearance/prompt/", + "statusCode": 308 + }, + { + "source": "/features/quit-warning", + "destination": "/terminal/more-features/quit-warning/", + "statusCode": 308 + }, + { + "source": "/features/session-management-and-restoration", + "destination": "/terminal/sessions/", "statusCode": 308 }, { @@ -1940,6 +2275,11 @@ "destination": "/terminal/sessions/", "statusCode": 308 }, + { + "source": "/features/sessions/README", + "destination": "/terminal/sessions/", + "statusCode": 308 + }, { "source": "/features/sessions/launch-configurations", "destination": "/terminal/sessions/launch-configurations/", @@ -2125,6 +2465,11 @@ "destination": "/terminal/windows/global-hotkey/", "statusCode": 308 }, + { + "source": "/features/windows/hotkey-window#dedicated-window", + "destination": "/terminal/windows/global-hotkey/", + "statusCode": 308 + }, { "source": "/features/windows/split-panes", "destination": "/terminal/windows/split-panes/", @@ -2200,6 +2545,26 @@ "destination": "/getting-started/quickstart/installation-and-setup/", "statusCode": 308 }, + { + "source": "/getting-started/getting-started-with-warp#appimage", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, + { + "source": "/getting-started/getting-started-with-warp#arch-linux-based-distributions", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, + { + "source": "/getting-started/getting-started-with-warp#logging-into-warp", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, + { + "source": "/getting-started/getting-started-with-warp#logging-into-warp-required", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, { "source": "/getting-started/getting-started-with-warp-on-linux", "destination": "/getting-started/quickstart/installation-and-setup/", @@ -2270,6 +2635,11 @@ "destination": "/getting-started/quickstart/installation-and-setup/", "statusCode": 308 }, + { + "source": "/getting-started/quickstart-guide/README", + "destination": "/quickstart/", + "statusCode": 308 + }, { "source": "/getting-started/quickstart-guide/agents-in-warp", "destination": "/agent-platform/getting-started/agents-in-warp/", @@ -2375,6 +2745,11 @@ "destination": "/quickstart/", "statusCode": 308 }, + { + "source": "/readme", + "destination": "/", + "statusCode": 308 + }, { "source": "/reference/agent-api-and-sdk", "destination": "/reference/api-and-sdk/", @@ -2485,6 +2860,21 @@ "destination": "/reference/api-and-sdk/troubleshooting/errors/resource-unavailable/", "statusCode": 308 }, + { + "source": "/reference/cli#api-key-authentication", + "destination": "/reference/cli/api-keys/", + "statusCode": 308 + }, + { + "source": "/reference/cli#quickstart-guide", + "destination": "/reference/cli/quickstart/", + "statusCode": 308 + }, + { + "source": "/reference/cli/README.md#api-key-authentication", + "destination": "/reference/cli/api-keys/", + "statusCode": 308 + }, { "source": "/reference/cli/integrations-and-environments", "destination": "/reference/cli/integration-setup/", @@ -2505,11 +2895,31 @@ "destination": "/reference/cli/", "statusCode": 308 }, + { + "source": "/reference/developers/cli#api-key-authentication", + "destination": "/reference/cli/api-keys/#authenticating-with-api-keys", + "statusCode": 308 + }, + { + "source": "/reference/developers/cli#generating-api-keys", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/reference/developers/cli#linux", + "destination": "/reference/cli/", + "statusCode": 308 + }, { "source": "/reference/integrations/integrations-overview/integrations-and-environments", "destination": "/reference/cli/integration-setup/", "statusCode": 308 }, + { + "source": "/reference/integrations/integrations-overview/integrations-and-environments#creating-an-environment", + "destination": "/reference/cli/integration-setup/#step-1-creating-an-environment", + "statusCode": 308 + }, { "source": "/reference/keybindings", "destination": "/getting-started/keyboard-shortcuts/", @@ -2525,6 +2935,11 @@ "destination": "/reference/api-and-sdk/", "statusCode": 308 }, + { + "source": "/reference/platform/agent-api-and-sdk#agent-sdk", + "destination": "/reference/api-and-sdk/", + "statusCode": 308 + }, { "source": "/reference/platform/agent-api-and-sdk/agent", "destination": "/reference/api-and-sdk/", @@ -2545,6 +2960,11 @@ "destination": "/reference/cli/", "statusCode": 308 }, + { + "source": "/reference/platform/cli#api-key-authentication", + "destination": "/reference/cli/api-keys/", + "statusCode": 308 + }, { "source": "/reference/platform/cli/api-keys", "destination": "/reference/cli/api-keys/", @@ -2605,6 +3025,11 @@ "destination": "/getting-started/keyboard-shortcuts/", "statusCode": 308 }, + { + "source": "/support-and-community/community/refer-a-friend#referral-program-terms-and-conditions", + "destination": "/support-and-community/community/refer-a-friend/", + "statusCode": 308 + }, { "source": "/support-and-community/features/network-log", "destination": "/support-and-community/privacy-and-security/network-log/", @@ -2650,6 +3075,31 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, + { + "source": "/support-and-community/help/known-issues#auto-update-on-macos-ventura", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/help/known-issues#debugging", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/help/known-issues#linux-workarounds", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/help/known-issues#list-of-incompatible-tools", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/help/known-issues#ssh-to-local-network-device-is-denied", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, { "source": "/support-and-community/help/licenses", "destination": "/support-and-community/community/open-source-licenses/", @@ -2670,21 +3120,41 @@ "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", "statusCode": 308 }, + { + "source": "/support-and-community/help/sending-us-feedback#gathering-warp-logs", + "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", + "statusCode": 308 + }, { "source": "/support-and-community/help/troubleshooting-login-issues", "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", "statusCode": 308 }, + { + "source": "/support-and-community/help/troubleshooting-login-issues#how-to-get-an-auth-token-to-login", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, { "source": "/support-and-community/help/uninstalling-warp", "destination": "/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/", "statusCode": 308 }, + { + "source": "/support-and-community/help/uninstalling-warp#removing-warp-login-settings-files-log-and-database-1", + "destination": "/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/", + "statusCode": 308 + }, { "source": "/support-and-community/help/updating-warp", "destination": "/support-and-community/troubleshooting-and-support/updating-warp/", "statusCode": 308 }, + { + "source": "/support-and-community/help/updating-warp#auto-update-issues", + "destination": "/support-and-community/troubleshooting-and-support/updating-warp/", + "statusCode": 308 + }, { "source": "/support-and-community/help/using-warp-offline", "destination": "/support-and-community/troubleshooting-and-support/using-warp-offline/", @@ -2750,6 +3220,16 @@ "destination": "/support-and-community/privacy-and-security/privacy/", "statusCode": 308 }, + { + "source": "/support-and-community/privacy/privacy#exhaustive-telemetry-table", + "destination": "/support-and-community/privacy-and-security/privacy/", + "statusCode": 308 + }, + { + "source": "/support-and-community/privacy/privacy#telemetry-what-usage-data-are-you-collecting-and-why", + "destination": "/support-and-community/privacy-and-security/privacy/", + "statusCode": 308 + }, { "source": "/support-and-community/privacy/secret-redaction", "destination": "/support-and-community/privacy-and-security/secret-redaction/", @@ -2775,6 +3255,36 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/known-issues#debugging", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/known-issues#linux-1", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/known-issues#list-of-incompatible-tools", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/known-issues#pwsh", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/known-issues#shells", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/known-issues#windows-1", + "destination": "/support-and-community/troubleshooting-and-support/known-issues/", + "statusCode": 308 + }, { "source": "/support-and-community/support-and-billing/licenses", "destination": "/support-and-community/community/open-source-licenses/", @@ -2800,6 +3310,11 @@ "destination": "/support-and-community/plans-and-billing/add-on-credits/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/plans-and-pricing/add-on-credits#id-2.-enable-auto-reload", + "destination": "/support-and-community/plans-and-billing/add-on-credits/", + "statusCode": 308 + }, { "source": "/support-and-community/support-and-billing/plans-and-pricing/ai-credits", "destination": "/support-and-community/plans-and-billing/credits/", @@ -2810,6 +3325,11 @@ "destination": "/support-and-community/plans-and-billing/credits/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/plans-and-pricing/ai-requests#how-are-warp-ai-requests-calculated", + "destination": "/support-and-community/plans-and-billing/credits/", + "statusCode": 308 + }, { "source": "/support-and-community/plans-and-billing/bring-your-own-api-key/:path*", "destination": "/agent-platform/inference/bring-your-own-api-key/", @@ -2820,11 +3340,31 @@ "destination": "/agent-platform/inference/bring-your-own-api-key/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/plans-and-pricing/bring-your-own-api-key#enabling-byok", + "destination": "/agent-platform/inference/bring-your-own-api-key/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/plans-and-pricing/bring-your-own-api-key#how-does-byok-work", + "destination": "/agent-platform/inference/bring-your-own-api-key/", + "statusCode": 308 + }, { "source": "/support-and-community/support-and-billing/plans-and-pricing/pricing-faqs", "destination": "/support-and-community/plans-and-billing/pricing-faqs/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/plans-and-pricing/pricing-faqs#how-can-i-subscribe-to-a-warp-enterprise-plan", + "destination": "/support-and-community/plans-and-billing/pricing-faqs/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/plans-and-pricing/pricing-faqs#how-can-i-upgrade-and-subscribe-to-a-warp-plan", + "destination": "/support-and-community/plans-and-billing/pricing-faqs/", + "statusCode": 308 + }, { "source": "/support-and-community/support-and-billing/plans-and-pricing/reload-credits-add-on-credits", "destination": "/support-and-community/plans-and-billing/add-on-credits/", @@ -2850,6 +3390,21 @@ "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/sending-us-feedback#gathering-ai-debugging-id", + "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/sending-us-feedback#gathering-warp-logs", + "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/sending-us-feedback#windows", + "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", + "statusCode": 308 + }, { "source": "/support-and-community/support-and-billing/subscription-management", "destination": "/support-and-community/plans-and-billing/plans-pricing-refunds/", @@ -2860,6 +3415,21 @@ "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", "statusCode": 308 }, + { + "source": "/support-and-community/support-and-billing/troubleshooting-login-issues#blocked-for-terms-of-service-violation", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/troubleshooting-login-issues#flagged-as-fraudulent", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/support-and-community/support-and-billing/troubleshooting-login-issues#how-to-get-an-auth-token-to-login", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, { "source": "/support-and-community/support-and-billing/uninstalling-warp", "destination": "/support-and-community/troubleshooting-and-support/logging-out-and-uninstalling/", @@ -2935,6 +3505,11 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, + { + "source": "/terminal/appearance/prompt#custom-prompt", + "destination": "/terminal/appearance/prompt/", + "statusCode": 308 + }, { "source": "/terminal/command-input/command-suggestions", "destination": "/terminal/command-completions/completions/", @@ -4100,6 +4675,41 @@ "destination": "/platform/managing-cloud-agents/", "statusCode": 308 }, + { + "source": "/getting-started/readme", + "destination": "/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme-1/coding-in-warp", + "destination": "/getting-started/quickstart/coding-in-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme-1/customizing-warp", + "destination": "/getting-started/quickstart/customizing-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme-1/installation-and-setup", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme/coding-in-warp", + "destination": "/getting-started/quickstart/coding-in-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme/customizing-warp", + "destination": "/getting-started/quickstart/customizing-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme/installation-and-setup", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, { "source": "/platform/warp-platform", "destination": "/reference/", @@ -4346,53 +4956,258 @@ "statusCode": 308 }, { - "source": "/agent-platform/agents/active-ai/", + "source": "/agent-platform/agent-platform/active-ai/", "destination": "/agent-platform/local-agents/active-ai/", "statusCode": 308 }, { - "source": "/agent-platform/agents/agent-modality-beta/", + "source": "/agent-platform/agent-platform/agent-modality-beta/", "destination": "/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/", "statusCode": 308 }, { - "source": "/agent-platform/agents/agents-md/", + "source": "/agent-platform/agent-platform/agent/agents-overview/", "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agents/agents-overview/", - "destination": "/agent-platform/local-agents/overview/", + "source": "/agent-platform/agent-platform/agent/using-agents/agent-profiles-permissions/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agent-platform/agents/ai/", - "destination": "/agent-platform/", + "source": "/agent-platform/agent-platform/agents-md/", + "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agents/ai-commander/", + "source": "/agent-platform/agent-platform/agents-overview/", "destination": "/agent-platform/local-agents/overview/", "statusCode": 308 }, { - "source": "/agent-platform/agents/ai-commands/", - "destination": "/agent-platform/local-agents/overview/", + "source": "/agent-platform/agent-platform/ai/", + "destination": "/agent-platform/", "statusCode": 308 }, { - "source": "/agent-platform/agents/ai-faqs/", + "source": "/agent-platform/agent-platform/ai-faqs/", "destination": "/agent-platform/getting-started/faqs/", "statusCode": 308 }, { - "source": "/agent-platform/agents/ai-getting-started/", - "destination": "/agent-platform/local-agents/overview/", + "source": "/agent-platform/agent-platform/ai-model-choice/", + "destination": "/agent-platform/inference/model-choice/", "statusCode": 308 }, { - "source": "/agent-platform/agents/autonomy/", - "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "source": "/agent-platform/agent-platform/ambient-agents/ambient-agents-overview/", + "destination": "/platform/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/autonomy/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/autonomy/agent-permissions/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/autonomy/run-to-completion/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/cloud-agents/cloud-agents-platform/", + "destination": "/platform/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/cloud-agents/warp-platform/", + "destination": "/platform/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/conversation-forking/", + "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/full-terminal-use/", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/generate/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/integrations/github-actions/readme/", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/integrations/integrations-overview/", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/model-choice/", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/slash-commands/", + "destination": "/agent-platform/capabilities/slash-commands/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/", + "destination": "/agent-platform/local-agents/agent-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/blocks-as-context/", + "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/images-as-context/", + "destination": "/agent-platform/local-agents/agent-context/images-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/selection-as-context/", + "destination": "/agent-platform/local-agents/agent-context/selection-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/urls-as-context/", + "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-context/using-to-add-context/", + "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-conversations/", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-conversations/conversation-forking/", + "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-permissions/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-profiles-permissions/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/agent-tasklists/", + "destination": "/agent-platform/capabilities/task-lists/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/managing-agents/", + "destination": "/platform/managing-cloud-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/model-choice/", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/planning/", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/third-party-cli-agents/", + "destination": "/agent-platform/cli-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/using-agents/web-search/", + "destination": "/agent-platform/capabilities/web-search/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/voice/", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent-platform/warp-ai/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/active-ai/", + "destination": "/agent-platform/local-agents/active-ai/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/agent-modality-beta/", + "destination": "/agent-platform/local-agents/interacting-with-agents/terminal-and-agent-modes/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/agents-md/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/agents-overview/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/ai/", + "destination": "/agent-platform/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/ai-commander/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/ai-commands/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/ai-faqs/", + "destination": "/agent-platform/getting-started/faqs/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/ai-getting-started/", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agents/autonomy/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { @@ -5200,6 +6015,11 @@ "destination": "/changelog/rss.xml", "statusCode": 308 }, + { + "source": "/changelog/url/docs.warp.dev/getting-started/changelog/", + "destination": "/changelog/", + "statusCode": 308 + }, { "source": "/changelog/warp/getting-started/changelog/", "destination": "/changelog/", @@ -7510,6 +8330,41 @@ "destination": "/platform/managing-cloud-agents/", "statusCode": 308 }, + { + "source": "/getting-started/readme/", + "destination": "/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme-1/coding-in-warp/", + "destination": "/getting-started/quickstart/coding-in-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme-1/customizing-warp/", + "destination": "/getting-started/quickstart/customizing-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme-1/installation-and-setup/", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme/coding-in-warp/", + "destination": "/getting-started/quickstart/coding-in-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme/customizing-warp/", + "destination": "/getting-started/quickstart/customizing-warp/", + "statusCode": 308 + }, + { + "source": "/getting-started/readme/installation-and-setup/", + "destination": "/getting-started/quickstart/installation-and-setup/", + "statusCode": 308 + }, { "source": "/platform/warp-platform/", "destination": "/reference/", @@ -7620,6 +8475,11 @@ "destination": "/agent-platform/capabilities/mcp/", "statusCode": 308 }, + { + "source": "/getting-started/readme-1", + "destination": "/quickstart/", + "statusCode": 308 + }, { "source": "/support-and-billing/plans-and-pricing/ai-credits", "destination": "/support-and-community/plans-and-billing/", @@ -7650,6 +8510,11 @@ "destination": "/agent-platform/inference/model-choice/", "statusCode": 308 }, + { + "source": "/getting-started/readme/agents-in-warp", + "destination": "/agent-platform/local-agents/overview/", + "statusCode": 308 + }, { "source": "/privacy/privacy", "destination": "/support-and-community/privacy-and-security/privacy/", @@ -8075,6 +8940,16 @@ "destination": "/agent-platform/capabilities/planning/", "statusCode": 308 }, + { + "source": "/agents/using-agents/model-choice#available-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/model-choice#how-to-change-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, { "source": "/guides/agent-workflows", "destination": "/guides/agent-workflows/how-to-review-ai-generated-code/", @@ -8086,68 +8961,578 @@ "statusCode": 308 }, { - "source": "/agent-platform/cloud-agents-and-orchestration/team-access-billing-and-identity", - "destination": "/platform/team-access-billing-and-identity/", + "source": "/agent-platform/agent/using-agents#agents-in-warp", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/agent-platform/warps-agent/agent-context/blocks-as-context", - "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", + "source": "/agent-platform/agent/using-agents#entering-agent-mode", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/agent-platform/warps-agent/agent-context/urls-as-context", - "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", + "source": "/agent-platform/agent/using-agents#what-is-agent-mode", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/agent-platform/warps-agent/agent-context/using-to-add-context", - "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", + "source": "/agent-platform/agent/using-agents/agent-conversations#conversations-with-warps-agent", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/agent-platform/warps-agent/capabilities-overview/web-search", - "destination": "/agent-platform/capabilities/web-search/", + "source": "/agent-platform/agent/using-agents/agent-conversations#starting-a-new-conversation", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/agent-platform/warps-agent/interacting-with-agents/conversation-forking", - "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", + "source": "/agent-platform/agent/using-agents/agent-conversations#staying-in-a-conversation-follow-ups", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/agent-platform/warps-agent/interactive-code-review", - "destination": "/agent-platform/local-agents/interactive-code-review/", + "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agents/using-agents/agent-permissions", + "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#agent-profiles", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/agents/using-agents/agent-permissions/", + "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#command-allowlist", "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/developers/cli", - "destination": "/reference/cli/", + "source": "/agent-platform/agent/using-agents/agent-profiles-permissions#command-denylist", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", "statusCode": 308 }, { - "source": "/enterprise/enterprise-features", - "destination": "/enterprise/enterprise-features/architecture-and-deployment/", + "source": "/agent-platform/agent/using-agents/managing-agents#agent-management-panel", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/features/ai", - "destination": "/agent-platform/", + "source": "/agent-platform/agent/using-agents/managing-agents#agent-status-indicators", + "destination": "/agent-platform/local-agents/interacting-with-agents/", "statusCode": 308 }, { - "source": "/features/warp-ai/agent-mode", - "destination": "/agent-platform/", + "source": "/agent-platform/agent/using-agents/managing-agents#in-app-agent-notifications", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/model-choice#auto-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/model-choice#available-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/model-choice#how-to-change-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/model-choice#model-fallback", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/planning#creating-a-plan", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/planning#executing-a-plan", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/planning#monitoring-progress", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/using-agents/planning#reviewing-and-editing", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/voice#initial-setup", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/voice#sample-use-cases", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/agent/voice#using-voice", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/cloud-agents-and-orchestration/team-access-billing-and-identity", + "destination": "/platform/team-access-billing-and-identity/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/blocks-as-context", + "destination": "/agent-platform/local-agents/agent-context/blocks-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#adding-an-mcp-server", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#adding-multiple-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#authentication-in-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#debugging-mcp", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#file-based-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#how-to-access-mcp-server-settings", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#sharing-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/mcp#where-mcp-logs-are-stored", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/urls-as-context", + "destination": "/agent-platform/local-agents/agent-context/urls-as-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/agent-context/using-to-add-context", + "destination": "/agent-platform/local-agents/agent-context/using-to-add-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#agent-profiles", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#command-allowlist", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/agent-profiles-permissions#command-denylist", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#codebase-indexing-states", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#ignore-files", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#indexing-your-codebase", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/codebase-context#when-does-codebase-syncing-happen", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/full-terminal-use#configuring-agent-permissions-and-autonomy", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/full-terminal-use#how-full-terminal-use-works", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/full-terminal-use#overview", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/model-choice#auto-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/model-choice#how-to-change-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/model-choice#model-fallback", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/rules#how-to-access-rules", + "destination": "/agent-platform/capabilities/rules/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/rules#project-rules", + "destination": "/agent-platform/capabilities/rules/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/session-sharing#key-capabilities", + "destination": "/agent-platform/local-agents/session-sharing/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/session-sharing#sharing-a-session", + "destination": "/agent-platform/local-agents/session-sharing/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/session-sharing#viewing-shared-sessions", + "destination": "/agent-platform/local-agents/session-sharing/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-interactions", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-skill-file", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-skill-with-arguments", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#example-skill-without-arguments", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#how-argument-substitution-works", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#how-skills-work", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#key-features", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#project-skills", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#project-vs-root-directory-skills", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#root-directory-skills-global", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#skill-name-conflicts", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#step-1-choose-a-location", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/skills#step-4-add-content", + "destination": "/agent-platform/capabilities/skills/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/capabilities-overview/web-search", + "destination": "/agent-platform/capabilities/web-search/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents#conversations-with-warps-agent", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents#panel-layout", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents#starting-a-new-conversation", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents#staying-in-a-conversation-follow-ups", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents/conversation-forking", + "destination": "/agent-platform/local-agents/interacting-with-agents/conversation-forking/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents/voice#initial-setup", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents/voice#sample-use-cases", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interacting-with-agents/voice#using-voice", + "destination": "/agent-platform/local-agents/interacting-with-agents/voice/", + "statusCode": 308 + }, + { + "source": "/agent-platform/warps-agent/interactive-code-review", + "destination": "/agent-platform/local-agents/interactive-code-review/", + "statusCode": 308 + }, + { + "source": "/agents/active-ai#next-command", + "destination": "/agent-platform/local-agents/active-ai/", + "statusCode": 308 + }, + { + "source": "/agents/active-ai#prompt-suggestions", + "destination": "/agent-platform/local-agents/active-ai/", + "statusCode": 308 + }, + { + "source": "/agents/full-terminal-use#configuring-agent-permissions-and-autonomy", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agents/full-terminal-use#how-full-terminal-use-works", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agents/full-terminal-use#overview", + "destination": "/agent-platform/capabilities/full-terminal-use/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents#agents-in-warp", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents#entering-agent-mode", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents#what-is-agent-mode", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-conversations#conversations-with-warps-agent", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-conversations#starting-a-new-conversation", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-conversations#staying-in-a-conversation-follow-ups", + "destination": "/agent-platform/local-agents/interacting-with-agents/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-profiles-permissions#agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-profiles-permissions#agent-profiles", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-profiles-permissions#command-allowlist", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-profiles-permissions#command-denylist", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-permissions", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/agent-permissions/", + "destination": "/agent-platform/capabilities/agent-profiles-permissions/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/model-choice#auto-models", + "destination": "/agent-platform/inference/model-choice/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/planning#creating-a-plan", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/planning#executing-a-plan", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/planning#reviewing-and-editing", + "destination": "/agent-platform/capabilities/planning/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/web-search#how-web-search-works-in-warp", + "destination": "/agent-platform/capabilities/web-search/", + "statusCode": 308 + }, + { + "source": "/agents/using-agents/web-search#when-the-agent-uses-web-search", + "destination": "/agent-platform/capabilities/web-search/", + "statusCode": 308 + }, + { + "source": "/code/codebase-context#codebase-indexing-states", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/code/codebase-context#indexing-your-codebase", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/code/codebase-context#when-does-codebase-syncing-happen", + "destination": "/agent-platform/capabilities/codebase-context/", + "statusCode": 308 + }, + { + "source": "/community/refer-a-friend#all-other-referral-tiers", + "destination": "/support-and-community/community/refer-a-friend/", + "statusCode": 308 + }, + { + "source": "/community/refer-a-friend#international-users", + "destination": "/support-and-community/community/refer-a-friend/", + "statusCode": 308 + }, + { + "source": "/community/refer-a-friend#referral-rewards-program", + "destination": "/support-and-community/community/refer-a-friend/", + "statusCode": 308 + }, + { + "source": "/community/refer-a-friend#shipping-time-frame", + "destination": "/support-and-community/community/refer-a-friend/", + "statusCode": 308 + }, + { + "source": "/community/warp-preview-and-alpha-program#getting-started-with-warp-preview", + "destination": "/support-and-community/community/warp-preview-and-alpha-program/", + "statusCode": 308 + }, + { + "source": "/community/warp-preview-and-alpha-program#important-notes", + "destination": "/support-and-community/community/warp-preview-and-alpha-program/", + "statusCode": 308 + }, + { + "source": "/community/warp-preview-and-alpha-program#key-warp-preview-features", + "destination": "/support-and-community/community/warp-preview-and-alpha-program/", + "statusCode": 308 + }, + { + "source": "/developers/cli", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/enterprise/enterprise-features", + "destination": "/enterprise/enterprise-features/architecture-and-deployment/", + "statusCode": 308 + }, + { + "source": "/features/ai", + "destination": "/agent-platform/", + "statusCode": 308 + }, + { + "source": "/features/warp-ai/agent-mode", + "destination": "/agent-platform/", "statusCode": 308 }, { @@ -8160,11 +9545,166 @@ "destination": "/support-and-community/troubleshooting-and-support/known-issues/", "statusCode": 308 }, + { + "source": "/help/troubleshooting-login-issues#all-browsers", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/help/troubleshooting-login-issues#cant-open-warp-from-sso", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/help/troubleshooting-login-issues#cant-sign-up-for-or-log-into-warp", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/help/troubleshooting-login-issues#proxies", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/help/troubleshooting-login-issues#safari", + "destination": "/support-and-community/troubleshooting-and-support/troubleshooting-login-issues/", + "statusCode": 308 + }, + { + "source": "/integrations/github-actions#id-1.-responding-to-comments-with-mentions", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/integrations/github-actions#id-2.-automated-pull-request-review", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/integrations/github-actions#id-3.-automatically-fix-issues", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/integrations/github-actions#quickstart", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/integrations/github-actions#requirements", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, + { + "source": "/integrations/github-actions#what-the-github-actions-integration-does", + "destination": "/platform/integrations/github-actions/", + "statusCode": 308 + }, { "source": "/integrations/integrations-and-plugins", "destination": "/platform/integrations/", "statusCode": 308 }, + { + "source": "/integrations/linear#how-to-configure-the-integration", + "destination": "/platform/integrations/linear/", + "statusCode": 308 + }, + { + "source": "/integrations/linear#requirements", + "destination": "/platform/integrations/linear/", + "statusCode": 308 + }, + { + "source": "/integrations/linear#using-warp-inside-linear", + "destination": "/platform/integrations/linear/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#joining-the-live-remote-session", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#monitoring-agent-progress", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#overview", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#pull-requests-and-output", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#requirements", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#triggering-an-agent", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/integrations/slack#using-warp-inside-slack", + "destination": "/platform/integrations/slack/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#adding-an-mcp-server", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#adding-multiple-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#authentication-in-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#debugging-mcp", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#how-to-access-mcp-server-settings", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#model-context-protocol-mcp", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#sharing-mcp-servers", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/mcp#where-mcp-logs-are-stored", + "destination": "/agent-platform/capabilities/mcp/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/rules#how-to-access-rules", + "destination": "/agent-platform/capabilities/rules/", + "statusCode": 308 + }, + { + "source": "/knowledge-and-collaboration/rules#project-rules", + "destination": "/agent-platform/capabilities/rules/", + "statusCode": 308 + }, { "source": "/platform/agent-api-and-sdk/agent", "destination": "/reference/api-and-sdk/", @@ -8175,11 +9715,156 @@ "destination": "/reference/api-and-sdk/", "statusCode": 308 }, + { + "source": "/platform/cli#api-key-authentication", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#bundled-with-warp", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#id-2.-authenticate", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#id-3.-run-an-agent", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#id-4.-add-github-context-optional", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#id-5.-next-steps", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#interactive-login-local-machines", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#running-agents", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#running-locally-warp-agent-run", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#running-the-cli", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#standalone-package", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli#what-is-the-warp-cli", + "destination": "/reference/cli/", + "statusCode": 308 + }, + { + "source": "/platform/cli/integrations-and-environments#how-integrations-and-environments-work", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/platform/cli/integrations-and-environments#option-1-guided-environment-setup-recommended", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/platform/cli/integrations-and-environments#option-2-create-an-environment-with-the-cli", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/platform/cli/integrations-and-environments#step-1-creating-an-environment", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/platform/cli/integrations-and-environments#step-2-authorizing-github", + "destination": "/platform/integrations/", + "statusCode": 308 + }, + { + "source": "/platform/environments#about-environments", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#create-an-environment-with-guided-setup-recommended", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#hosts-and-environments", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#how-environments-fit-into-the-warp-platform", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#key-features", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#what-happens-at-runtime", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#when-to-use-environments", + "destination": "/platform/environments/", + "statusCode": 308 + }, + { + "source": "/platform/environments#where-to-configure-environments", + "destination": "/platform/environments/", + "statusCode": 308 + }, { "source": "/platform/team-access-billing-and-identity-permissions", "destination": "/agent-platform/", "statusCode": 308 }, + { + "source": "/privacy/privacy#how-to-disable-telemetry-and-crash-reporting", + "destination": "/support-and-community/privacy-and-security/privacy/", + "statusCode": 308 + }, + { + "source": "/privacy/privacy#what-telemetry-data-does-warp-collect-and-why", + "destination": "/support-and-community/privacy-and-security/privacy/", + "statusCode": 308 + }, + { + "source": "/privacy/secret-redaction#how-it-works", + "destination": "/support-and-community/privacy-and-security/secret-redaction/", + "statusCode": 308 + }, + { + "source": "/privacy/secret-redaction#visually-hiding-secrets", + "destination": "/support-and-community/privacy-and-security/secret-redaction/", + "statusCode": 308 + }, { "source": "/support-and-community/troubleshooting-and-support", "destination": "/support-and-community/troubleshooting-and-support/sending-us-feedback/", @@ -8541,4 +10226,4 @@ "statusCode": 308 } ] -} +} \ No newline at end of file From 9838a746b022c1d260f3d1afcb926f305bed429f Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:47:18 -0600 Subject: [PATCH 08/15] Fix Kapa chat copy button icon rendering Co-Authored-By: Warp Agent --- src/components/KapaChatLauncher.css | 5 +++++ src/components/KapaChatLauncher.tsx | 30 +++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/components/KapaChatLauncher.css b/src/components/KapaChatLauncher.css index e33362c08..e6fda41e2 100644 --- a/src/components/KapaChatLauncher.css +++ b/src/components/KapaChatLauncher.css @@ -212,6 +212,11 @@ right: 0.5rem; z-index: 1; } +.sl-kapa-codeblock .copy button svg { + display: block; + width: 0.95rem; + height: 0.95rem; +} .sl-kapa-codeblock pre { margin: 0; diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx index 5dbcf308d..f0483f627 100644 --- a/src/components/KapaChatLauncher.tsx +++ b/src/components/KapaChatLauncher.tsx @@ -6,6 +6,8 @@ import { PUBLIC_KAPA_INTEGRATION_ID, PUBLIC_KAPA_PROJECT_ID } from 'astro:env/cl import { isMac, keymatch } from 'keymatch'; import ReactMarkdown from 'react-markdown'; import { + LuCheck, + LuCopy, LuExternalLink, LuLoaderCircle, LuMessageSquare, @@ -90,6 +92,26 @@ function getChatErrorMessage(error: unknown) { } return message; } +async function copyTextToClipboard(text: string) { + if (navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(text); + return; + } + const textarea = document.createElement('textarea'); + textarea.value = text; + textarea.setAttribute('readonly', ''); + textarea.style.position = 'fixed'; + textarea.style.opacity = '0'; + document.body.appendChild(textarea); + textarea.select(); + try { + if (!document.execCommand('copy')) { + throw new Error('Clipboard copy command failed'); + } + } finally { + textarea.remove(); + } +} const CHAT_LANGUAGE_ALIASES: Record = { @@ -332,7 +354,11 @@ function ChatCodeBlock({ onCopy(); }} > -
+ {copiedCodeKey === copyKey ? ( +
@@ -525,7 +551,7 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio const copyCodeBlock = async (code: string, copyKey: string) => { try { - await navigator.clipboard.writeText(code); + await copyTextToClipboard(code); setCopiedCodeKey(copyKey); window.setTimeout(() => { setCopiedCodeKey((currentKey) => (currentKey === copyKey ? null : currentKey)); From cbbccb955d80e6cc474796977da5195bde826340 Mon Sep 17 00:00:00 2001 From: Danny <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:02:42 -0600 Subject: [PATCH 09/15] Update src/components/KapaChatLauncher.tsx Co-authored-by: oz-for-oss[bot] <277970191+oz-for-oss[bot]@users.noreply.github.com> --- src/components/KapaChatLauncher.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx index f0483f627..a79d553a3 100644 --- a/src/components/KapaChatLauncher.tsx +++ b/src/components/KapaChatLauncher.tsx @@ -234,9 +234,14 @@ async function requestHighlightedPre({ }); highlightInFlight.set(cacheKey, requestPromise); - requestPromise.finally(() => { - highlightInFlight.delete(cacheKey); - }); + requestPromise.then( + () => { + highlightInFlight.delete(cacheKey); + }, + () => { + highlightInFlight.delete(cacheKey); + } + ); return requestPromise; } From a26d44e4fa5d24836297b643b5ff62ef1d6b96d3 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:16:01 -0600 Subject: [PATCH 10/15] Harden support handoff with captcha and abuse guards Co-Authored-By: Warp Agent --- src/components/KapaChatLauncher.tsx | 10 ++++- src/pages/api/support-handoff.ts | 66 +++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx index a79d553a3..dc2a79ad2 100644 --- a/src/components/KapaChatLauncher.tsx +++ b/src/components/KapaChatLauncher.tsx @@ -1,7 +1,7 @@ import type { FormEvent, MouseEvent, ReactElement, ReactNode } from 'react'; import * as Popover from '@radix-ui/react-popover'; import { isValidElement, useEffect, useMemo, useRef, useState } from 'react'; -import { KapaProvider, useChat } from '@kapaai/react-sdk'; +import { CaptchaAction, KapaProvider, useCaptcha, useChat } from '@kapaai/react-sdk'; import { PUBLIC_KAPA_INTEGRATION_ID, PUBLIC_KAPA_PROJECT_ID } from 'astro:env/client'; import { isMac, keymatch } from 'keymatch'; import ReactMarkdown from 'react-markdown'; @@ -403,6 +403,7 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio submitQuery, threadId, } = useChat(); + const { executeCaptcha } = useCaptcha(); useEffect(() => { setIsAppleDevice(isMac()); @@ -597,6 +598,11 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio } const conversationLink = buildConversationLink(activeThreadId); + const captcha = await executeCaptcha(CaptchaAction.FeedbackSubmit); + if (!captcha?.token || !captcha?.key) { + setHandoffErrorMessage('Captcha verification failed. Please try again.'); + return; + } setIsSubmittingHandoff(true); setHandoffErrorMessage(null); @@ -615,6 +621,8 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio kapa_project_id: projectId || null, kapa_thread_id: activeThreadId, kapa_conversation_url: conversationLink || null, + captcha_token: captcha.token, + captcha_header: captcha.key, }), }); const payload: HandoffApiSuccess & { message?: string } = await response.json().catch(() => ({})); diff --git a/src/pages/api/support-handoff.ts b/src/pages/api/support-handoff.ts index 3e6f77009..c643793fe 100644 --- a/src/pages/api/support-handoff.ts +++ b/src/pages/api/support-handoff.ts @@ -11,6 +11,8 @@ type HandoffPayload = { kapa_project_id?: unknown; kapa_thread_id?: unknown; kapa_conversation_url?: unknown; + captcha_token?: unknown; + captcha_header?: unknown; }; const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; @@ -18,8 +20,13 @@ const KAPA_ID_PATTERN = /^[a-zA-Z0-9_-]{1,128}$/; const MAX_QUESTION_LENGTH = 4_000; const MAX_TRANSCRIPT_LENGTH = 50_000; const MAX_PAGE_URL_LENGTH = 2_048; +const MAX_CAPTCHA_TOKEN_LENGTH = 4_096; const ALLOWED_PAGE_URL_HOSTS = new Set(['docs.warp.dev', 'localhost']); const ALLOWED_PAGE_URL_SUFFIXES = ['.vercel.app']; +const ALLOWED_CAPTCHA_HEADERS = new Set(['X-RECAPTCHA-ENTERPRISE-TOKEN', 'X-HCAPTCHA-TOKEN']); +const RATE_LIMIT_WINDOW_MS = 10 * 60 * 1000; +const RATE_LIMIT_MAX_REQUESTS = 5; +const rateLimitStore = new Map(); function asTrimmedString(value: unknown) { return typeof value === 'string' ? value.trim() : ''; @@ -49,12 +56,65 @@ function isAllowedPageUrl(url: string) { } } +function isAllowedHostname(hostname: string) { + const lowercasedHostname = hostname.toLowerCase(); + if (ALLOWED_PAGE_URL_HOSTS.has(lowercasedHostname)) return true; + return ALLOWED_PAGE_URL_SUFFIXES.some((suffix) => lowercasedHostname.endsWith(suffix)); +} + +function isAllowedRequestOrigin(request: Request) { + const originHeader = request.headers.get('origin'); + if (!originHeader) return false; + try { + const parsedOrigin = new URL(originHeader); + if (!['http:', 'https:'].includes(parsedOrigin.protocol)) return false; + return isAllowedHostname(parsedOrigin.hostname); + } catch { + return false; + } +} + +function getClientIp(request: Request) { + const forwardedFor = request.headers.get('x-forwarded-for'); + if (forwardedFor) { + const firstIp = forwardedFor.split(',')[0]?.trim(); + if (firstIp) return firstIp; + } + const connectingIp = request.headers.get('cf-connecting-ip')?.trim(); + if (connectingIp) return connectingIp; + const realIp = request.headers.get('x-real-ip')?.trim(); + if (realIp) return realIp; + return 'unknown'; +} + +function isRateLimited(clientIp: string) { + const now = Date.now(); + const existing = rateLimitStore.get(clientIp); + if (!existing || existing.resetAt <= now) { + rateLimitStore.set(clientIp, { count: 1, resetAt: now + RATE_LIMIT_WINDOW_MS }); + return false; + } + existing.count += 1; + if (existing.count > RATE_LIMIT_MAX_REQUESTS) { + return true; + } + rateLimitStore.set(clientIp, existing); + return false; +} + export const POST: APIRoute = async ({ request }) => { const supportHandoffEndpointUrl = SUPPORT_HANDOFF_ENDPOINT_URL?.trim() || ''; const supportHandoffSharedSecret = SUPPORT_HANDOFF_SHARED_SECRET?.trim() || ''; if (!supportHandoffEndpointUrl || !supportHandoffSharedSecret) { return jsonError('Support handoff is not configured.', 503); } + if (!isAllowedRequestOrigin(request)) { + return jsonError('Request origin is not allowed.', 403); + } + const clientIp = getClientIp(request); + if (isRateLimited(clientIp)) { + return jsonError('Too many support handoff attempts. Please try again later.', 429); + } let payload: HandoffPayload; try { @@ -74,6 +134,8 @@ export const POST: APIRoute = async ({ request }) => { const kapaProjectId = asTrimmedString(payload.kapa_project_id); const kapaThreadId = asTrimmedString(payload.kapa_thread_id); const suppliedKapaConversationUrl = asTrimmedString(payload.kapa_conversation_url); + const captchaToken = asTrimmedString(payload.captcha_token); + const captchaHeader = asTrimmedString(payload.captcha_header); if (!question) return jsonError('A question is required.'); if (question.length > MAX_QUESTION_LENGTH) return jsonError('Question is too long.'); @@ -85,6 +147,9 @@ export const POST: APIRoute = async ({ request }) => { } if (!kapaThreadId) return jsonError('Kapa thread ID is required.'); if (!KAPA_ID_PATTERN.test(kapaThreadId)) return jsonError('Kapa thread ID is invalid.'); + if (!captchaToken) return jsonError('Captcha verification is required.'); + if (captchaToken.length > MAX_CAPTCHA_TOKEN_LENGTH) return jsonError('Captcha token is invalid.'); + if (!ALLOWED_CAPTCHA_HEADERS.has(captchaHeader)) return jsonError('Captcha token header is invalid.'); if (kapaProjectId && !KAPA_ID_PATTERN.test(kapaProjectId)) { return jsonError('Kapa project ID is invalid.'); } @@ -117,6 +182,7 @@ export const POST: APIRoute = async ({ request }) => { const forwardHeaders: HeadersInit = { 'content-type': 'application/json', authorization: `Bearer ${supportHandoffSharedSecret}`, + [captchaHeader]: captchaToken, }; let upstreamResponse: Response; From 60154c9323a1eefc7fbd1e1dfe4bf35f2386fcb5 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Tue, 11 Aug 2026 17:43:00 -0600 Subject: [PATCH 11/15] Allow endpoint-only support handoff config Co-Authored-By: Warp Agent --- src/pages/api/support-handoff.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/pages/api/support-handoff.ts b/src/pages/api/support-handoff.ts index c643793fe..bc5a80987 100644 --- a/src/pages/api/support-handoff.ts +++ b/src/pages/api/support-handoff.ts @@ -105,7 +105,7 @@ function isRateLimited(clientIp: string) { export const POST: APIRoute = async ({ request }) => { const supportHandoffEndpointUrl = SUPPORT_HANDOFF_ENDPOINT_URL?.trim() || ''; const supportHandoffSharedSecret = SUPPORT_HANDOFF_SHARED_SECRET?.trim() || ''; - if (!supportHandoffEndpointUrl || !supportHandoffSharedSecret) { + if (!supportHandoffEndpointUrl) { return jsonError('Support handoff is not configured.', 503); } if (!isAllowedRequestOrigin(request)) { @@ -181,9 +181,11 @@ export const POST: APIRoute = async ({ request }) => { const forwardHeaders: HeadersInit = { 'content-type': 'application/json', - authorization: `Bearer ${supportHandoffSharedSecret}`, [captchaHeader]: captchaToken, }; + if (supportHandoffSharedSecret) { + forwardHeaders.authorization = `Bearer ${supportHandoffSharedSecret}`; + } let upstreamResponse: Response; try { From 242739d477d8ee1ff7100648fa07eb1123d04ae5 Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Wed, 12 Aug 2026 10:57:48 -0600 Subject: [PATCH 12/15] Require shared secret for support handoff Fail closed when SUPPORT_HANDOFF_SHARED_SECRET is missing so public requests cannot reach the upstream without auth. Co-Authored-By: Warp Agent --- src/pages/api/support-handoff.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/pages/api/support-handoff.ts b/src/pages/api/support-handoff.ts index bc5a80987..c643793fe 100644 --- a/src/pages/api/support-handoff.ts +++ b/src/pages/api/support-handoff.ts @@ -105,7 +105,7 @@ function isRateLimited(clientIp: string) { export const POST: APIRoute = async ({ request }) => { const supportHandoffEndpointUrl = SUPPORT_HANDOFF_ENDPOINT_URL?.trim() || ''; const supportHandoffSharedSecret = SUPPORT_HANDOFF_SHARED_SECRET?.trim() || ''; - if (!supportHandoffEndpointUrl) { + if (!supportHandoffEndpointUrl || !supportHandoffSharedSecret) { return jsonError('Support handoff is not configured.', 503); } if (!isAllowedRequestOrigin(request)) { @@ -181,11 +181,9 @@ export const POST: APIRoute = async ({ request }) => { const forwardHeaders: HeadersInit = { 'content-type': 'application/json', + authorization: `Bearer ${supportHandoffSharedSecret}`, [captchaHeader]: captchaToken, }; - if (supportHandoffSharedSecret) { - forwardHeaders.authorization = `Bearer ${supportHandoffSharedSecret}`; - } let upstreamResponse: Response; try { From 5b481fc624f8a5a19b32149ce991888d986db84c Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:35:20 -0600 Subject: [PATCH 13/15] Reuse Expressive Code copy button in Kapa chat code blocks The chat's copy button was a one-off lucide SVG inside EC-lookalike markup, so Expressive Code's stylesheet (which paints the icon via button::after mask on an empty inner div) never styled it, leaving a plain clipboard glyph that didn't match docs code blocks. - ChatCodeBlock now emits EC's exact copy markup (aria-live feedback div + button with data-copied/data-code, newlines encoded as \u007f), so ec.css styles it pixel-identical to docs blocks and ec.js attaches its own click handler (navigator.clipboard with execCommand fallback plus the "Copied!" tooltip) via its MutationObserver. - KapaLauncher.astro renders a hidden block so EC's hashed assets ship on every page, not just pages with fenced code blocks. - Dropped the now-redundant React copy state/helpers and the Kapa-specific .copy CSS overrides. Co-Authored-By: Warp Agent --- src/components/KapaChatLauncher.css | 16 ++---- src/components/KapaChatLauncher.tsx | 76 ++++++----------------------- src/components/KapaLauncher.astro | 17 +++++++ 3 files changed, 37 insertions(+), 72 deletions(-) diff --git a/src/components/KapaChatLauncher.css b/src/components/KapaChatLauncher.css index e6fda41e2..eafcf2caa 100644 --- a/src/components/KapaChatLauncher.css +++ b/src/components/KapaChatLauncher.css @@ -206,17 +206,11 @@ max-width: 100%; } -.sl-kapa-codeblock .copy { - position: absolute; - top: 0.5rem; - right: 0.5rem; - z-index: 1; -} -.sl-kapa-codeblock .copy button svg { - display: block; - width: 0.95rem; - height: 0.95rem; -} +/* Copy button: no Kapa-specific styling on purpose. The chat renders EC's + exact `.copy` markup, so Expressive Code's own stylesheet (ec.*.css, + preloaded globally via the hidden block in KapaLauncher.astro) + plus the site-wide overrides in warp-components.css §2 (frosted glass, + 0.5rem inset for untitled frames) style it identically to docs blocks. */ .sl-kapa-codeblock pre { margin: 0; diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx index dc2a79ad2..d019675f0 100644 --- a/src/components/KapaChatLauncher.tsx +++ b/src/components/KapaChatLauncher.tsx @@ -6,8 +6,6 @@ import { PUBLIC_KAPA_INTEGRATION_ID, PUBLIC_KAPA_PROJECT_ID } from 'astro:env/cl import { isMac, keymatch } from 'keymatch'; import ReactMarkdown from 'react-markdown'; import { - LuCheck, - LuCopy, LuExternalLink, LuLoaderCircle, LuMessageSquare, @@ -92,27 +90,6 @@ function getChatErrorMessage(error: unknown) { } return message; } -async function copyTextToClipboard(text: string) { - if (navigator.clipboard?.writeText) { - await navigator.clipboard.writeText(text); - return; - } - const textarea = document.createElement('textarea'); - textarea.value = text; - textarea.setAttribute('readonly', ''); - textarea.style.position = 'fixed'; - textarea.style.opacity = '0'; - document.body.appendChild(textarea); - textarea.select(); - try { - if (!document.execCommand('copy')) { - throw new Error('Clipboard copy command failed'); - } - } finally { - textarea.remove(); - } -} - const CHAT_LANGUAGE_ALIASES: Record = { shell: 'bash', @@ -248,16 +225,10 @@ async function requestHighlightedPre({ function ChatCodeBlock({ className, codeText, - copyKey, - copiedCodeKey, - onCopy, deferHighlight, }: { className?: string; codeText: string; - copyKey: string; - copiedCodeKey: string | null; - onCopy: () => void; deferHighlight?: boolean; }) { const language = className?.replace('language-', '') ?? 'text'; @@ -344,26 +315,27 @@ function ChatCodeBlock({
)} + {/* Exact Expressive Code copy-button markup (see + @expressive-code/plugin-frames): an empty inner
paints + the frosted background and the icon is drawn by EC's CSS via + `button::after` mask, so the button renders pixel-identical + to docs code blocks. EC's runtime module (`ec.*.js`, loaded + globally via the hidden block in KapaLauncher.astro) + watches the DOM with a MutationObserver and attaches its own + click handler to every `.expressive-code .copy button` — + including these dynamically rendered ones. That handler reads + `data-code` (newlines encoded as \u007f), copies it with + `navigator.clipboard` plus an `execCommand` fallback, and + shows the same "Copied!" feedback tooltip as the docs. */}
-
{copiedCodeKey === copyKey ? 'Copied!' : ''}
+
@@ -388,7 +360,6 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio const [handoffErrorMessage, setHandoffErrorMessage] = useState(null); const [handoffSuccessMessage, setHandoffSuccessMessage] = useState(null); const [isSubmittingHandoff, setIsSubmittingHandoff] = useState(false); - const [copiedCodeKey, setCopiedCodeKey] = useState(null); const messagesRef = useRef(null); const dialogRef = useRef(null); const triggerRef = useRef(null); @@ -555,17 +526,6 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio return `https://app.kapa.ai/${projectId}/conversations/${currentThreadId}`; }; - const copyCodeBlock = async (code: string, copyKey: string) => { - try { - await copyTextToClipboard(code); - setCopiedCodeKey(copyKey); - window.setTimeout(() => { - setCopiedCodeKey((currentKey) => (currentKey === copyKey ? null : currentKey)); - }, 1400); - } catch { - setCopiedCodeKey(null); - } - }; const openHandoffForm = (qaId: string) => { setHandoffQaId(qaId); setHandoffErrorMessage(null); @@ -769,19 +729,13 @@ function ChatSurface({ title, welcomeMessage, autoOpen = false, onNewConversatio ? codeElement.props.className : undefined; const codeText = markdownChildrenToText(codeElement.props.children); - const language = codeClassName?.replace('language-', '') ?? 'text'; - const qaKey = qa.id ?? qa.question ?? 'qa'; const isStreamingAnswer = isBusy && conversation[conversation.length - 1]?.id === qa.id; - const copyKey = `${qaKey}:${language}:${codeText.slice(0, 64)}`; return ( void copyCodeBlock(codeText, copyKey)} /> ); }, diff --git a/src/components/KapaLauncher.astro b/src/components/KapaLauncher.astro index 028bc96f5..5a1818374 100644 --- a/src/components/KapaLauncher.astro +++ b/src/components/KapaLauncher.astro @@ -2,7 +2,24 @@ // The button sits to the right of the sidebar search pill (see // CustomSidebar.astro), rendering as `[icon] Ask` at one type-scale step // smaller than search so it reads as the secondary affordance. +import { Code } from 'astro-expressive-code/components'; import KapaChatLauncher from './KapaChatLauncher'; --- + +{/* + Hidden Expressive Code block that guarantees EC's hashed assets + (`/_astro/ec.*.css` + `/_astro/ec.*.js`) are emitted on EVERY page, not + just pages whose markdown contains a fenced code block. The Kapa chat + (KapaChatLauncher.tsx) renders answer code blocks with EC's exact + `.expressive-code .copy button` markup and relies on: + - ec.*.css to style the frame + copy button identically to docs blocks + - ec.*.js to attach the copy-to-clipboard handler (it observes the DOM + with a MutationObserver, so it picks up chat blocks as they stream in) + Duplicate tags on pages that already have code blocks are harmless: the + stylesheet href is identical and module scripts execute once per URL. +*/} + From 23a660eb133215da2a61774008329612ebfa4a0a Mon Sep 17 00:00:00 2001 From: Danny Neira <16809145+dannyneira@users.noreply.github.com> Date: Wed, 12 Aug 2026 11:44:46 -0600 Subject: [PATCH 14/15] Rebuild Kapa chat codeblock copy as a single control Stop reusing Expressive Code .copy markup, which stacked EC's CSS mask icon with residual SVG. Own one frosted-glass button with a CSS-mask icon and clipboard handler. Co-Authored-By: Warp Agent --- src/components/KapaChatLauncher.css | 98 +++++++++++++++++++++++++-- src/components/KapaChatLauncher.tsx | 101 +++++++++++++++++++++++----- src/components/KapaLauncher.astro | 13 +--- 3 files changed, 179 insertions(+), 33 deletions(-) diff --git a/src/components/KapaChatLauncher.css b/src/components/KapaChatLauncher.css index eafcf2caa..d810c5b08 100644 --- a/src/components/KapaChatLauncher.css +++ b/src/components/KapaChatLauncher.css @@ -206,11 +206,99 @@ max-width: 100%; } -/* Copy button: no Kapa-specific styling on purpose. The chat renders EC's - exact `.copy` markup, so Expressive Code's own stylesheet (ec.*.css, - preloaded globally via the hidden block in KapaLauncher.astro) - plus the site-wide overrides in warp-components.css §2 (frosted glass, - 0.5rem inset for untitled frames) style it identically to docs blocks. */ +/* Chat-only copy control. Deliberately avoids EC's `.copy` class so EC CSS + (`button::after` mask) and EC JS never attach a second icon/handler. Visual + tokens match docs frosted-glass copy buttons in warp-components.css §2. */ +.sl-kapa-codeblock__copy-wrap { + position: absolute; + inset-block-start: 0.5rem; + inset-inline-end: 0.5rem; + z-index: 2; + display: flex; + align-items: center; + gap: 0.25rem; + pointer-events: none; +} + +.sl-kapa-codeblock__copy { + pointer-events: auto; + position: relative; + box-sizing: border-box; + width: 2rem; + height: 2rem; + margin: 0; + padding: 0; + border-radius: var(--sl-radius-sm); + border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.08); + backdrop-filter: blur(8px); + cursor: pointer; + opacity: 0.4; + transition: + opacity 0.15s ease, + background-color 0.15s ease, + border-color 0.15s ease; +} + +.sl-kapa-codeblock:hover .sl-kapa-codeblock__copy, +.sl-kapa-codeblock:focus-within .sl-kapa-codeblock__copy { + opacity: 0.75; +} + +.sl-kapa-codeblock__copy:hover, +.sl-kapa-codeblock__copy:focus-visible { + opacity: 1; + background: rgba(255, 255, 255, 0.16); + border-color: rgba(255, 255, 255, 0.18); +} + +.sl-kapa-codeblock__copy:focus-visible { + outline: 2px solid var(--sl-color-accent-high); + outline-offset: 2px; +} + +.sl-kapa-codeblock__copy-icon { + position: absolute; + inset: 0.475rem; + background-color: var(--sl-color-white, #f9f8f6); + -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75'%3E%3Cpath d='M3 19a2 2 0 0 1-1-2V2a2 2 0 0 1 1-1h13a2 2 0 0 1 2 1'/%3E%3Crect x='6' y='5' width='16' height='18' rx='1.5' ry='1.5'/%3E%3C/svg%3E"); + mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75'%3E%3Cpath d='M3 19a2 2 0 0 1-1-2V2a2 2 0 0 1 1-1h13a2 2 0 0 1 2 1'/%3E%3Crect x='6' y='5' width='16' height='18' rx='1.5' ry='1.5'/%3E%3C/svg%3E"); + -webkit-mask-repeat: no-repeat; + mask-repeat: no-repeat; + -webkit-mask-position: center; + mask-position: center; + -webkit-mask-size: contain; + mask-size: contain; +} + +.sl-kapa-codeblock__copy-feedback { + pointer-events: none; + user-select: none; + font-size: var(--sl-text-2xs); + line-height: 1.2; + padding: 0.2rem 0.4rem; + border-radius: var(--sl-radius-sm); + background: color-mix(in srgb, var(--sl-color-accent) 85%, black); + color: var(--sl-color-white); + white-space: nowrap; +} + +:root[data-theme='light'] .sl-kapa-codeblock__copy { + background: rgba(0, 0, 0, 0.04); + border: 1px solid rgba(0, 0, 0, 0.08); + opacity: 0.6; +} + +:root[data-theme='light'] .sl-kapa-codeblock__copy:hover, +:root[data-theme='light'] .sl-kapa-codeblock__copy:focus-visible { + background: rgba(0, 0, 0, 0.08); + border-color: rgba(0, 0, 0, 0.12); + opacity: 1; +} + +:root[data-theme='light'] .sl-kapa-codeblock__copy-icon { + background-color: var(--sl-color-white, #0a0d12); +} .sl-kapa-codeblock pre { margin: 0; diff --git a/src/components/KapaChatLauncher.tsx b/src/components/KapaChatLauncher.tsx index d019675f0..dcc0b2e55 100644 --- a/src/components/KapaChatLauncher.tsx +++ b/src/components/KapaChatLauncher.tsx @@ -116,6 +116,50 @@ function escapeHtml(value: string): string { return value.replace(/&/g, '&').replace(//g, '>'); } +async function copyTextToClipboard(text: string): Promise { + try { + if (navigator.clipboard?.writeText) { + await navigator.clipboard.writeText(text); + return true; + } + } catch { + // Fall through to execCommand fallback. + } + try { + const pre = document.createElement('pre'); + Object.assign(pre.style, { + opacity: '0', + pointerEvents: 'none', + position: 'absolute', + overflow: 'hidden', + left: '0', + top: '0', + width: '20px', + height: '20px', + webkitUserSelect: 'auto', + userSelect: 'all', + }); + pre.setAttribute('aria-hidden', 'true'); + pre.textContent = text; + document.body.appendChild(pre); + const range = document.createRange(); + range.selectNode(pre); + const selection = window.getSelection(); + if (!selection) { + document.body.removeChild(pre); + return false; + } + selection.removeAllRanges(); + selection.addRange(range); + const ok = document.execCommand('copy'); + selection.removeAllRanges(); + document.body.removeChild(pre); + return ok; + } catch { + return false; + } +} + type MarkdownCodeProps = { className?: string; children?: ReactNode }; // react-markdown v9+ no longer passes an `inline` flag to the `code` @@ -239,6 +283,8 @@ function ChatCodeBlock({ const isTerminalLanguage = ['bash', 'sh', 'shell', 'zsh', 'powershell'].includes(normalizedLanguage); const [highlighted, setHighlighted] = useState<{ key: string; preHtml: string } | null>(null); const [isDarkTheme, setIsDarkTheme] = useState(true); + const [isCopied, setIsCopied] = useState(false); + const copiedResetRef = useRef(null); useEffect(() => { const root = document.documentElement; @@ -261,6 +307,14 @@ function ChatCodeBlock({ return () => observer.disconnect(); }, []); + useEffect(() => { + return () => { + if (copiedResetRef.current !== null) { + window.clearTimeout(copiedResetRef.current); + } + }; + }, []); + const theme = isDarkTheme ? 'dark' : 'light'; const highlightKey = `${theme}:${normalizedLanguage}:${codeText}`; @@ -298,6 +352,19 @@ function ChatCodeBlock({ // highlighted content from flashing while new text is streaming in. const highlightedPreHtml = highlighted?.key === highlightKey ? highlighted.preHtml : null; + const onCopy = async () => { + const ok = await copyTextToClipboard(codeText); + if (!ok) return; + setIsCopied(true); + if (copiedResetRef.current !== null) { + window.clearTimeout(copiedResetRef.current); + } + copiedResetRef.current = window.setTimeout(() => { + setIsCopied(false); + copiedResetRef.current = null; + }, 1500); + }; + return (
@@ -315,27 +382,25 @@ function ChatCodeBlock({
)} - {/* Exact Expressive Code copy-button markup (see - @expressive-code/plugin-frames): an empty inner
paints - the frosted background and the icon is drawn by EC's CSS via - `button::after` mask, so the button renders pixel-identical - to docs code blocks. EC's runtime module (`ec.*.js`, loaded - globally via the hidden block in KapaLauncher.astro) - watches the DOM with a MutationObserver and attaches its own - click handler to every `.expressive-code .copy button` — - including these dynamically rendered ones. That handler reads - `data-code` (newlines encoded as \u007f), copies it with - `navigator.clipboard` plus an `execCommand` fallback, and - shows the same "Copied!" feedback tooltip as the docs. */} -
-
+ {/* Dedicated chat copy control — intentionally NOT EC's `.copy` + class. Reusing EC markup stacked EC's CSS mask icon on top of + any residual SVG and produced a double clipboard. One button, + one icon (CSS mask), one click handler. */} +
+ + {isCopied ? 'Copied!' : ''} + + {isCopied ? Copied! : null}
diff --git a/src/components/KapaLauncher.astro b/src/components/KapaLauncher.astro index 5a1818374..a978012c4 100644 --- a/src/components/KapaLauncher.astro +++ b/src/components/KapaLauncher.astro @@ -9,16 +9,9 @@ import KapaChatLauncher from './KapaChatLauncher'; {/* - Hidden Expressive Code block that guarantees EC's hashed assets - (`/_astro/ec.*.css` + `/_astro/ec.*.js`) are emitted on EVERY page, not - just pages whose markdown contains a fenced code block. The Kapa chat - (KapaChatLauncher.tsx) renders answer code blocks with EC's exact - `.expressive-code .copy button` markup and relies on: - - ec.*.css to style the frame + copy button identically to docs blocks - - ec.*.js to attach the copy-to-clipboard handler (it observes the DOM - with a MutationObserver, so it picks up chat blocks as they stream in) - Duplicate tags on pages that already have code blocks are harmless: the - stylesheet href is identical and module scripts execute once per URL. + Hidden Expressive Code block so EC frame CSS variables/assets exist on + every page. Chat copy buttons are owned by KapaChatLauncher (not EC's + `.copy` markup) to avoid double icons. */}