From 43761942a604913d03f617543f5ada65ae911fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 14:55:16 +0200 Subject: [PATCH 01/51] feat(extension): add browser extension app --- apps/extension/.gitignore | 28 + apps/extension/.oxfmtrc.json | 4 + apps/extension/.oxlintrc.json | 56 + apps/extension/entrypoints/background.ts | 3 + apps/extension/entrypoints/content/index.tsx | 135 + apps/extension/entrypoints/content/style.css | 1 + apps/extension/entrypoints/popup/app.tsx | 90 + apps/extension/entrypoints/popup/index.html | 13 + apps/extension/entrypoints/popup/main.tsx | 16 + apps/extension/entrypoints/popup/style.css | 12 + apps/extension/package.json | 42 + apps/extension/public/icon/128.png | Bin 0 -> 3074 bytes apps/extension/public/icon/16.png | Bin 0 -> 559 bytes apps/extension/public/icon/32.png | Bin 0 -> 916 bytes apps/extension/public/icon/48.png | Bin 0 -> 1334 bytes apps/extension/public/icon/96.png | Bin 0 -> 2366 bytes apps/extension/src/shared/messages.test.ts | 42 + apps/extension/src/shared/messages.ts | 53 + apps/extension/src/shared/storage.test.ts | 33 + apps/extension/src/shared/storage.ts | 24 + apps/extension/src/types/css.d.ts | 1 + apps/extension/tsconfig.json | 20 + apps/extension/vitest.config.ts | 12 + apps/extension/wxt.config.ts | 26 + pnpm-lock.yaml | 2568 +++++++++++++++++- pnpm-workspace.yaml | 1 + 26 files changed, 3091 insertions(+), 89 deletions(-) create mode 100644 apps/extension/.gitignore create mode 100644 apps/extension/.oxfmtrc.json create mode 100644 apps/extension/.oxlintrc.json create mode 100644 apps/extension/entrypoints/background.ts create mode 100644 apps/extension/entrypoints/content/index.tsx create mode 100644 apps/extension/entrypoints/content/style.css create mode 100644 apps/extension/entrypoints/popup/app.tsx create mode 100644 apps/extension/entrypoints/popup/index.html create mode 100644 apps/extension/entrypoints/popup/main.tsx create mode 100644 apps/extension/entrypoints/popup/style.css create mode 100644 apps/extension/package.json create mode 100644 apps/extension/public/icon/128.png create mode 100644 apps/extension/public/icon/16.png create mode 100644 apps/extension/public/icon/32.png create mode 100644 apps/extension/public/icon/48.png create mode 100644 apps/extension/public/icon/96.png create mode 100644 apps/extension/src/shared/messages.test.ts create mode 100644 apps/extension/src/shared/messages.ts create mode 100644 apps/extension/src/shared/storage.test.ts create mode 100644 apps/extension/src/shared/storage.ts create mode 100644 apps/extension/src/types/css.d.ts create mode 100644 apps/extension/tsconfig.json create mode 100644 apps/extension/vitest.config.ts create mode 100644 apps/extension/wxt.config.ts diff --git a/apps/extension/.gitignore b/apps/extension/.gitignore new file mode 100644 index 0000000000..d264d1531b --- /dev/null +++ b/apps/extension/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +.output +coverage +stats.html +stats-*.json +.wxt +web-ext.config.ts +web-ext-artifacts + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/apps/extension/.oxfmtrc.json b/apps/extension/.oxfmtrc.json new file mode 100644 index 0000000000..8efe730f26 --- /dev/null +++ b/apps/extension/.oxfmtrc.json @@ -0,0 +1,4 @@ +{ + "$schema": "../../node_modules/oxfmt/configuration_schema.json", + "ignorePatterns": [".wxt/**", ".output/**", "node_modules/**"] +} diff --git a/apps/extension/.oxlintrc.json b/apps/extension/.oxlintrc.json new file mode 100644 index 0000000000..74fbcfcd90 --- /dev/null +++ b/apps/extension/.oxlintrc.json @@ -0,0 +1,56 @@ +{ + "$schema": "../../node_modules/oxlint/configuration_schema.json", + "plugins": [ + "typescript", + "unicorn", + "oxc", + "import", + "react", + "react-perf", + "jsx-a11y", + "promise", + "vitest" + ], + "categories": { + "correctness": "error", + "suspicious": "error", + "pedantic": "error", + "perf": "error", + "style": "error" + }, + "rules": { + "eslint/func-style": "off", + "eslint/max-lines-per-function": "off", + "eslint/max-statements": "off", + "eslint/no-duplicate-imports": "off", + "eslint/no-magic-numbers": "off", + "eslint/no-ternary": "off", + "eslint/no-void": "off", + "eslint/sort-imports": "off", + "import/exports-last": "off", + "import/group-exports": "off", + "import/no-default-export": "off", + "import/no-named-export": "off", + "import/no-unassigned-import": "off", + "import/prefer-default-export": "off", + "react/jsx-filename-extension": "off", + "react/jsx-max-depth": "off", + "react/jsx-no-literals": "off", + "react/only-export-components": "off", + "react/react-in-jsx-scope": "off", + "react-perf/jsx-no-new-function-as-prop": "off", + "typescript/prefer-readonly-parameter-types": "off", + "typescript/strict-void-return": "off", + "unicorn/no-null": "off", + "vitest/no-importing-vitest-globals": "off", + "vitest/prefer-to-be-falsy": "off", + "vitest/prefer-to-be-truthy": "off", + "vitest/require-hook": "off", + "vitest/require-test-timeout": "off" + }, + "env": { + "browser": true, + "builtin": true, + "node": true + } +} diff --git a/apps/extension/entrypoints/background.ts b/apps/extension/entrypoints/background.ts new file mode 100644 index 0000000000..a67f570adf --- /dev/null +++ b/apps/extension/entrypoints/background.ts @@ -0,0 +1,3 @@ +export default defineBackground(() => { + browser.runtime.onInstalled.addListener(() => {}); +}); diff --git a/apps/extension/entrypoints/content/index.tsx b/apps/extension/entrypoints/content/index.tsx new file mode 100644 index 0000000000..70593911fb --- /dev/null +++ b/apps/extension/entrypoints/content/index.tsx @@ -0,0 +1,135 @@ +import './style.css'; +import { browser, createShadowRootUi, defineContentScript, storage } from '#imports'; +import React, { useEffect, useState } from 'react'; +import { createRoot } from 'react-dom/client'; +import type { Root } from 'react-dom/client'; +import { + createSidebarStateMessage, + isGetSidebarStateMessage, + isToggleSidebarMessage, +} from '@/src/shared/messages'; +import { + DEFAULT_SIDEBAR_PREFERENCES, + SIDEBAR_PREFERENCES_STORAGE_KEY, + normalizeSidebarPreferences, +} from '@/src/shared/storage'; + +type SidebarSubscriber = (isOpen: boolean) => void; +type RuntimeMessageListener = Parameters[0]; +type SendResponse = Parameters[2]; + +const subscribers = new Set(); +let isSidebarOpen = DEFAULT_SIDEBAR_PREFERENCES.isOpen; + +const notifySubscribers = (): void => { + for (const subscriber of subscribers) { + subscriber(isSidebarOpen); + } +}; + +const setSidebarOpen = async (nextIsOpen: boolean): Promise => { + isSidebarOpen = nextIsOpen; + notifySubscribers(); + await storage.setItem(SIDEBAR_PREFERENCES_STORAGE_KEY, { isOpen: nextIsOpen }); +}; + +const toggleSidebar = async (): Promise => { + await setSidebarOpen(!isSidebarOpen); + return isSidebarOpen; +}; + +const subscribeToSidebarState = (subscriber: SidebarSubscriber): (() => void) => { + subscribers.add(subscriber); + subscriber(isSidebarOpen); + + return (): void => { + subscribers.delete(subscriber); + }; +}; + +const KiloSidebar = (): React.JSX.Element | null => { + const [isOpen, setIsOpen] = useState(isSidebarOpen); + + useEffect(() => subscribeToSidebarState(setIsOpen), []); + + if (!isOpen) { + return null; + } + + return ( + + ); +}; + +const handleSidebarMessage = (message: unknown, sendResponse: SendResponse): boolean => { + if (isToggleSidebarMessage(message)) { + void (async (): Promise => { + const nextIsOpen = await toggleSidebar(); + sendResponse(createSidebarStateMessage(nextIsOpen)); + })(); + return true; + } + + if (isGetSidebarStateMessage(message)) { + sendResponse(createSidebarStateMessage(isSidebarOpen)); + } + + return false; +}; + +export default defineContentScript({ + cssInjectionMode: 'ui', + async main(ctx): Promise { + const storedPreferences = normalizeSidebarPreferences( + await storage.getItem(SIDEBAR_PREFERENCES_STORAGE_KEY) + ); + isSidebarOpen = storedPreferences.isOpen; + + browser.runtime.onMessage.addListener((message, _sender, sendResponse) => + handleSidebarMessage(message, sendResponse) + ); + + const ui = await createShadowRootUi(ctx, { + anchor: 'body', + isolateEvents: true, + name: 'kilo-sidebar', + onMount: container => { + const root = createRoot(container); + root.render( + + + + ); + return root; + }, + onRemove: root => { + root?.unmount(); + }, + position: 'overlay', + zIndex: 2_147_483_647, + }); + + ui.mount(); + }, + matches: [''], +}); diff --git a/apps/extension/entrypoints/content/style.css b/apps/extension/entrypoints/content/style.css new file mode 100644 index 0000000000..d4b5078586 --- /dev/null +++ b/apps/extension/entrypoints/content/style.css @@ -0,0 +1 @@ +@import 'tailwindcss'; diff --git a/apps/extension/entrypoints/popup/app.tsx b/apps/extension/entrypoints/popup/app.tsx new file mode 100644 index 0000000000..11bd06ef62 --- /dev/null +++ b/apps/extension/entrypoints/popup/app.tsx @@ -0,0 +1,90 @@ +import { browser } from '#imports'; +import React, { useEffect, useState } from 'react'; +import { + createGetSidebarStateMessage, + createToggleSidebarMessage, + isSidebarStateMessage, +} from '@/src/shared/messages'; +import type { GetSidebarStateMessage, ToggleSidebarMessage } from '@/src/shared/messages'; + +type PopupRequestMessage = GetSidebarStateMessage | ToggleSidebarMessage; + +const unavailableStatus = 'Sidebar is unavailable on this page.'; + +const getSidebarStatus = (isOpen: boolean): string => { + if (isOpen) { + return 'Sidebar visible'; + } + + return 'Sidebar hidden'; +}; + +const getToggleLabel = (isOpen: boolean | undefined): string => { + if (isOpen === true) { + return 'Hide sidebar'; + } + + return 'Show sidebar'; +}; + +export const App = (): React.JSX.Element => { + const [isSidebarOpen, setIsSidebarOpen] = useState(); + const [status, setStatus] = useState('Ready'); + + const sendSidebarMessage = async (message: PopupRequestMessage): Promise => { + try { + setStatus('Connecting to this tab...'); + const [activeTab] = await browser.tabs.query({ + active: true, + currentWindow: true, + }); + + if (typeof activeTab?.id !== 'number') { + throw new TypeError('No active tab is available.'); + } + + const response: unknown = await browser.tabs.sendMessage(activeTab.id, message); + + if (!isSidebarStateMessage(response)) { + throw new TypeError('The tab returned an unexpected sidebar response.'); + } + + setIsSidebarOpen(response.isOpen); + setStatus(getSidebarStatus(response.isOpen)); + } catch (error) { + setIsSidebarOpen(undefined); + setStatus(error instanceof Error ? error.message : unavailableStatus); + } + }; + + useEffect(() => { + void sendSidebarMessage(createGetSidebarStateMessage()); + }, []); + + return ( +
+
+

Kilo

+

Hello world

+

+ Toggle the floating sidebar on the current page. +

+
+ +
+

Sidebar

+

{status}

+
+ + +
+ ); +}; diff --git a/apps/extension/entrypoints/popup/index.html b/apps/extension/entrypoints/popup/index.html new file mode 100644 index 0000000000..ed4cb94947 --- /dev/null +++ b/apps/extension/entrypoints/popup/index.html @@ -0,0 +1,13 @@ + + + + + + Default Popup Title + + + +
+ + + diff --git a/apps/extension/entrypoints/popup/main.tsx b/apps/extension/entrypoints/popup/main.tsx new file mode 100644 index 0000000000..80212b7de5 --- /dev/null +++ b/apps/extension/entrypoints/popup/main.tsx @@ -0,0 +1,16 @@ +import './style.css'; +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import { App } from './app'; + +const root = document.querySelector('#root'); + +if (!(root instanceof HTMLElement)) { + throw new Error('Popup root element was not found.'); +} + +createRoot(root).render( + + + +); diff --git a/apps/extension/entrypoints/popup/style.css b/apps/extension/entrypoints/popup/style.css new file mode 100644 index 0000000000..29ec5dc737 --- /dev/null +++ b/apps/extension/entrypoints/popup/style.css @@ -0,0 +1,12 @@ +@import 'tailwindcss'; + +html, +body, +#root { + min-width: 20rem; +} + +body { + margin: 0; + overflow: hidden; +} diff --git a/apps/extension/package.json b/apps/extension/package.json new file mode 100644 index 0000000000..1f76a4507b --- /dev/null +++ b/apps/extension/package.json @@ -0,0 +1,42 @@ +{ + "name": "kilo-extension", + "description": "Kilo browser extension.", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "wxt", + "dev:firefox": "wxt -b firefox --mv3", + "build": "wxt build", + "build:firefox": "wxt build -b firefox --mv3", + "zip": "wxt zip", + "zip:firefox": "wxt zip -b firefox --mv3", + "typecheck": "tsc --noEmit", + "compile": "pnpm run typecheck", + "lint": "pnpm -w exec oxlint --type-aware --type-check --import-plugin --react-plugin --react-perf-plugin --jsx-a11y-plugin --promise-plugin --vitest-plugin --deny-warnings --config apps/extension/.oxlintrc.json apps/extension", + "format": "pnpm -w exec oxfmt apps/extension", + "format:check": "pnpm -w exec oxfmt --list-different apps/extension", + "test": "vitest --run", + "test:watch": "vitest", + "validate:firefox": "npx --loglevel error -y -p node@22 node ./node_modules/web-ext/bin/web-ext.js lint --source-dir .output/firefox-mv3 --no-input", + "verify": "pnpm run typecheck && pnpm run lint && pnpm run format:check && pnpm run test", + "postinstall": "wxt prepare" + }, + "dependencies": { + "react": "19.2.6", + "react-dom": "19.2.6" + }, + "devDependencies": { + "@tailwindcss/vite": "4.3.1", + "@types/node": "catalog:", + "@types/react": "19.2.14", + "@types/react-dom": "19.2.3", + "@vitest/coverage-v8": "catalog:", + "@wxt-dev/module-react": "1.2.2", + "tailwindcss": "4.3.1", + "typescript": "catalog:", + "vitest": "catalog:", + "web-ext": "10.4.0", + "wxt": "0.20.26" + } +} diff --git a/apps/extension/public/icon/128.png b/apps/extension/public/icon/128.png new file mode 100644 index 0000000000000000000000000000000000000000..9e35d130796978714468fa149241172744bf3992 GIT binary patch literal 3074 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 Q9RL6T07*qoM6N<$g0^9zvj6}9 literal 0 HcmV?d00001 diff --git a/apps/extension/public/icon/16.png b/apps/extension/public/icon/16.png new file mode 100644 index 0000000000000000000000000000000000000000..cd09f8cfbc020b5a077c6c491e2be5f1cb75fb50 GIT binary patch literal 559 zcmV+~0?_@5P)J*;soIYk(IETZ~(bMj$o8vnQ?Z`K&P@byKnRdgL9BcAPx)vHta#e(k_EN+QtB~a;#B7vY4-MPwd z0I*M%0Ii$vMXQ0J*IDiEx*HeHO#2~|QUWDPMwmjovlOSF45Is5Q{nqwq^gh#fRPv6 zS}@*-M+8d*2rWit4ITS_^ytbtKuJ{`srD|`y4ycdB$KV&w?aSmH!}7OlPlMt4AEQp zhZ%K%Z3q@VTdrAraF5Y9z3|}q+%#iwp}*e_69qRYzn6K?6mgj zj?N1`|7Fpj-nU)JS}?UmCFPhx`KK{AMERWeC5F}p!vOUOl x{o{41KG|W@*}t!GLho_Yiov7vl{n4;-T?Ii%lIRLgKym_bV-2v#fCmVkAh`iih%Om#5EqsU zEB$;ulbPxHNiqxxepRVTcfam_)BWD}zDCH1!#lJ1=QkYzLKTQg1TaFtD>Sfey|Nw1 z3Cv>jc4%%Q$sQXQ)5Zy*b+&%lh8&pdK=X%LqOt7p-_p#5NNihWyASt-m}fv^KK5X9 zbks(t8*DKHMv44r@nJitenlQlcBQ64mJYAwD3KR8Dmyf5Q6f}^(*cw^x1qBd8s%9kw)PqOF+ zc-#S zwQjUnP-RT=n$z;oa{$o^ej$o%)Kw)I9tuf6Q`Tn+#^dIVS&7sFkK3u|69@r)NF$HD zn5?fe?w80Fs5B&yA2ly4ut2Ew4a9w|>vbXq1Q}Wd!xyk%#42Pl;Q%w^j@J4G3&z1W zvl_P0Dd_YlpU67vy~AJ_#T7gd5&C5&WPNcQtPjvH(26c7^r`6R;v+X!sKdcrNe*yU zu%IoZ&tmCi;5IA?s^k;m?l}i#BnCL@`+N#*F3DTVC`^hA)cVg?aqWB(jFA(tHZEp< zwF)31XomugC@(-5{jAQilHIq;7k$02kY(b8Kv-7EiXJ9J%oAhjFm3N<5ujX#EH9TW9YBdNqdt0000<{22)0j@ZAli#Ip&84}hAsEPnZ0vICT zIil>g)=nMB5eRp{-n;rUl5nIZozTq{LL5B**?A2)AhQ9D%laV^98KF_fMq|gbh*W_VK z1jmlNdOFzMnWnR6z&J3c=k!HD!pQmK(ypfUD~#Df9-3~ld-VB_oA?C8H;_0Hc_u)( zkPLQNszn=p+I^HX5MyYO{Sc@2!+9Vp?Ft~F`P!l-lx{XHv`YA9z_Otk!1`zN$>8z6qBU3z6!!)@Cylpu z&2$r4dr z!Ph&1n@}}yZ|UZmlwLZ3yn({y_xC54U@7EOHs zmS9Ox%wtj5-FXeFu?9FB4(G0#0YAVJ!7g(VX(}eN5NByC!#oOv_#o0Wj5RxTHdK#0}VOB}LiJ$VTSLE0$n_c4LN3lA@FuMfFbX^Typ_M);{*DcI)i6`WkWsC0j9uXW3O zVuOZ!LPg1b(kgf{rMV>i4+)t4j0{Pu7zjk3{An}TrkIRbNlQWFk|JO4^rG#EB2j-C z$|~4rDvhoAGr1@OO2Pi^N;kHK|71{qA96S36HTf1nb0gBaFKb-q<8q)Wk`U5Mv3!J zsKJ!Llmig|{?`gPQPn>@48Ai~??4K2FD)WqrXqmSJFT^`-buopHnKdR2ti1B(Eeq* sU%9M=0p6t5!3M|Pz3;IZ)jLV}0)HJVZ}+VOtN;K207*qoM6N<$f?ddKj{pDw literal 0 HcmV?d00001 diff --git a/apps/extension/public/icon/96.png b/apps/extension/public/icon/96.png new file mode 100644 index 0000000000000000000000000000000000000000..c28ad52d56fc409195f52f57c447442326d94b6b GIT binary patch literal 2366 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 literal 0 HcmV?d00001 diff --git a/apps/extension/src/shared/messages.test.ts b/apps/extension/src/shared/messages.test.ts new file mode 100644 index 0000000000..748627927b --- /dev/null +++ b/apps/extension/src/shared/messages.test.ts @@ -0,0 +1,42 @@ +import { describe, expect, it } from 'vitest'; +import { + createGetSidebarStateMessage, + createSidebarStateMessage, + createToggleSidebarMessage, + isGetSidebarStateMessage, + isSidebarStateMessage, + isToggleSidebarMessage, +} from './messages'; + +describe('sidebar messages', () => { + it('creates a toggle message with the stable extension protocol type', () => { + expect.assertions(1); + expect(createToggleSidebarMessage()).toStrictEqual({ + type: 'kilo.sidebar.toggle', + }); + }); + + it('creates a state request message with the stable extension protocol type', () => { + expect.assertions(1); + expect(createGetSidebarStateMessage()).toStrictEqual({ + type: 'kilo.sidebar.getState', + }); + }); + + it('creates a sidebar state response with an explicit boolean state', () => { + expect.assertions(1); + expect(createSidebarStateMessage(true)).toStrictEqual({ + isOpen: true, + type: 'kilo.sidebar.state', + }); + }); + + it('accepts only the known sidebar message shapes', () => { + expect.assertions(5); + expect(isToggleSidebarMessage({ type: 'kilo.sidebar.toggle' })).toBe(true); + expect(isGetSidebarStateMessage({ type: 'kilo.sidebar.getState' })).toBe(true); + expect(isSidebarStateMessage({ isOpen: false, type: 'kilo.sidebar.state' })).toBe(true); + expect(isSidebarStateMessage({ type: 'kilo.sidebar.state' })).toBe(false); + expect(isToggleSidebarMessage({ type: 'kilo.sidebar.unknown' })).toBe(false); + }); +}); diff --git a/apps/extension/src/shared/messages.ts b/apps/extension/src/shared/messages.ts new file mode 100644 index 0000000000..5ddee29a4e --- /dev/null +++ b/apps/extension/src/shared/messages.ts @@ -0,0 +1,53 @@ +const GET_SIDEBAR_STATE_MESSAGE_TYPE = 'kilo.sidebar.getState'; +const SIDEBAR_STATE_MESSAGE_TYPE = 'kilo.sidebar.state'; +const TOGGLE_SIDEBAR_MESSAGE_TYPE = 'kilo.sidebar.toggle'; + +interface ToggleSidebarMessage { + readonly type: typeof TOGGLE_SIDEBAR_MESSAGE_TYPE; +} + +interface GetSidebarStateMessage { + readonly type: typeof GET_SIDEBAR_STATE_MESSAGE_TYPE; +} + +interface SidebarStateMessage { + readonly isOpen: boolean; + readonly type: typeof SIDEBAR_STATE_MESSAGE_TYPE; +} + +export type SidebarRequestMessage = GetSidebarStateMessage | ToggleSidebarMessage; + +export const createToggleSidebarMessage = (): ToggleSidebarMessage => ({ + type: TOGGLE_SIDEBAR_MESSAGE_TYPE, +}); + +export const createGetSidebarStateMessage = (): GetSidebarStateMessage => ({ + type: GET_SIDEBAR_STATE_MESSAGE_TYPE, +}); + +export const createSidebarStateMessage = (isOpen: boolean): SidebarStateMessage => ({ + isOpen, + type: SIDEBAR_STATE_MESSAGE_TYPE, +}); + +export const isToggleSidebarMessage = (value: unknown): value is ToggleSidebarMessage => + isObjectWithType(value, TOGGLE_SIDEBAR_MESSAGE_TYPE); + +export const isGetSidebarStateMessage = (value: unknown): value is GetSidebarStateMessage => + isObjectWithType(value, GET_SIDEBAR_STATE_MESSAGE_TYPE); + +export const isSidebarStateMessage = (value: unknown): value is SidebarStateMessage => + isRecord(value) && + value['type'] === SIDEBAR_STATE_MESSAGE_TYPE && + typeof value['isOpen'] === 'boolean'; + +const isRecord = (value: unknown): value is Record => + typeof value === 'object' && value !== null; + +const isObjectWithType = ( + value: unknown, + type: TType +): value is { readonly type: TType } => isRecord(value) && value['type'] === type; + +export type { GetSidebarStateMessage, SidebarStateMessage, ToggleSidebarMessage }; +export { GET_SIDEBAR_STATE_MESSAGE_TYPE, SIDEBAR_STATE_MESSAGE_TYPE, TOGGLE_SIDEBAR_MESSAGE_TYPE }; diff --git a/apps/extension/src/shared/storage.test.ts b/apps/extension/src/shared/storage.test.ts new file mode 100644 index 0000000000..f911845a7a --- /dev/null +++ b/apps/extension/src/shared/storage.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from 'vitest'; +import { + DEFAULT_SIDEBAR_PREFERENCES, + SIDEBAR_PREFERENCES_STORAGE_KEY, + normalizeSidebarPreferences, +} from './storage'; + +describe('sidebar storage', () => { + it('uses a local WXT storage key for sidebar preferences', () => { + expect.assertions(1); + expect(SIDEBAR_PREFERENCES_STORAGE_KEY).toBe('local:sidebarPreferences'); + }); + + it('keeps the sidebar closed by default', () => { + expect.assertions(1); + expect(DEFAULT_SIDEBAR_PREFERENCES).toStrictEqual({ isOpen: false }); + }); + + it('normalizes valid persisted sidebar preferences', () => { + expect.assertions(1); + expect(normalizeSidebarPreferences({ isOpen: true })).toStrictEqual({ + isOpen: true, + }); + }); + + it('falls back to defaults for invalid persisted values', () => { + expect.assertions(2); + expect(normalizeSidebarPreferences()).toStrictEqual(DEFAULT_SIDEBAR_PREFERENCES); + expect(normalizeSidebarPreferences({ isOpen: 'yes' })).toStrictEqual( + DEFAULT_SIDEBAR_PREFERENCES + ); + }); +}); diff --git a/apps/extension/src/shared/storage.ts b/apps/extension/src/shared/storage.ts new file mode 100644 index 0000000000..12a3bfc09a --- /dev/null +++ b/apps/extension/src/shared/storage.ts @@ -0,0 +1,24 @@ +export const SIDEBAR_PREFERENCES_STORAGE_KEY = 'local:sidebarPreferences'; + +export interface SidebarPreferences { + readonly isOpen: boolean; +} + +export const DEFAULT_SIDEBAR_PREFERENCES: SidebarPreferences = { + isOpen: false, +}; + +export const normalizeSidebarPreferences = (value?: unknown): SidebarPreferences => { + if ( + typeof value === 'object' && + value !== null && + 'isOpen' in value && + typeof value.isOpen === 'boolean' + ) { + return { + isOpen: value.isOpen, + }; + } + + return DEFAULT_SIDEBAR_PREFERENCES; +}; diff --git a/apps/extension/src/types/css.d.ts b/apps/extension/src/types/css.d.ts new file mode 100644 index 0000000000..35306c6fc9 --- /dev/null +++ b/apps/extension/src/types/css.d.ts @@ -0,0 +1 @@ +declare module '*.css'; diff --git a/apps/extension/tsconfig.json b/apps/extension/tsconfig.json new file mode 100644 index 0000000000..e786c0c509 --- /dev/null +++ b/apps/extension/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "./.wxt/tsconfig.json", + "compilerOptions": { + "allowImportingTsExtensions": true, + "exactOptionalPropertyTypes": true, + "forceConsistentCasingInFileNames": true, + "jsx": "react-jsx", + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "strict": true, + "useUnknownInCatchVariables": true + }, + "include": ["**/*.ts", "**/*.tsx", ".wxt/types/**/*.d.ts"], + "exclude": ["node_modules", ".output"] +} diff --git a/apps/extension/vitest.config.ts b/apps/extension/vitest.config.ts new file mode 100644 index 0000000000..f151238f4e --- /dev/null +++ b/apps/extension/vitest.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + coverage: { + provider: 'v8', + reporter: ['text', 'html'], + }, + globals: false, + include: ['src/**/*.test.ts', 'src/**/*.test.tsx'], + }, +}); diff --git a/apps/extension/wxt.config.ts b/apps/extension/wxt.config.ts new file mode 100644 index 0000000000..e27d36e19f --- /dev/null +++ b/apps/extension/wxt.config.ts @@ -0,0 +1,26 @@ +import { defineConfig } from 'wxt'; +import tailwindcss from '@tailwindcss/vite'; + +// See https://wxt.dev/api/config.html +export default defineConfig({ + manifest: { + action: { + default_title: 'Kilo', + }, + browser_specific_settings: { + gecko: { + data_collection_permissions: { + required: ['none'], + }, + id: 'kilo-extension@kilocode.ai', + }, + }, + description: 'Kilo browser extension.', + name: 'Kilo Extension', + permissions: ['activeTab'], + }, + modules: ['@wxt-dev/module-react'], + vite: () => ({ + plugins: [tailwindcss()], + }), +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 840a59e532..44794dbc5b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -163,6 +163,49 @@ importers: specifier: 'catalog:' version: 5.9.3 + apps/extension: + dependencies: + react: + specifier: 19.2.6 + version: 19.2.6 + react-dom: + specifier: 19.2.6 + version: 19.2.6(react@19.2.6) + devDependencies: + '@tailwindcss/vite': + specifier: 4.3.1 + version: 4.3.1(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) + '@types/node': + specifier: 'catalog:' + version: 24.12.4 + '@types/react': + specifier: 19.2.14 + version: 19.2.14 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitest/coverage-v8': + specifier: 'catalog:' + version: 4.1.6(vitest@4.1.6) + '@wxt-dev/module-react': + specifier: 1.2.2 + version: 1.2.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))(wxt@0.20.26(@types/node@24.12.4)(eslint@9.39.4(jiti@2.7.0))(jiti@2.7.0)(oxc-parser@0.120.0)(rollup@4.59.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) + tailwindcss: + specifier: 4.3.1 + version: 4.3.1 + typescript: + specifier: 'catalog:' + version: 5.9.3 + vitest: + specifier: 'catalog:' + version: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + web-ext: + specifier: 10.4.0 + version: 10.4.0(express@5.2.1)(jiti@2.7.0) + wxt: + specifier: 0.20.26 + version: 0.20.26(@types/node@24.12.4)(eslint@9.39.4(jiti@2.7.0))(jiti@2.7.0)(oxc-parser@0.120.0)(rollup@4.59.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + apps/mobile: dependencies: '@expo-google-fonts/jetbrains-mono': @@ -200,7 +243,7 @@ importers: version: 7.11.0(expo@55.0.24)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0) '@shopify/flash-list': specifier: 2.0.2 - version: 2.0.2(@babel/runtime@7.29.2)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0) + version: 2.0.2(@babel/runtime@7.29.7)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0) '@tailwindcss/postcss': specifier: 4.2.4 version: 4.2.4 @@ -375,7 +418,7 @@ importers: version: 7.0.0-dev.20260514.1 eslint-plugin-sonarjs: specifier: 4.0.3 - version: 4.0.3 + version: 4.0.3(eslint@9.39.4(jiti@2.7.0)) knip: specifier: 6.0.6 version: 6.0.6 @@ -442,7 +485,7 @@ importers: version: 9.1.20(patch_hash=e1857649664eed8f87877c352d277c90d4af5a58d0ad931105f033c8c08165c1)(esbuild@0.27.4)(next@16.2.6(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.58.2)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)))(type-fest@4.41.0)(typescript@5.9.3)(webpack-hot-middleware@2.26.1)(webpack@5.105.4(esbuild@0.27.4)) '@storybook/test-runner': specifier: 0.23.0 - version: 0.23.0(@types/node@25.5.2)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))) + version: 0.23.0(@types/node@25.5.2)(node-notifier@10.0.1)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))) '@tailwindcss/typography': specifier: 0.5.19 version: 0.5.19(tailwindcss@4.2.4) @@ -962,7 +1005,7 @@ importers: version: 6.8.0(@types/react@19.2.14)(bufferutil@4.1.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react@19.2.6)(utf-8-validate@6.0.6) jest: specifier: 30.3.0 - version: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)) + version: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) knip: specifier: 5.86.0 version: 5.86.0(@types/node@24.12.4)(typescript@5.9.3) @@ -977,7 +1020,7 @@ importers: version: 4.2.4 ts-jest: specifier: 29.4.9 - version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.4)(jest-util@30.3.0)(jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.4)(jest-util@30.3.0)(jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1))(typescript@5.9.3) tsconfig-paths: specifier: 4.2.0 version: 4.2.0 @@ -1382,7 +1425,7 @@ importers: version: 0.31.10 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@24.12.4) + version: 29.7.0(@types/node@24.12.4)(node-notifier@10.0.1) typescript: specifier: 'catalog:' version: 5.9.3 @@ -1857,10 +1900,10 @@ importers: version: 7.0.0-dev.20260514.1 jest: specifier: 30.3.0 - version: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)) + version: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) ts-jest: specifier: 29.4.9 - version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.4)(jest-util@30.3.0)(jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.4)(jest-util@30.3.0)(jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1))(typescript@5.9.3) typescript: specifier: 'catalog:' version: 5.9.3 @@ -1918,10 +1961,10 @@ importers: version: 7.0.0-dev.20260514.1 jest: specifier: 29.7.0 - version: 29.7.0(@types/node@24.12.4) + version: 29.7.0(@types/node@24.12.4)(node-notifier@10.0.1) ts-jest: specifier: 29.4.9 - version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@29.7.0(@types/node@24.12.4))(typescript@5.9.3) + version: 29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@29.7.0(@types/node@24.12.4)(node-notifier@10.0.1))(typescript@5.9.3) tsx: specifier: 'catalog:' version: 4.21.0 @@ -1970,7 +2013,7 @@ importers: version: 7.0.0-dev.20260514.1 jest: specifier: 30.3.0 - version: 30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4)) + version: 30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) typescript: specifier: 'catalog:' version: 5.9.3 @@ -2920,6 +2963,9 @@ importers: packages: + '@1natsu/wait-element@4.2.0': + resolution: {integrity: sha512-Om0Q+WE9mNrpY4AwMTvkFiYHv8VM7TML3PvOqXy+w6kAjLjKhGYHYX+305+a6J8RVpds9s7IF2Z5aOPYwULFNw==} + '@adobe/css-tools@4.4.4': resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} @@ -2968,6 +3014,16 @@ packages: resolution: {integrity: sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw==} engines: {node: '>=18'} + '@aklinker1/rollup-plugin-visualizer@5.12.0': + resolution: {integrity: sha512-X24LvEGw6UFmy0lpGJDmXsMyBD58XmX1bbwsaMLhNoM+UMQfQ3b2RtC+nz4b/NoRK5r6QJSKJHBNVeUdwqybaQ==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + rollup: 2.x || 3.x || 4.x + peerDependenciesMeta: + rollup: + optional: true + '@alcalzone/ansi-tokenize@0.2.5': resolution: {integrity: sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw==} engines: {node: '>=18'} @@ -3870,10 +3926,18 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 + '@babel/runtime@7.28.2': + resolution: {integrity: sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==} + engines: {node: '>=6.9.0'} + '@babel/runtime@7.29.2': resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} @@ -4154,6 +4218,19 @@ packages: resolution: {integrity: sha512-Y6+WUMsTFWE5jb20IFP4YGa5IrGY/+a/FbOSjDF/wz9gepU2hwCYSXRHP/vPwBvwcY3SVMASt4yXxbXNXigmZQ==} engines: {node: '>=18'} + '@devicefarmer/adbkit-logcat@2.1.3': + resolution: {integrity: sha512-yeaGFjNBc/6+svbDeul1tNHtNChw6h8pSHAt5D+JsedUrMTN7tla7B15WLDyekxsuS2XlZHRxpuC6m92wiwCNw==} + engines: {node: '>= 4'} + + '@devicefarmer/adbkit-monkey@1.2.1': + resolution: {integrity: sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg==} + engines: {node: '>= 0.10.4'} + + '@devicefarmer/adbkit@3.3.8': + resolution: {integrity: sha512-7rBLLzWQnBwutH2WZ0EWUkQdihqrnLYCUMaB44hSol9e0/cdIhuNFcqZO0xNheAU6qqHVA8sMiLofkYTgb+lmw==} + engines: {node: '>= 0.10.4'} + hasBin: true + '@discordjs/builders@1.13.1': resolution: {integrity: sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==} engines: {node: '>=16.11.0'} @@ -4394,10 +4471,44 @@ packages: cpu: [x64] os: [win32] + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@expo-google-fonts/jetbrains-mono@0.4.1': resolution: {integrity: sha512-CslACrtMOcRwoWXCO7OMEI+9w3fukWSoBtvNz46OqPoogEuuoY0tkDY1O8sFumk8t0pC6Cx0Xr95O0TOQhpkug==} @@ -4603,6 +4714,14 @@ packages: '@floating-ui/utils@0.2.11': resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + '@fluent/syntax@0.19.0': + resolution: {integrity: sha512-5D2qVpZrgpjtqU4eNOcWGp1gnUCgjfM+vKGE2y03kKN6z5EBhtx0qdRFbg8QuNNj8wXNoX93KJoYb+NqoxswmQ==} + engines: {node: '>=14.0.0', npm: '>=7.0.0'} + + '@fregante/relaxed-json@2.0.0': + resolution: {integrity: sha512-PyUXQWB42s4jBli435TDiYuVsadwRHnMc27YaLouINktvTWsL3FcKrRMGawTayFk46X+n5bE23RjUTWQwrukWw==} + engines: {node: '>= 0.10.0'} + '@google/genai@2.7.0': resolution: {integrity: sha512-tv0DRtcndt2oEhBYy+5mA0TaXH98+L1Gt0AP9unBfH7DP20KhB7+O3QqAN1Lz+laMARGTHS7BFQSNpLbl4gm1g==} engines: {node: '>=20.0.0'} @@ -4655,6 +4774,26 @@ packages: '@trpc/server': ^10.10.0 || >11.0.0-rc hono: 4.12.18 + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + '@img/colour@1.1.0': resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} @@ -5216,6 +5355,9 @@ packages: '@marijn/find-cluster-break@1.0.2': resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==} + '@mdn/browser-compat-data@8.0.2': + resolution: {integrity: sha512-bT8u6Ll/vuV8qC9tn8cqvxoAtBpKcCwhKMW51qJRK9+G3JUtAx3lc1wjij4GJzGCfqA0keRbJUFetCgwwYaskA==} + '@mdx-js/loader@3.1.1': resolution: {integrity: sha512-0TTacJyZ9mDmY+VefuthVshaNIyCGZHJG2fMnGaDttCt8HmjUF7SizlHJpaCDoGnN635nK1wpzfpx/Xx5S4WnQ==} peerDependencies: @@ -6354,6 +6496,9 @@ packages: '@paper-design/shaders@0.0.76': resolution: {integrity: sha512-AcNDY4J66YQHUfQYFInkCP7M9VOje0od7wLpOR7LtCmc532opJy6ll+h1W9zBovz8tt9U7OADUmJ/qKEXyOX/A==} + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} + '@pkgr/core@0.2.9': resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -6389,6 +6534,18 @@ packages: webpack-plugin-serve: optional: true + '@pnpm/config.env-replace@1.1.0': + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + + '@pnpm/network.ca-file@1.0.2': + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + + '@pnpm/npm-conf@3.0.3': + resolution: {integrity: sha512-//0sR/cow/s4ICQaYoAobOl4aU8cjU6x/V24V7XkKotb9+O+3zySIYp146vpaobYHnxa4pZX8NkV54Z5AwbDKA==} + engines: {node: '>=12'} + '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} @@ -7278,6 +7435,9 @@ packages: '@rolldown/pluginutils@1.0.0-rc.17': resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/plugin-commonjs@28.0.1': resolution: {integrity: sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA==} engines: {node: '>=16.0.0 || 14 >= 14.17'} @@ -8469,36 +8629,69 @@ packages: '@tailwindcss/node@4.2.4': resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} + '@tailwindcss/node@4.3.1': + resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==} + '@tailwindcss/oxide-android-arm64@4.2.4': resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} engines: {node: '>= 20'} cpu: [arm64] os: [android] + '@tailwindcss/oxide-android-arm64@4.3.1': + resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + '@tailwindcss/oxide-darwin-arm64@4.2.4': resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] + '@tailwindcss/oxide-darwin-arm64@4.3.1': + resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + '@tailwindcss/oxide-darwin-x64@4.2.4': resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] + '@tailwindcss/oxide-darwin-x64@4.3.1': + resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + '@tailwindcss/oxide-freebsd-x64@4.2.4': resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] + '@tailwindcss/oxide-freebsd-x64@4.3.1': + resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} engines: {node: '>= 20'} cpu: [arm] os: [linux] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} engines: {node: '>= 20'} @@ -8506,6 +8699,13 @@ packages: os: [linux] libc: [glibc] + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} engines: {node: '>= 20'} @@ -8513,6 +8713,13 @@ packages: os: [linux] libc: [musl] + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + libc: [musl] + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==} engines: {node: '>= 20'} @@ -8520,6 +8727,13 @@ packages: os: [linux] libc: [glibc] + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [glibc] + '@tailwindcss/oxide-linux-x64-musl@4.2.4': resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==} engines: {node: '>= 20'} @@ -8527,6 +8741,13 @@ packages: os: [linux] libc: [musl] + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + libc: [musl] + '@tailwindcss/oxide-wasm32-wasi@4.2.4': resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==} engines: {node: '>=14.0.0'} @@ -8539,22 +8760,50 @@ packages: - '@emnapi/wasi-threads' - tslib + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==} engines: {node: '>= 20'} cpu: [x64] os: [win32] + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + '@tailwindcss/oxide@4.2.4': resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==} engines: {node: '>= 20'} + '@tailwindcss/oxide@4.3.1': + resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==} + engines: {node: '>= 20'} + '@tailwindcss/postcss@4.2.4': resolution: {integrity: sha512-wgAVj6nUWAolAu8YFvzT2cTBIElWHkjZwFYovF+xsqKsW2ADxM/X2opxj5NsF/qVccAOjRNe8X2IdPzMsWyHTg==} @@ -8563,6 +8812,11 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + '@tailwindcss/vite@4.3.1': + resolution: {integrity: sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ==} + peerDependencies: + vite: '>=8.0.5 <8.0.11' + '@tanstack/query-core@5.100.10': resolution: {integrity: sha512-8UR0yJR+GiQ40m3lPhUr0xbfAupe6GSQiksSBSa9SM2NjezFyxXCIA69/lz8cSoNKZLrw1/PktIyQBJcVeMi3w==} @@ -8705,12 +8959,21 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/filesystem@0.0.36': + resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==} + + '@types/filewriter@0.0.33': + resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==} + '@types/graceful-fs@4.1.9': resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} '@types/hammerjs@2.0.46': resolution: {integrity: sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==} + '@types/har-format@1.2.16': + resolution: {integrity: sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -8761,6 +9024,9 @@ packages: '@types/mdx@2.0.13': resolution: {integrity: sha512-+OWZQfAYyio6YkJb3HLxDrvnx6SWWDbC0zVPfBRzUk0/nqoDyf6dNxQi3eArPe8rJ473nobTMQ/8Zk+LxJ+Yuw==} + '@types/minimatch@3.0.5': + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} @@ -8841,6 +9107,9 @@ packages: '@types/wait-on@5.3.4': resolution: {integrity: sha512-EBsPjFMrFlMbbUFf9D1Fp+PAB2TwmUn7a3YtHyD9RLuTIk1jDd8SxXVAoez2Ciy+8Jsceo2MYEYZzJ/DvorOKw==} + '@types/webextension-polyfill@0.12.5': + resolution: {integrity: sha512-uKSAv6LgcVdINmxXMKBuVIcg/2m5JZugoZO8x20g7j2bXJkPIl/lVGQcDlbV+aXAiTyXT2RA5U5mI4IGCDMQeg==} + '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} @@ -9105,6 +9374,19 @@ packages: '@opentelemetry/sdk-metrics': '>=2.0.0 <3.0.0' '@opentelemetry/sdk-trace-base': '>=2.0.0 <3.0.0' + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: '>=8.0.5 <8.0.11' + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + '@vitest/coverage-v8@4.1.6': resolution: {integrity: sha512-36l628fQ/9a/8ihy97eOtEnvWQEdqULQOJtcaxtoNq0G1w3Mxd4szSahOaMM9/NGyZ+hyKcMtIW/WIxq0XQViQ==} peerDependencies: @@ -9235,6 +9517,15 @@ packages: '@webassemblyjs/wast-printer@1.14.1': resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + '@webext-core/fake-browser@1.5.2': + resolution: {integrity: sha512-nkDQwOJ23X5Q7cEtN6LRuBtVFf1KVOFi5GoQAro0lzqdh59F5E+K350j1isbnqYbzsXRh1NJtboudIcHfZtvOQ==} + + '@webext-core/isolated-element@1.1.5': + resolution: {integrity: sha512-4m6oP8Vzm/68YO1QmkUOZqqUcmyBtA53tji2g00/nYXE3E3IceYgeub7eIqvXDV2Z7xU6cm6qO1IMt4XFVwtvQ==} + + '@webext-core/match-patterns@1.0.3': + resolution: {integrity: sha512-NY39ACqCxdKBmHgw361M9pfJma8e4AZo20w9AY+5ZjIj1W2dvXC8J31G5fjfOGbulW9w4WKpT8fPooi0mLkn9A==} + '@workflow/serde@4.1.0-beta.2': resolution: {integrity: sha512-8kkeoQKLDaKXefjV5dbhBj2aErfKp1Mc4pb6tj8144cF+Em5SPbyMbyLCHp+BVrFfFVCBluCtMx+jjvaFVZGww==} @@ -9242,6 +9533,18 @@ packages: resolution: {integrity: sha512-NgQKHpwh8AbT4KvAsW91Y+4f4jja2IvFPQ5atcy5NUxUMVRgXzRFEee3erawfXrTmiCVqJjd9PljHySKBXmHKQ==} engines: {node: '>=20.15.0'} + '@wxt-dev/browser@0.1.43': + resolution: {integrity: sha512-RMB0zgfe7uuiTp18s9taLeKXoOCLBV418797dnEggiMWmM1JDJekiLtlvrNc6QeZg+amDBy2/KKYuQB2kh/K9A==} + + '@wxt-dev/module-react@1.2.2': + resolution: {integrity: sha512-+lRLi1r9dAXpLySWSIWHLJ1h/nFzR20iQnx3RNrKyA6oJg4+ClOluVXozHjfPg9Okfy/umtffiOopGayASrg6w==} + peerDependencies: + vite: '>=8.0.5 <8.0.11' + wxt: '>=0.19.16' + + '@wxt-dev/storage@1.2.8': + resolution: {integrity: sha512-GWCFKgF5+d7eslOxUDFC70ypA9njupmJb1nQM8uZoX0J3sWT2BO5xJLzb1sYahWAfID9p2BMtnUBN1lkWxPsbQ==} + '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} @@ -9308,10 +9611,33 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + addons-linter@10.7.0: + resolution: {integrity: sha512-WdfEuL2CUqE4BLzQ3kqVa0rTmnnuRZ8CM9xAP37vpdVqMS2eX0GlBXmC33I6ilkVWTcsW42xEGcLUYirLI4O1A==} + engines: {node: '>=20.0.0'} + hasBin: true + + addons-moz-compare@1.3.0: + resolution: {integrity: sha512-/rXpQeaY0nOKhNx00pmZXdk5Mu+KhVlL3/pSBuAYwrxRrNiTvI/9xfQI8Lmm7DMMl+PDhtfAHY/0ibTpdeoQQQ==} + + addons-scanner-utils@15.2.0: + resolution: {integrity: sha512-SkjE3jE7Sfx67KuL8nI5DolqqQ35G1GMcMrgT9LufKnBJUW4YnoBO1sLAILj3N/FLhfSAT0hwWK1MSVLmgbASQ==} + peerDependencies: + express: 5.2.1 + safe-compare: 1.1.4 + peerDependenciesMeta: + express: + optional: true + safe-compare: + optional: true + adjust-sourcemap-loader@4.0.0: resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} engines: {node: '>=8.9'} + adm-zip@0.5.17: + resolution: {integrity: sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==} + engines: {node: '>=12.0'} + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} @@ -9361,6 +9687,9 @@ packages: anser@2.3.5: resolution: {integrity: sha512-vcZjxvvVoxTeR5XBNJB38oTu/7eDCZlwdz32N1eNgpyPF7j/Z7Idf+CUwQOkKKpJ7RJyjxgLHCM7vdIK0iCNMQ==} + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -9453,9 +9782,17 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} + array-differ@4.0.0: + resolution: {integrity: sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + array-timsort@1.0.3: resolution: {integrity: sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==} + array-union@3.0.1: + resolution: {integrity: sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==} + engines: {node: '>=12'} + asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} @@ -9487,12 +9824,22 @@ packages: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true + async-mutex@0.5.0: + resolution: {integrity: sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==} + async@3.2.6: resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + atomically@2.1.1: + resolution: {integrity: sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==} + auto-bind@5.0.1: resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -9710,6 +10057,9 @@ packages: blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + bn.js@4.12.3: resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} @@ -9729,6 +10079,10 @@ packages: bowser@2.14.1: resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + boxen@8.0.1: + resolution: {integrity: sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==} + engines: {node: '>=18'} + bplist-creator@0.1.0: resolution: {integrity: sha512-sXaHZicyEEmY86WyueLTQesbeoH/mquvarJaQNbjuOQO+7gbFcDEWqKmcWA4cOTLzFlfgvkiVxolk1k5bBIpmg==} @@ -9786,6 +10140,9 @@ packages: bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + buffer-crc32@1.0.0: resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==} engines: {node: '>=8.0.0'} @@ -9819,10 +10176,30 @@ packages: bun-types@1.3.14: resolution: {integrity: sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} + c12@3.3.4: + resolution: {integrity: sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==} + peerDependencies: + magicast: '*' + peerDependenciesMeta: + magicast: + optional: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + cac@7.0.0: + resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==} + engines: {node: '>=20.19.0'} + caching-transform@4.0.0: resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} engines: {node: '>=8'} @@ -9854,6 +10231,10 @@ packages: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + caniuse-lite@1.0.30001779: resolution: {integrity: sha512-U5og2PN7V4DMgF50YPNtnZJGWVLFjjsN3zb6uMT5VGYIewieDj1upwfuVNXf4Kor+89c3iCRJnSzMD5LmTvsfA==} @@ -9914,6 +10295,13 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} + chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} @@ -9943,6 +10331,11 @@ packages: engines: {node: '>=12.13.0'} hasBin: true + chrome-launcher@1.2.0: + resolution: {integrity: sha512-JbuGuBNss258bvGil7FT4HKdC3SC2K7UAEUqiPy3ACS3Yxo3hAW6bvFpCu2HsIJLgTqxgEX6BkujvzZfLpUD0Q==} + engines: {node: '>=12.13.0'} + hasBin: true + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} @@ -9965,6 +10358,9 @@ packages: resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} engines: {node: '>= 0.10'} + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} + cjs-module-lexer@1.2.3: resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} @@ -10015,6 +10411,10 @@ packages: resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + cli-spinners@2.9.2: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} @@ -10102,6 +10502,10 @@ packages: colorjs.io@0.6.0-alpha.1: resolution: {integrity: sha512-c/h/8uAmPydQcriRdX8UTAFHj6SpSHFHBA8LvMikvYWAVApPTwg/pyOXNsGmaCBd6L/EeDlRHSNhTtnIFp/qsg==} + columnify@1.6.0: + resolution: {integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==} + engines: {node: '>=8.0.0'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -10120,6 +10524,10 @@ packages: commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@2.9.0: + resolution: {integrity: sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==} + engines: {node: '>= 0.6.x'} + commander@3.0.2: resolution: {integrity: sha512-Gar0ASD4BDyKC4hl4DwHqDrmvjoxWKZigVnAbn5H1owvm4CxCPdb0HQDehwNYMJpla5+M2tPmPARzhtYuwpHow==} @@ -10131,6 +10539,10 @@ packages: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + comment-json@4.6.2: resolution: {integrity: sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==} engines: {node: '>= 6'} @@ -10138,6 +10550,10 @@ packages: common-path-prefix@3.0.0: resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -10156,10 +10572,31 @@ packages: compute-scroll-into-view@2.0.4: resolution: {integrity: sha512-y/ZA3BGnxoM/QHHQ2Uy49CLtnWPbt4tTPpEEZiEmmiWBFKjej7nEyH8Ryz54jH0MLXflUYA3Er2zUxPSJu5R+g==} + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.4: + resolution: {integrity: sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==} + + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + + configstore@7.1.0: + resolution: {integrity: sha512-N4oog6YJWbR9kGyXvS7jEykLDXIE2C0ILYqNBZBp9iwiJpoCBWYsuAdW6PPFn6w06jjnC+3JstVvWHO4cZqvRg==} + engines: {node: '>=18'} + connect@3.7.0: resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} engines: {node: '>= 0.10.0'} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + console-browserify@1.2.0: resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} @@ -10394,6 +10831,15 @@ packages: supports-color: optional: true + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -10407,6 +10853,10 @@ packages: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} engines: {node: '>=0.10.0'} + decamelize@6.0.1: + resolution: {integrity: sha512-G7Cqgaelq68XHJNGlZ7lrNQyhZGsFqpwtGFexqUv4IQdjKoSYF7ipZ9UuTJZUSQXFj/XaoBLuEVIVqr8EJngEQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + decimal.js-light@2.5.1: resolution: {integrity: sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==} @@ -10440,10 +10890,21 @@ packages: resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} engines: {node: '>=4.0.0'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + default-require-extensions@3.0.1: resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} engines: {node: '>=8'} @@ -10459,10 +10920,17 @@ packages: resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} engines: {node: '>=8'} + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -10488,6 +10956,9 @@ packages: des.js@1.1.0: resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -10641,6 +11112,10 @@ packages: dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dot-prop@9.0.0: + resolution: {integrity: sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==} + engines: {node: '>=18'} + dotenv-expand@12.0.3: resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==} engines: {node: '>=12'} @@ -10816,6 +11291,9 @@ packages: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + end-of-stream@1.4.5: resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} @@ -10830,6 +11308,10 @@ packages: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + entities@1.1.2: resolution: {integrity: sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==} @@ -10840,6 +11322,10 @@ packages: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + entities@7.0.1: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} @@ -10926,6 +11412,10 @@ packages: escape-carriage@1.3.1: resolution: {integrity: sha512-GwBr6yViW3ttx1kb7/Oh+gKQ1/TrhYwxKqVmg5gS+BK+Qe2KrOa/Vh7w3HPBvgGf0LfcDGoY9I6NHKoA5Hozhw==} + escape-goat@4.0.0: + resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} + engines: {node: '>=12'} + escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} @@ -10950,6 +11440,11 @@ packages: engines: {node: '>=6.0'} hasBin: true + eslint-plugin-no-unsanitized@4.1.5: + resolution: {integrity: sha512-MSB4hXPVFQrI8weqzs6gzl7reP2k/qSjtCoL2vUMSDejIIq9YL1ZKvq5/ORBXab/PvfBBrWO2jWviYpL+4Ghfg==} + peerDependencies: + eslint: ^9 || ^10 + eslint-plugin-sonarjs@4.0.3: resolution: {integrity: sha512-5drkJKLC9qQddIiaATV0e8+ygbUc7b0Ti6VB7M2d3jmKNh3X0RaiIJYTs3dr9xnlhlrxo+/s1FoO3Jgv6O/c7g==} peerDependencies: @@ -10959,19 +11454,53 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-visitor-keys@5.0.1: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + esniff@2.0.1: resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} engines: {node: '>=0.10'} + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} @@ -11393,6 +11922,9 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + ext@1.7.0: resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} @@ -11419,9 +11951,19 @@ packages: fast-json-parse@1.0.3: resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==} + fast-json-patch@3.1.1: + resolution: {integrity: sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==} + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} @@ -11486,6 +12028,10 @@ packages: fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + file-type@22.0.1: resolution: {integrity: sha512-ww5Mhre0EE+jmBvOXTmXAbEMuZE7uX4a3+oRCQFNj8w++g3ev913N6tXQz0XTXbueQ5TWQfm6BdaViEHHn8bhA==} engines: {node: '>=22'} @@ -11494,6 +12040,10 @@ packages: resolution: {integrity: sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==} engines: {node: '>= 10.4.0'} + filesize@11.0.17: + resolution: {integrity: sha512-oHLTvMLw6imZUl1se/RBQrFlyy50nXce4sU7yGR6Qc0JgCwqnfiFsAnEwotdGmfKLD7SArGUk2/5STU0k8LOBQ==} + engines: {node: '>= 10.8.0'} + filing-cabinet@5.2.0: resolution: {integrity: sha512-eNrCJGdYQY0tV+ACNesQ7vb2aMxD76NM7THayMn0Z5XBt1Tonr4vbVN+FbhHfekKGQG9O5UaciDDR7+dw8P9ZA==} engines: {node: '>=18'} @@ -11558,10 +12108,23 @@ packages: resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} engines: {node: '>=18'} + firefox-profile@4.7.0: + resolution: {integrity: sha512-aGApEu5bfCNbA4PGUZiRJAIU6jKmghV2UVdklXAofnNtiDjqYw0czLS46W7IfFqVKgKhFB8Ao2YoNGHY4BoIMQ==} + engines: {node: '>=18'} + hasBin: true + + first-chunk-stream@3.0.0: + resolution: {integrity: sha512-LNRvR4hr/S8cXXkIY5pTgVP7L3tq6LlYWcg9nWBuW7o1NMxKZo6oOVa/6GIekMGI0Iw7uC+HWimMe9u/VAeKqw==} + engines: {node: '>=8'} + flat-cache@3.2.0: resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + flatted@3.4.1: resolution: {integrity: sha512-IxfVbRFVlV8V/yRaGzk0UVIcsKKHMSfYw66T/u4nTwlWteQePsxe//LjudR1AMX4tZW3WFCh3Zqa/sjlqpbURQ==} @@ -11598,6 +12161,10 @@ packages: typescript: '>3.6.0' webpack: ^5.11.0 + form-data-encoder@4.1.0: + resolution: {integrity: sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==} + engines: {node: '>= 18'} + form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} @@ -11611,6 +12178,10 @@ packages: engines: {node: '>=18.3.0'} hasBin: true + formdata-node@6.0.3: + resolution: {integrity: sha512-8e1++BCiTzUno9v5IZ2J6bv4RU+3UKDmqWUQD0MIMVCd9AdhWkO1gw57oo1mNEX1dMq2EGI+FbWz4B92pscSQg==} + engines: {node: '>= 18'} + formdata-polyfill@4.0.10: resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} engines: {node: '>=12.20.0'} @@ -11655,6 +12226,10 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs-extra@11.3.5: + resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} + engines: {node: '>=14.14'} + fs-monkey@1.1.0: resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} @@ -11677,6 +12252,14 @@ packages: fuzzysort@3.1.0: resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} + fx-runner@1.4.0: + resolution: {integrity: sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg==} + hasBin: true + + fx-runner@1.5.0: + resolution: {integrity: sha512-EstfdRQu04tM+SXR3pBmc0+GYKZj9FMHAvA8XAbKPzTvUeHP0v1/F3aQ10bG7EluR6phvFqsvn5Z7SvYJsEgNw==} + hasBin: true + gaxios@7.1.4: resolution: {integrity: sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==} engines: {node: '>=18'} @@ -11724,6 +12307,9 @@ packages: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} + get-port-please@3.2.0: + resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} @@ -11739,6 +12325,10 @@ packages: resolution: {integrity: sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==} engines: {node: '>=6'} + giget@3.3.0: + resolution: {integrity: sha512-gzi2D96p+AMfDcmJHGDj3KJ9NRiwvlFAU5yfa3ROwWZmFUjX4P43x3BcyRaOMMLto1vUo7C+86+MFhYTl6Ryiw==} + hasBin: true + github-slugger@2.0.0: resolution: {integrity: sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==} @@ -11746,6 +12336,10 @@ packages: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} @@ -11765,6 +12359,10 @@ packages: resolution: {integrity: sha512-gOPiyxcD9dJGCEArAhF4Hd0BAqvAe/JzERP7tYumE4yIkmIedPUVXcJFWbV3/p/ovIIvKjkrTk+f1UVkq7vvbw==} engines: {node: '>=0.10.0'} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + globals@17.4.0: resolution: {integrity: sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==} engines: {node: '>=18'} @@ -11786,13 +12384,22 @@ packages: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} + graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graceful-readlink@1.0.1: + resolution: {integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==} + grammy@1.43.0: resolution: {integrity: sha512-7dYm06A945mXuIk/5HUlSjeyIYChW8vCEiU2dkOKKqJJzwAWxTkCc91Eqbz7TgODh2rtFFKWI/fekowWHOkmjQ==} engines: {node: ^12.20.0 || >=14.13.1} + growly@1.3.0: + resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} + gzip-size@6.0.0: resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} engines: {node: '>=10'} @@ -11901,6 +12508,9 @@ packages: resolution: {integrity: sha512-RWzP96k/yv0PQfyXnWjs6zot20TqfpfsNXhOnev8d1InAxubW93L11/oNUc3tQqn2G0bSdAOBpX+2uDFHV7kdQ==} engines: {node: '>=16.9.0'} + hookable@6.1.1: + resolution: {integrity: sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ==} + hosted-git-info@10.1.1: resolution: {integrity: sha512-DeOnSPAvOndYKfw075gt8yZzQ7S2hNztw34zBTfhIzLhmBTswIBg5/y+pqu/VD5cYWm5goAFTusDmUEmKZ0PEQ==} engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} @@ -11975,6 +12585,10 @@ packages: engines: {node: '>=18'} hasBin: true + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + iconv-lite@0.7.2: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} @@ -12030,6 +12644,9 @@ packages: engines: {node: '>=8'} hasBin: true + import-meta-resolve@4.2.0: + resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==} + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -12042,6 +12659,10 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} + index-to-position@1.2.0: + resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} + engines: {node: '>=18'} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -12052,6 +12673,10 @@ packages: resolution: {integrity: sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ini@4.1.3: + resolution: {integrity: sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + ini@6.0.0: resolution: {integrity: sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==} engines: {node: ^20.17.0 || >=22.9.0} @@ -12095,6 +12720,10 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-absolute@0.1.7: + resolution: {integrity: sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA==} + engines: {node: '>=0.10.0'} + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} @@ -12131,6 +12760,11 @@ packages: engines: {node: '>=8'} hasBin: true + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + is-electron@2.2.2: resolution: {integrity: sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==} @@ -12165,11 +12799,25 @@ packages: is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + is-in-ci@1.0.0: + resolution: {integrity: sha512-eUuAjybVTHMYWm/U+vBO1sY/JOCgoPCXRxzdju0K+K0BiGW0SChEL1MLC0PoCIR1OlPo5YAp8HuQoUlsWEICwg==} + engines: {node: '>=18'} + hasBin: true + is-in-ci@2.0.0: resolution: {integrity: sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w==} engines: {node: '>=20'} hasBin: true + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-installed-globally@1.0.0: resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} engines: {node: '>=18'} @@ -12182,6 +12830,10 @@ packages: resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} engines: {node: '>= 0.4'} + is-npm@6.1.0: + resolution: {integrity: sha512-O2z4/kNgyjhQwVR1Wpkbfc19JIhggF97NZNCpWTnjH7kVcZMUrnut9XSN7txI7VdyIYk5ZatOq3zvSuWpU8hoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -12198,10 +12850,21 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-primitive@3.0.1: + resolution: {integrity: sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==} + engines: {node: '>=0.10.0'} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -12216,6 +12879,10 @@ packages: resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} engines: {node: '>=0.10.0'} + is-relative@0.1.3: + resolution: {integrity: sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA==} + engines: {node: '>=0.10.0'} + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -12238,6 +12905,9 @@ packages: is-url@1.2.4: resolution: {integrity: sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==} + is-utf8@0.2.1: + resolution: {integrity: sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==} + is-windows@0.2.0: resolution: {integrity: sha512-n67eJYmXbniZB7RF4I/FTjK1s6RPOCTxhYrVYLRaCt3lF0mpWZPKr3T2LSZAqyjQsxR2qMmGYXXzK0YWwcPM1Q==} engines: {node: '>=0.10.0'} @@ -12250,15 +12920,30 @@ packages: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isexe@1.1.2: + resolution: {integrity: sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} @@ -12603,6 +13288,9 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + jose@5.9.6: + resolution: {integrity: sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==} + jose@6.2.3: resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} @@ -12642,6 +13330,9 @@ packages: js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + js-yaml@3.14.2: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true @@ -12664,9 +13355,16 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-merge-patch@1.0.2: + resolution: {integrity: sha512-M6Vp2GN9L7cfuMXiWOmHj9bEFbeC250iVtcKQbqVgEsDVYnIsrNsbU+h/Y/PkbBQCtEa4Bez+Ebv0zfbC8ObLg==} + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-parse-even-better-errors@3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + json-schema-to-ts@3.1.1: resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} engines: {node: '>=16'} @@ -12683,6 +13381,9 @@ packages: json-schema@0.4.0: resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-with-bigint@3.5.7: resolution: {integrity: sha512-7ei3MdAI5+fJPVnKlW77TKNKwQ5ppSzWvhPuSuINT/GYW9ZOC1eRKOuhV9yHG5aEsUPj9BBx5JIekkmoLHxZOw==} @@ -12744,6 +13445,10 @@ packages: kubernetes-types@1.30.0: resolution: {integrity: sha512-Dew1okvhM/SQcIa2rcgujNndZwU8VnSapDgdxlYoB84ZlpAD43U6KLAFqYo17ykSFGHNPrg0qry0bP+GJd9v7Q==} + ky@1.14.3: + resolution: {integrity: sha512-9zy9lkjac+TR1c2tG+mkNSVlyOpInnWdSMiue4F+kq8TwJSgv6o8jhLRg8Ho6SnZ9wOYUq/yozts9qQCfk7bIw==} + engines: {node: '>=18'} + kysely@0.29.2: resolution: {integrity: sha512-s6WVJyEZrbm6jhBpiKHsGHyePMrVQKJ85wZCFCr9W4QHv6WTjWIrdvTmO9hDEA3bNK0xkrE2DqrHsXMLWuZpQg==} engines: {node: '>=22.0.0'} @@ -12752,6 +13457,10 @@ packages: resolution: {integrity: sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==} hasBin: true + latest-version@9.0.0: + resolution: {integrity: sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==} + engines: {node: '>=18'} + lazystream@1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} @@ -12760,6 +13469,10 @@ packages: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + lexical@0.35.0: resolution: {integrity: sha512-3VuV8xXhh5xJA6tzvfDvE0YBCMkIZUmxtRilJQDDdCgJCc+eut6qAv2qbN+pbqvarqcQqPN1UF+8YvsjmyOZpw==} @@ -12769,6 +13482,9 @@ packages: lighthouse-logger@1.4.2: resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + lighthouse-logger@2.0.2: + resolution: {integrity: sha512-vWl2+u5jgOQuZR55Z1WM0XDdrJT6mzMP8zHUct7xTlWhuQs+eV0g+QL0RQdFjT54zVmbhLCP8vIVpy1wGn/gCg==} + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} @@ -12840,6 +13556,10 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lines-and-columns@2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + linkedom@0.18.12: resolution: {integrity: sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==} engines: {node: '>=16'} @@ -12852,6 +13572,10 @@ packages: linkify-it@5.0.0: resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + listr2@10.2.1: + resolution: {integrity: sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==} + engines: {node: '>=22.13.0'} + loader-runner@4.3.1: resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} engines: {node: '>=6.11.5'} @@ -12864,6 +13588,10 @@ packages: resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} engines: {node: '>= 12.13.0'} + local-pkg@1.2.1: + resolution: {integrity: sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==} + engines: {node: '>=14'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -12929,6 +13657,10 @@ packages: resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} engines: {node: '>=10'} + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + loglevel@1.9.2: resolution: {integrity: sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg==} engines: {node: '>= 0.6.0'} @@ -13016,6 +13748,10 @@ packages: makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + many-keys-map@3.0.3: + resolution: {integrity: sha512-1DiZmDHPXMBgMRjeUtHy1q1VYmeJscHxhIAexX9z/zjRMP80+0ETuPfssi8z+kMY4DwUgsKuHqpjxgmeA9gBNA==} + engines: {node: '>=18'} + map-or-similar@1.5.0: resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} @@ -13345,6 +14081,10 @@ packages: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mimic-response@3.1.0: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} @@ -13398,6 +14138,9 @@ packages: engines: {node: '>=10'} hasBin: true + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + module-definition@6.0.1: resolution: {integrity: sha512-FeVc50FTfVVQnolk/WQT8MX+2WVcDnTGiq6Wo+/+lJ2ET1bRVi3HG3YlJUfqagNMc/kUlFSoR96AJkxGpKz13g==} engines: {node: '>=18'} @@ -13455,17 +14198,28 @@ packages: msgpackr@1.11.12: resolution: {integrity: sha512-RBdJ1Un7yGlXWajrkxcSa93nvQ0w4zBf60c0yYv7YtBelP8H2FA7XsfBbMHtXKXUMUxH7zV3Zuozh+kUQWhHvg==} + multimatch@6.0.0: + resolution: {integrity: sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + multipasta@0.2.7: resolution: {integrity: sha512-KPA58d68KgGil15oDqXjkUBEBYc00XvbPj5/X+dyzeo/lWm9Nc25pQRlf1D+gv4OpK7NM0J1odrbu9JNNGvynA==} multitars@1.0.0: resolution: {integrity: sha512-H/J4fMLedtudftaYMOg7ajzLYgT3/rwbWVJbqr/iUgB8DQztn38ys5HOqI1CzSxx8QhXXwOOnnBvd4v3jG5+Mg==} + nano-spawn@2.1.0: + resolution: {integrity: sha512-yTW+2okrElHiH4fsiz/+/zc0EDo9BDDoC3iKk8dpv1GeRc9nUWzUZHx6TofMWErchhUQR8hY9/Eu1Uja9x1nqA==} + engines: {node: '>=20.17'} + nanoid@3.3.11: resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + nanospinner@1.2.2: + resolution: {integrity: sha512-Zt/AmG6qRU3e+WnzGGLuMCEAO/dAu45stNbHY223tUxldaDAeE+FxSPsd9Q+j+paejmm0ZbrNVs5Sraqy3dRxA==} + napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} @@ -13557,6 +14311,9 @@ packages: resolution: {integrity: sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==} engines: {node: '>=18'} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -13601,6 +14358,9 @@ packages: node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-notifier@10.0.1: + resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==} + node-polyfill-webpack-plugin@2.0.1: resolution: {integrity: sha512-ZUMiCnZkP1LF0Th2caY6J/eKKoA0TefpoVa68m/LQU1I/mE8rGt4fNYGgNuCcK+aG8P8P43nbeJ2RqJMOL/Y1A==} engines: {node: '>=12'} @@ -13641,6 +14401,11 @@ packages: engines: {node: '>=8.9'} hasBin: true + nypm@0.6.7: + resolution: {integrity: sha512-s3ds97SD5pd1dULE+tHUk1DrV0cSHOnsfpcdGATJ8JpBo21DoKqN9exTH4/2nhPQNOLomBdTFMicN94S4DrZrQ==} + engines: {node: '>=18'} + hasBin: true + oauth@0.9.15: resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} @@ -13678,10 +14443,20 @@ packages: obug@2.1.1: resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + ofetch@1.5.1: + resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} + + ohash@2.0.11: + resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + oidc-token-hash@5.2.0: resolution: {integrity: sha512-6gj2m8cJZ+iSW8bm0FXdGF0YhIQbKrfP4yWTNzxc31U6MOjfEmB1rHvlYvxI1B7t7BCi1F2vYTT6YhtQRG4hxw==} engines: {node: ^10.13.0 || >=12.0.0} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} + on-finished@2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -13705,6 +14480,14 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + open@11.0.0: + resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} + engines: {node: '>=20'} + open@7.4.2: resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} engines: {node: '>=8'} @@ -13749,6 +14532,10 @@ packages: openid-client@5.7.1: resolution: {integrity: sha512-jDBPgSVfTnkIh71Hg9pRvtJc6wTwqjRkN88+gCFtYWrlP4Yx2Dsrow8uPi3qLr/aeymPF3o2+dS+wOpglK04ew==} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + ora@3.4.0: resolution: {integrity: sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==} engines: {node: '>=6'} @@ -13764,6 +14551,10 @@ packages: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} + os-shim@0.1.3: + resolution: {integrity: sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==} + engines: {node: '>= 0.4.0'} + outvariant@1.4.0: resolution: {integrity: sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==} @@ -13857,6 +14648,10 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-json@10.0.1: + resolution: {integrity: sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==} + engines: {node: '>=18'} + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} @@ -13878,6 +14673,14 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} + parse-json@7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + parse-ms@2.1.0: resolution: {integrity: sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA==} engines: {node: '>=6'} @@ -13890,6 +14693,15 @@ packages: resolution: {integrity: sha512-Nt/a5SfCLiTnQAjx3fHlqp8hRgTL3z7kTQZzvIMS9uCAepnCyjpdEc6M/sz69WqMBdaDBw9sF1F1UaHROYzGkQ==} engines: {node: '>=10'} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -13948,6 +14760,12 @@ packages: resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} engines: {node: '>= 0.10'} + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + perfect-debounce@2.1.0: + resolution: {integrity: sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==} + pg-cloudflare@1.3.0: resolution: {integrity: sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==} @@ -13997,6 +14815,23 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true + + pino@9.7.0: + resolution: {integrity: sha512-vnMCM6xZTb1WDmLvtG2lE/2p+t9hDEIvTWJsu6FejkE62vB7gDhvzrpFR4Cw2to+9JNQxVnkAKVPA1KPB98vWg==} + hasBin: true + pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -14013,6 +14848,12 @@ packages: resolution: {integrity: sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==} engines: {node: '>=14.16'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.1: + resolution: {integrity: sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==} + playwright-core@1.58.2: resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} engines: {node: '>=18'} @@ -14136,6 +14977,10 @@ packages: resolution: {integrity: sha512-sy020/Q4mt18eCkVo/cGEJD+wgdxeg5DTgNUaA85awBCbuEP43BOdCTOOw/K2Tvgw2oZfag3PFyhkVuQ6nJfBg==} engines: {node: '>=20'} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} + preact-render-to-string@5.2.6: resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} peerDependencies: @@ -14149,6 +14994,10 @@ packages: engines: {node: '>=18'} hasBin: true + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + pretty-error@4.0.0: resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} @@ -14182,6 +15031,9 @@ packages: resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==} engines: {node: '>=8'} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + process@0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -14197,6 +15049,10 @@ packages: resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} engines: {node: '>=10'} + promise-toolbox@0.21.0: + resolution: {integrity: sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==} + engines: {node: '>=6'} + promise@8.3.0: resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} @@ -14213,6 +15069,9 @@ packages: property-information@7.1.0: resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + protobufjs@8.0.3: resolution: {integrity: sha512-LBYnMWkKLB8fE/ljROPDbCl7mgLSlI+oBe1fAAr5MTqFg4TIi0tYrVVurJvQggOjnUYMQtEZBjrej59ojMNTHQ==} engines: {node: '>=12.0.0'} @@ -14231,6 +15090,11 @@ packages: public-encrypt@4.0.3: resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + publish-browser-extension@4.0.5: + resolution: {integrity: sha512-EePAn3VIHJS/jqCuvs1NgPgoecCT8+RsES76hbgYe2Ze1dyvB0tX60C1PCrV8Z8fv56mW3E59s9Gd/GwWiw7dw==} + engines: {node: '>=18.0.0'} + hasBin: true + pump@3.0.4: resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} @@ -14241,6 +15105,10 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pupa@3.3.0: + resolution: {integrity: sha512-LjgDO2zPtoXP2wJpDjZrGdojii1uqO0cnwKoIoUzkfS98HDmbeiGmYiXo3lXeFlq2xvne1QFQhwYXSUCLKtEuA==} + engines: {node: '>=12.20'} + pure-rand@6.1.0: resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} @@ -14259,6 +15127,9 @@ packages: resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} engines: {node: '>=0.6'} + quansync@0.2.11: + resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + query-selector-shadow-dom@1.0.1: resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} @@ -14276,6 +15147,9 @@ packages: queue@6.0.2: resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + quickjs-wasi@3.0.0: resolution: {integrity: sha512-X7ouKC4ZVf9bXQ8rsE7+L6TeBbesejAJH61x16xRaGAQGfBHHRcniWgzJZZVtHc8rS9yVsY+Tvk8/usAosg4bg==} @@ -14304,6 +15178,9 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + rc9@3.0.1: + resolution: {integrity: sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==} + rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true @@ -14328,11 +15205,6 @@ packages: resolution: {integrity: sha512-hlSJDQ2synMPKFZOsKo9Hi8WWZTC7POR8EmWvTSjow+VDgKzkmjQvFm2fk0tmRw+f0vTOIYKlarR0iL4996pdg==} engines: {node: '>=16.14.0'} - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - react-dom@19.2.6: resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} peerDependencies: @@ -14551,6 +15423,13 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + real-require@1.0.0: + resolution: {integrity: sha512-P4nbQYQfePJxRSmY+v/KINxVucm4NF3p3s7pJveMTtom52FR4YGltUQLB8idDXwDDWW+eYrWDFbuzUnjoWHF7g==} + recast@0.23.11: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} @@ -14626,6 +15505,14 @@ packages: resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} engines: {node: '>=4'} + registry-auth-token@5.1.1: + resolution: {integrity: sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==} + engines: {node: '>=14'} + + registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} @@ -14743,6 +15630,10 @@ packages: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + ret@0.2.2: resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} engines: {node: '>=4'} @@ -14759,6 +15650,9 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported @@ -14799,6 +15693,10 @@ packages: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} @@ -14825,6 +15723,10 @@ packages: safe-regex@2.1.1: resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==} + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} + safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} @@ -14873,6 +15775,9 @@ packages: resolution: {integrity: sha512-3A6sD0WYP7+QrjbfNA2FN3FsOaGGFoekCVgTyypy53gPxhbkCIjtO6YWgdrfM+n/8sI8JeXZOIxsHjMTNxQ4nQ==} engines: {node: ^14.0.0 || >=16.0.0} + scule@1.3.0: + resolution: {integrity: sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==} + seedrandom@3.0.5: resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} @@ -14895,6 +15800,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.2: + resolution: {integrity: sha512-c8jsqUZm3omBOI66G90z1Dyw5z622G8oLG+omfsHBJf3CWQTlOcwOjvOG6wtiNfW6anKm/eA39LMwMtMez2TiQ==} + engines: {node: '>=10'} + hasBin: true + send@0.19.2: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} engines: {node: '>= 0.8.0'} @@ -14925,6 +15835,10 @@ packages: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} + set-value@4.1.0: + resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} + engines: {node: '>=11.0'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} @@ -14959,6 +15873,9 @@ packages: resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} engines: {node: '>= 0.4'} + shellwords@0.1.1: + resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -15020,6 +15937,10 @@ packages: resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} engines: {node: '>=14.16'} + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} + slice-ansi@8.0.0: resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} engines: {node: '>=20'} @@ -15032,6 +15953,9 @@ packages: resolution: {integrity: sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==} engines: {node: '>= 18'} + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + sonner-native@0.23.1: resolution: {integrity: sha512-p4WRxVoTjLTeuLcvuyMNzgd81tEUS0ayoqXEFhi5GNU1okbvBpqU5GiUjv14DgiLUYXPUQ0qq+OdrFJM2j4j+w==} peerDependencies: @@ -15074,6 +15998,9 @@ packages: space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + spawn-sync@1.0.15: + resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==} + spawn-wrap@2.0.0: resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} engines: {node: '>=8'} @@ -15089,6 +16016,9 @@ packages: resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} engines: {node: '>= 10.x'} + split@1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -15231,6 +16161,14 @@ packages: resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} + strip-bom-buf@2.0.0: + resolution: {integrity: sha512-gLFNHucd6gzb8jMsl5QmZ3QgnUJmp7qn4uUSHNwEXumAp7YizoGYw19ZUVfuq4aBOQUtyn2k8X/CwzWB73W2lQ==} + engines: {node: '>=8'} + + strip-bom-stream@4.0.0: + resolution: {integrity: sha512-0ApK3iAkHv6WbgLICw/J4nhwHeDZsBxIIsOD+gHgZICL6SeJ0S9f/WZqemka9cjkTyMN5geId6e8U5WGFAn3cQ==} + engines: {node: '>=8'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -15239,6 +16177,10 @@ packages: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} + strip-bom@5.0.0: + resolution: {integrity: sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==} + engines: {node: '>=12'} + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} @@ -15259,10 +16201,17 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} + strip-json-comments@5.0.2: + resolution: {integrity: sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g==} + engines: {node: '>=14.16'} + strip-json-comments@5.0.3: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + stripe@19.3.1: resolution: {integrity: sha512-5NXhLxTZ+4uO1wnsmNysILVuyeZ1Xia7niz/8ykBkGJkCcrY2WyQZwcfYuWZmZEJtWr2+0j49JXwNC6y9CHL7Q==} engines: {node: '>=16'} @@ -15283,6 +16232,12 @@ packages: structured-headers@0.4.1: resolution: {integrity: sha512-0MP/Cxx5SzeeZ10p/bZI0S6MpgD+yxAhi1BOQ34jgnMXsCq3j1t6tQnZu+KdlL7dvJTLT3g9xN8tl10TqgFMcg==} + stubborn-fs@2.0.0: + resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} + + stubborn-utils@1.0.2: + resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} + style-loader@3.3.4: resolution: {integrity: sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==} engines: {node: '>= 12.13.0'} @@ -15388,10 +16343,17 @@ packages: tailwindcss@4.2.4: resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==} + tailwindcss@4.3.1: + resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==} + tapable@2.3.0: resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} engines: {node: '>=6'} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + tar-stream@3.1.8: resolution: {integrity: sha512-U6QpVRyCGHva435KoNWy9PRoi2IFYCgtEhq9nmrPPpbRacPs9IH4aJ3gbrFC8dPcXvdSZ4XXfXT5Fshbp2MtlQ==} @@ -15448,9 +16410,19 @@ packages: third-party-capital@1.0.20: resolution: {integrity: sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA==} + thread-stream@3.2.0: + resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==} + + thread-stream@4.2.0: + resolution: {integrity: sha512-e2zZ96wSChazBsbENf/Pcm/4swHt2cEKQ92rhUjkL9GCKiTDJIaTBenjE/m9DXi0QBmTMDkFDdOomUy20A1tDQ==} + engines: {node: '>=20'} + throat@5.0.0: resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + timers-browserify@2.0.12: resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} engines: {node: '>=0.6.0'} @@ -15465,6 +16437,10 @@ packages: resolution: {integrity: sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==} engines: {node: '>=18'} + tinyexec@1.2.4: + resolution: {integrity: sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==} + engines: {node: '>=18'} + tinyglobby@0.2.16: resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} @@ -15492,6 +16468,14 @@ packages: resolution: {integrity: sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==} hasBin: true + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + + tmp@0.2.7: + resolution: {integrity: sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==} + engines: {node: '>=14.14'} + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} @@ -15630,6 +16614,10 @@ packages: tw-animate-css@1.4.0: resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} @@ -15650,6 +16638,10 @@ packages: resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} engines: {node: '>=12.20'} + type-fest@3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + type-fest@4.41.0: resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} engines: {node: '>=16'} @@ -15675,6 +16667,9 @@ packages: typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -15688,6 +16683,9 @@ packages: uc.micro@2.1.0: resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + uglify-js@3.19.3: resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} engines: {node: '>=0.8.0'} @@ -15765,6 +16763,18 @@ packages: unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unimport@6.3.0: + resolution: {integrity: sha512-M+Dxk5W9WRd+8j56W9tp8lGW/dmMc7g5zj7BWQnEjKQhryBstqsi1V0izb0zHwSkEN8cSYV7K75/bykairV2tA==} + engines: {node: '>=18.12.0'} + peerDependencies: + oxc-parser: '*' + rolldown: ^1.0.0 + peerDependenciesMeta: + oxc-parser: + optional: true + rolldown: + optional: true + unist-util-is@6.0.1: resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} @@ -15797,19 +16807,35 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin-utils@0.3.1: + resolution: {integrity: sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==} + engines: {node: '>=20.19.0'} + unplugin@1.16.1: resolution: {integrity: sha512-4/u/j4FrCKdi17jaxuJA0jClGxB1AvU2hw/IuayPc4ay1XGaJs/rbb4v5WKwAjNifjmXK9PIFyuPiaK8azyR9w==} engines: {node: '>=14.0.0'} + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} + unrs-resolver@1.11.1: resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + upath@3.0.7: + resolution: {integrity: sha512-VjBBquch25nUGMuVBpOb2Cj3gc8Kb7lJBqbsXR/0anZ/5uJsL14Kpth9JKfnBsckxCfgIp6hPvcvvmZ97R9X7g==} + engines: {node: '>=20'} + update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' + update-notifier@7.3.1: + resolution: {integrity: sha512-+dwUY4L35XFYEzE+OAL3sarJdUioVovq+8f7lcIJ7wnmnYQV5UD1Y/lcwaMSyaQ6Bj3JMj1XSTjZbNLHn/19yA==} + engines: {node: '>=18'} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -15922,6 +16948,11 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} + vite-node@6.0.0: + resolution: {integrity: sha512-oj4PVrT+pDh6GYf5wfUXkcZyekYS8kKPfLPXVl8qe324Ec6l4K2DUKNadRbZ3LQl0qGcDz+PyOo7ZAh00Y+JjQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + vite@8.0.10: resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} engines: {node: ^20.19.0 || >=22.12.0} @@ -16038,6 +17069,10 @@ packages: warn-once@0.1.1: resolution: {integrity: sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==} + watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + engines: {node: '>=10.13.0'} + watchpack@2.5.1: resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} engines: {node: '>=10.13.0'} @@ -16050,6 +17085,15 @@ packages: wcwidth@1.0.1: resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + web-ext-run@0.2.4: + resolution: {integrity: sha512-rQicL7OwuqWdQWI33JkSXKcp7cuv1mJG8u3jRQwx/8aDsmhbTHs9ZRmNYOL+LX0wX8edIEQX8jj4bB60GoXtKA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + + web-ext@10.4.0: + resolution: {integrity: sha512-8QXl8qrGl1IMsFphOnKHHDciGo6B9cnuJ4KPzZu1xHZaAhIV2o+NH1CItQtpapJvNkJ8Iu4Ikmse579O8oJcjA==} + engines: {node: '>=20.0.0', npm: '>=8.0.0'} + hasBin: true + web-push@3.6.7: resolution: {integrity: sha512-OpiIUe8cuGjrj3mMBFWY+e4MMIkW3SVT+7vEIjvD9kejGUypv8GPDf84JdPWskK8zMRIJ6xYGm+Kxr8YkPyA0A==} engines: {node: '>= 16'} @@ -16106,9 +17150,18 @@ packages: webpack-cli: optional: true + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + whatwg-fetch@3.6.20: resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + whatwg-url-minimum@0.1.2: resolution: {integrity: sha512-XPEm0XFQWNVG292lII1PrRRJl3sItrs7CettZ4ncYxuDVpLyy+NwlGyut2hXI0JswcJUxeCH+CyOJK0ZzAXD6A==} @@ -16119,6 +17172,12 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + when-exit@2.1.5: + resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} + + when@3.7.7: + resolution: {integrity: sha512-9lFZp/KHoqH6bPKjbWqa+3Dg/K/r2v0X/3/G2x4DBGchVS2QX2VXL3cZV994WQVnTM1/PD71Az25nAzryEUugw==} + which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} @@ -16126,6 +17185,10 @@ packages: resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} + which@1.2.4: + resolution: {integrity: sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA==} + hasBin: true + which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -16135,15 +17198,31 @@ packages: engines: {node: '>= 8'} hasBin: true + which@4.0.0: + resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} + engines: {node: ^16.13.0 || >=18.0.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} hasBin: true + widest-line@5.0.0: + resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} + engines: {node: '>=18'} + widest-line@6.0.0: resolution: {integrity: sha512-U89AsyEeAsyoF0zVJBkG9zBgekjgjK7yk9sje3F4IQpXBJ10TF6ByLlIfjMhcmHMJgHZI4KHt4rdNfktzxIAMA==} engines: {node: '>=20'} + winreg@0.0.12: + resolution: {integrity: sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ==} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -16165,6 +17244,10 @@ packages: '@cloudflare/workers-types': optional: true + wrap-ansi@10.0.0: + resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} + engines: {node: '>=20'} + wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -16239,14 +17322,36 @@ packages: utf-8-validate: optional: true + wsl-utils@0.3.1: + resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} + engines: {node: '>=20'} + + wxt@0.20.26: + resolution: {integrity: sha512-PMGz7sAlONJgwBkOriInXOoEU6/jlGKrhSFvZfiBPHZocyYPfnw1lod9rGDra957H83WO+TnGjYwJiGYciSIqA==} + engines: {bun: '>=1.2.0', node: '>=20.12.0'} + hasBin: true + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true + xcode@3.0.1: resolution: {integrity: sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==} engines: {node: '>=10.0.0'} + xdg-basedir@5.1.0: + resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} + engines: {node: '>=12'} + xml2js@0.6.0: resolution: {integrity: sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w==} engines: {node: '>=4.0.0'} + xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + xml@1.0.1: resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} @@ -16304,6 +17409,14 @@ packages: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} + yauzl@3.3.0: + resolution: {integrity: sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ==} + engines: {node: '>=12'} + + yauzl@3.3.2: + resolution: {integrity: sha512-Md9ankxxN23wncAN8s7+Tn3Co52zLUPMtnrLAbVCnfG5d2tKBFfmygYSgXlqFgXObtzIgqkx7aNgDBpso9+4qA==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -16321,6 +17434,9 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} + zip-dir@2.0.0: + resolution: {integrity: sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==} + zip-stream@6.0.1: resolution: {integrity: sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==} engines: {node: '>= 14'} @@ -16365,6 +17481,11 @@ packages: snapshots: + '@1natsu/wait-element@4.2.0': + dependencies: + defu: 6.1.7 + many-keys-map: 3.0.3 + '@adobe/css-tools@4.4.4': {} '@agentclientprotocol/sdk@0.22.1(zod@4.4.3)': @@ -16413,6 +17534,15 @@ snapshots: dependencies: json-schema: 0.4.0 + '@aklinker1/rollup-plugin-visualizer@5.12.0(rollup@4.59.1)': + dependencies: + open: 8.4.2 + picomatch: 2.3.2 + source-map: 0.7.6 + yargs: 17.7.2 + optionalDependencies: + rollup: 4.59.1 + '@alcalzone/ansi-tokenize@0.2.5': dependencies: ansi-styles: 6.2.3 @@ -17807,8 +18937,12 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/runtime@7.28.2': {} + '@babel/runtime@7.29.2': {} + '@babel/runtime@7.29.7': {} + '@babel/template@7.28.6': dependencies: '@babel/code-frame': 7.29.0 @@ -18347,6 +19481,22 @@ snapshots: gonzales-pe: 4.3.0 node-source-walk: 7.0.1 + '@devicefarmer/adbkit-logcat@2.1.3': {} + + '@devicefarmer/adbkit-monkey@1.2.1': {} + + '@devicefarmer/adbkit@3.3.8': + dependencies: + '@devicefarmer/adbkit-logcat': 2.1.3 + '@devicefarmer/adbkit-monkey': 1.2.1 + bluebird: 3.7.2 + commander: 9.5.0 + debug: 4.3.7 + node-forge: 1.4.0 + split: 1.0.1 + transitivePeerDependencies: + - supports-color + '@discordjs/builders@1.13.1': dependencies: '@discordjs/formatters': 0.6.2 @@ -18542,8 +19692,52 @@ snapshots: '@esbuild/win32-x64@0.27.4': optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.2': {} + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + '@expo-google-fonts/jetbrains-mono@0.4.1': {} '@expo-google-fonts/material-symbols@0.4.27': {} @@ -18935,6 +20129,10 @@ snapshots: '@floating-ui/utils@0.2.11': {} + '@fluent/syntax@0.19.0': {} + + '@fregante/relaxed-json@2.0.0': {} + '@google/genai@2.7.0(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(bufferutil@4.1.0)(utf-8-validate@6.0.6)': dependencies: google-auth-library: 10.6.2 @@ -18986,6 +20184,22 @@ snapshots: '@trpc/server': 11.17.0(typescript@5.9.3) hono: 4.12.18 + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + '@img/colour@1.1.0': {} '@img/sharp-darwin-arm64@0.34.5': @@ -19116,10 +20330,10 @@ snapshots: jest-util: 30.3.0 slash: 3.0.0 - '@jest/core@29.7.0': + '@jest/core@29.7.0(node-notifier@10.0.1)': dependencies: '@jest/console': 29.7.0 - '@jest/reporters': 29.7.0 + '@jest/reporters': 29.7.0(node-notifier@10.0.1) '@jest/test-result': 29.7.0 '@jest/transform': 29.7.0 '@jest/types': 29.6.3 @@ -19146,16 +20360,18 @@ snapshots: pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - babel-plugin-macros - supports-color - ts-node - '@jest/core@30.3.0(esbuild-register@3.6.0(esbuild@0.27.4))': + '@jest/core@30.3.0(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1)': dependencies: '@jest/console': 30.3.0 '@jest/pattern': 30.0.1 - '@jest/reporters': 30.3.0 + '@jest/reporters': 30.3.0(node-notifier@10.0.1) '@jest/test-result': 30.3.0 '@jest/transform': 30.3.0 '@jest/types': 30.3.0 @@ -19180,6 +20396,8 @@ snapshots: jest-watcher: 30.3.0 pretty-format: 30.3.0 slash: 3.0.0 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - babel-plugin-macros - esbuild-register @@ -19275,7 +20493,7 @@ snapshots: '@types/node': 24.12.4 jest-regex-util: 30.0.1 - '@jest/reporters@29.7.0': + '@jest/reporters@29.7.0(node-notifier@10.0.1)': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 29.7.0 @@ -19301,10 +20519,12 @@ snapshots: string-length: 4.0.2 strip-ansi: 6.0.1 v8-to-istanbul: 9.3.0 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - supports-color - '@jest/reporters@30.3.0': + '@jest/reporters@30.3.0(node-notifier@10.0.1)': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 30.3.0 @@ -19329,6 +20549,8 @@ snapshots: slash: 3.0.0 string-length: 4.0.2 v8-to-istanbul: 9.3.0 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - supports-color @@ -19793,6 +21015,8 @@ snapshots: '@marijn/find-cluster-break@1.0.2': {} + '@mdn/browser-compat-data@8.0.2': {} + '@mdx-js/loader@3.1.1(webpack@5.105.4(@swc/core@1.15.18)(esbuild@0.27.4))': dependencies: '@mdx-js/mdx': 3.1.1 @@ -20891,6 +22115,8 @@ snapshots: '@paper-design/shaders@0.0.76': {} + '@pinojs/redact@0.4.0': {} + '@pkgr/core@0.2.9': {} '@playwright/test@1.58.2': @@ -20912,6 +22138,18 @@ snapshots: type-fest: 4.41.0 webpack-hot-middleware: 2.26.1 + '@pnpm/config.env-replace@1.1.0': {} + + '@pnpm/network.ca-file@1.0.2': + dependencies: + graceful-fs: 4.2.10 + + '@pnpm/npm-conf@3.0.3': + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + '@polka/url@1.0.0-next.29': {} '@poppinss/colors@4.1.6': @@ -22012,6 +23250,8 @@ snapshots: '@rolldown/pluginutils@1.0.0-rc.17': {} + '@rolldown/pluginutils@1.0.1': {} + '@rollup/plugin-commonjs@28.0.1(rollup@4.59.0)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.59.0) @@ -22522,9 +23762,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@shopify/flash-list@2.0.2(@babel/runtime@7.29.2)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0)': + '@shopify/flash-list@2.0.2(@babel/runtime@7.29.7)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0)': dependencies: - '@babel/runtime': 7.29.2 + '@babel/runtime': 7.29.7 react: 19.2.0 react-native: 0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6) tslib: 2.8.1 @@ -23023,11 +24263,11 @@ snapshots: '@storybook/addon-docs@8.5.8(@types/react@19.2.14)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))': dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.6) - '@storybook/blocks': 8.5.8(react-dom@19.2.4(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@storybook/blocks': 8.5.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)) '@storybook/csf-plugin': 8.5.8(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)) - '@storybook/react-dom-shim': 8.5.8(react-dom@19.2.4(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)) + '@storybook/react-dom-shim': 8.5.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)) react: 19.2.6 - react-dom: 19.2.4(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) ts-dedent: 2.2.0 transitivePeerDependencies: @@ -23037,10 +24277,10 @@ snapshots: dependencies: '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.6) '@storybook/csf-plugin': 9.1.20(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))) - '@storybook/icons': 1.6.0(react-dom@19.2.4(react@19.2.6))(react@19.2.6) - '@storybook/react-dom-shim': 9.1.20(react-dom@19.2.4(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))) + '@storybook/icons': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@storybook/react-dom-shim': 9.1.20(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))) react: 19.2.6 - react-dom: 19.2.4(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) ts-dedent: 2.2.0 transitivePeerDependencies: @@ -23100,15 +24340,15 @@ snapshots: memoizerific: 1.11.3 storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) - '@storybook/blocks@8.5.8(react-dom@19.2.4(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))': + '@storybook/blocks@8.5.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))': dependencies: '@storybook/csf': 0.1.12 - '@storybook/icons': 1.6.0(react-dom@19.2.4(react@19.2.6))(react@19.2.6) + '@storybook/icons': 1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) ts-dedent: 2.2.0 optionalDependencies: react: 19.2.6 - react-dom: 19.2.4(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) '@storybook/builder-webpack5@8.5.8(@swc/core@1.15.18)(esbuild@0.27.4)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))(typescript@5.9.3)': dependencies: @@ -23244,10 +24484,10 @@ snapshots: '@storybook/global@5.0.0': {} - '@storybook/icons@1.6.0(react-dom@19.2.4(react@19.2.6))(react@19.2.6)': + '@storybook/icons@1.6.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: react: 19.2.6 - react-dom: 19.2.4(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) '@storybook/manager-api@8.5.8(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))': dependencies: @@ -23365,16 +24605,10 @@ snapshots: transitivePeerDependencies: - supports-color - '@storybook/react-dom-shim@8.5.8(react-dom@19.2.4(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))': - dependencies: - react: 19.2.6 - react-dom: 19.2.4(react@19.2.6) - storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) - - '@storybook/react-dom-shim@9.1.20(react-dom@19.2.4(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)))': + '@storybook/react-dom-shim@8.5.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6))': dependencies: react: 19.2.6 - react-dom: 19.2.4(react@19.2.6) + react-dom: 19.2.6(react@19.2.6) storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) '@storybook/react-dom-shim@9.1.20(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)))': @@ -23434,7 +24668,7 @@ snapshots: ts-dedent: 2.2.0 yaml: 2.8.4 - '@storybook/test-runner@0.23.0(@types/node@25.5.2)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)))': + '@storybook/test-runner@0.23.0(@types/node@25.5.2)(node-notifier@10.0.1)(storybook@9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)))': dependencies: '@babel/core': 7.29.0 '@babel/generator': 7.29.1 @@ -23444,14 +24678,14 @@ snapshots: '@swc/core': 1.15.18 '@swc/jest': 0.2.39(@swc/core@1.15.18) expect-playwright: 0.8.0 - jest: 29.7.0(@types/node@25.5.2) + jest: 29.7.0(@types/node@25.5.2)(node-notifier@10.0.1) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-junit: 16.0.0 - jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@25.5.2)) + jest-playwright-preset: 4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@25.5.2)(node-notifier@10.0.1)) jest-runner: 29.7.0 jest-serializer-html: 7.1.0 - jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@25.5.2)) + jest-watch-typeahead: 2.2.2(jest@29.7.0(@types/node@25.5.2)(node-notifier@10.0.1)) nyc: 15.1.0 playwright: 1.58.2 storybook: 9.1.20(bufferutil@4.1.0)(utf-8-validate@6.0.6)(vite@8.0.10(@types/node@25.5.2)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) @@ -23545,42 +24779,88 @@ snapshots: source-map-js: 1.2.1 tailwindcss: 4.2.4 + '@tailwindcss/node@4.3.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.30.1 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.1 + '@tailwindcss/oxide-android-arm64@4.2.4': optional: true + '@tailwindcss/oxide-android-arm64@4.3.1': + optional: true + '@tailwindcss/oxide-darwin-arm64@4.2.4': optional: true + '@tailwindcss/oxide-darwin-arm64@4.3.1': + optional: true + '@tailwindcss/oxide-darwin-x64@4.2.4': optional: true + '@tailwindcss/oxide-darwin-x64@4.3.1': + optional: true + '@tailwindcss/oxide-freebsd-x64@4.2.4': optional: true + '@tailwindcss/oxide-freebsd-x64@4.3.1': + optional: true + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': optional: true + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + optional: true + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': optional: true + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + optional: true + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': optional: true + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + optional: true + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': optional: true + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + optional: true + '@tailwindcss/oxide-linux-x64-musl@4.2.4': optional: true + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + optional: true + '@tailwindcss/oxide-wasm32-wasi@4.2.4': optional: true + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + optional: true + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': optional: true + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + optional: true + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': optional: true + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + optional: true + '@tailwindcss/oxide@4.2.4': optionalDependencies: '@tailwindcss/oxide-android-arm64': 4.2.4 @@ -23596,6 +24876,21 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 + '@tailwindcss/oxide@4.3.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-x64': 4.3.1 + '@tailwindcss/oxide-freebsd-x64': 4.3.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-x64-musl': 4.3.1 + '@tailwindcss/oxide-wasm32-wasi': 4.3.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.1 + '@tailwindcss/postcss@4.2.4': dependencies: '@alloc/quick-lru': 5.2.0 @@ -23609,6 +24904,13 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 4.2.4 + '@tailwindcss/vite@4.3.1(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))': + dependencies: + '@tailwindcss/node': 4.3.1 + '@tailwindcss/oxide': 4.3.1 + tailwindcss: 4.3.1 + vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + '@tanstack/query-core@5.100.10': {} '@tanstack/react-query@5.100.10(react@19.2.0)': @@ -23774,12 +25076,20 @@ snapshots: '@types/estree@1.0.8': {} + '@types/filesystem@0.0.36': + dependencies: + '@types/filewriter': 0.0.33 + + '@types/filewriter@0.0.33': {} + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 24.12.4 '@types/hammerjs@2.0.46': {} + '@types/har-format@1.2.16': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -23832,6 +25142,8 @@ snapshots: '@types/mdx@2.0.13': {} + '@types/minimatch@3.0.5': {} + '@types/ms@2.1.0': {} '@types/mysql@2.15.27': @@ -23920,6 +25232,8 @@ snapshots: dependencies: '@types/node': 24.12.4 + '@types/webextension-polyfill@0.12.5': {} + '@types/ws@8.18.1': dependencies: '@types/node': 24.12.4 @@ -24114,6 +25428,13 @@ snapshots: '@opentelemetry/sdk-metrics': 2.6.1(@opentelemetry/api@1.9.1) '@opentelemetry/sdk-trace-base': 2.6.0(@opentelemetry/api@1.9.1) + '@vitejs/plugin-react@6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + optionalDependencies: + babel-plugin-react-compiler: 1.0.0 + '@vitest/coverage-v8@4.1.6(vitest@4.1.6)': dependencies: '@bcoe/v8-coverage': 1.0.2 @@ -24126,7 +25447,7 @@ snapshots: obug: 2.1.1 std-env: 4.0.0 tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) '@vitest/expect@3.2.4': dependencies: @@ -24212,7 +25533,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@25.5.2)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vitest: 4.1.6(@opentelemetry/api@1.9.1)(@types/node@24.12.4)(@vitest/coverage-v8@4.1.6)(@vitest/ui@4.1.6)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) '@vitest/utils@3.2.4': dependencies: @@ -24336,12 +25657,43 @@ snapshots: '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 + '@webext-core/fake-browser@1.5.2': + dependencies: + '@types/webextension-polyfill': 0.12.5 + lodash.merge: 4.6.2 + + '@webext-core/isolated-element@1.1.5': + dependencies: + is-potential-custom-element-name: 1.0.1 + + '@webext-core/match-patterns@1.0.3': {} + '@workflow/serde@4.1.0-beta.2': {} '@workos-inc/node@8.13.0': dependencies: eventemitter3: 5.0.4 + '@wxt-dev/browser@0.1.43': + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.16 + + '@wxt-dev/module-react@1.2.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))(wxt@0.20.26(@types/node@24.12.4)(eslint@9.39.4(jiti@2.7.0))(jiti@2.7.0)(oxc-parser@0.120.0)(rollup@4.59.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4))': + dependencies: + '@vitejs/plugin-react': 6.0.2(babel-plugin-react-compiler@1.0.0)(vite@8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4)) + vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + wxt: 0.20.26(@types/node@24.12.4)(eslint@9.39.4(jiti@2.7.0))(jiti@2.7.0)(oxc-parser@0.120.0)(rollup@4.59.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + transitivePeerDependencies: + - '@rolldown/plugin-babel' + - babel-plugin-react-compiler + + '@wxt-dev/storage@1.2.8': + dependencies: + '@wxt-dev/browser': 0.1.43 + async-mutex: 0.5.0 + dequal: 2.0.3 + '@xmldom/xmldom@0.8.13': {} '@xterm/addon-clipboard@0.2.0': @@ -24396,11 +25748,58 @@ snapshots: acorn@8.16.0: {} + addons-linter@10.7.0(express@5.2.1)(jiti@2.7.0): + dependencies: + '@fluent/syntax': 0.19.0 + '@fregante/relaxed-json': 2.0.0 + '@mdn/browser-compat-data': 8.0.2 + addons-moz-compare: 1.3.0 + addons-scanner-utils: 15.2.0(express@5.2.1) + ajv: 8.20.0 + cheerio: 1.2.0 + columnify: 1.6.0 + common-tags: 1.8.2 + deepmerge: 4.3.1 + eslint: 9.39.4(jiti@2.7.0) + eslint-plugin-no-unsanitized: 4.1.5(eslint@9.39.4(jiti@2.7.0)) + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esprima: 4.0.1 + fast-json-patch: 3.1.1 + image-size: 2.0.2 + json-merge-patch: 1.0.2 + pino: 10.3.1 + semver: 7.8.2 + source-map-support: 0.5.21 + upath: 3.0.7 + yargs: 17.7.2 + yauzl: 3.3.2 + transitivePeerDependencies: + - express + - jiti + - safe-compare + - supports-color + + addons-moz-compare@1.3.0: {} + + addons-scanner-utils@15.2.0(express@5.2.1): + dependencies: + common-tags: 1.8.2 + first-chunk-stream: 3.0.0 + jsonwebtoken: 9.0.3 + strip-bom-stream: 4.0.0 + upath: 3.0.7 + yauzl: 3.3.0 + optionalDependencies: + express: 5.2.1 + adjust-sourcemap-loader@4.0.0: dependencies: loader-utils: 2.0.4 regex-parser: 2.3.1 + adm-zip@0.5.17: {} + agent-base@6.0.2: dependencies: debug: 4.4.3 @@ -24464,6 +25863,10 @@ snapshots: anser@2.3.5: {} + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -24549,8 +25952,12 @@ snapshots: aria-query@5.3.2: {} + array-differ@4.0.0: {} + array-timsort@1.0.3: {} + array-union@3.0.1: {} + asap@2.0.6: {} asn1.js@4.10.1: @@ -24590,10 +25997,21 @@ snapshots: astring@1.9.0: {} + async-mutex@0.5.0: + dependencies: + tslib: 2.8.1 + async@3.2.6: {} asynckit@0.4.0: {} + atomic-sleep@1.0.0: {} + + atomically@2.1.1: + dependencies: + stubborn-fs: 2.0.0 + when-exit: 2.1.5 + auto-bind@5.0.1: {} available-typed-arrays@1.0.7: @@ -24867,6 +26285,8 @@ snapshots: blake3-wasm@2.1.5: {} + bluebird@3.7.2: {} + bn.js@4.12.3: {} bn.js@5.2.3: {} @@ -24891,6 +26311,17 @@ snapshots: bowser@2.14.1: {} + boxen@8.0.1: + dependencies: + ansi-align: 3.0.1 + camelcase: 8.0.0 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 7.2.0 + type-fest: 4.41.0 + widest-line: 5.0.0 + wrap-ansi: 9.0.2 + bplist-creator@0.1.0: dependencies: stream-buffers: 2.2.0 @@ -24975,6 +26406,8 @@ snapshots: dependencies: node-int64: 0.4.0 + buffer-crc32@0.2.13: {} + buffer-crc32@1.0.0: {} buffer-equal-constant-time@1.0.1: {} @@ -25005,8 +26438,33 @@ snapshots: dependencies: '@types/node': 24.12.4 + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + bytes@3.1.2: {} + c12@3.3.4(magicast@0.5.2): + dependencies: + chokidar: 5.0.0 + confbox: 0.2.4 + defu: 6.1.7 + dotenv: 17.3.1 + exsolve: 1.0.8 + giget: 3.3.0 + jiti: 2.7.0 + ohash: 2.0.11 + pathe: 2.0.3 + perfect-debounce: 2.1.0 + pkg-types: 2.3.1 + rc9: 3.0.1 + optionalDependencies: + magicast: 0.5.2 + + cac@6.7.14: {} + + cac@7.0.0: {} + caching-transform@4.0.0: dependencies: hasha: 5.2.2 @@ -25042,6 +26500,8 @@ snapshots: camelcase@6.3.0: {} + camelcase@8.0.0: {} + caniuse-lite@1.0.30001779: {} capnweb@0.8.0: {} @@ -25099,6 +26559,29 @@ snapshots: check-error@2.1.3: {} + cheerio-select@2.1.0: + dependencies: + boolbase: 1.0.0 + css-select: 5.2.2 + css-what: 6.2.2 + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + + cheerio@1.2.0: + dependencies: + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.2.2 + encoding-sniffer: 0.2.1 + htmlparser2: 10.1.0 + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 + parse5-parser-stream: 7.1.2 + undici: 7.25.0 + whatwg-mimetype: 4.0.0 + chokidar@3.6.0: dependencies: anymatch: 3.1.3 @@ -25130,6 +26613,15 @@ snapshots: transitivePeerDependencies: - supports-color + chrome-launcher@1.2.0: + dependencies: + '@types/node': 24.12.4 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 2.0.2 + transitivePeerDependencies: + - supports-color + chrome-trace-event@1.0.4: {} chromium-edge-launcher@0.2.0: @@ -25155,6 +26647,8 @@ snapshots: safe-buffer: 5.2.1 to-buffer: 1.2.2 + citty@0.2.2: {} + cjs-module-lexer@1.2.3: {} cjs-module-lexer@1.4.3: {} @@ -25193,6 +26687,10 @@ snapshots: dependencies: restore-cursor: 4.0.0 + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + cli-spinners@2.9.2: {} cli-truncate@5.2.0: @@ -25285,6 +26783,11 @@ snapshots: colorjs.io@0.6.0-alpha.1: {} + columnify@1.6.0: + dependencies: + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -25297,12 +26800,18 @@ snapshots: commander@2.20.3: {} + commander@2.9.0: + dependencies: + graceful-readlink: 1.0.1 + commander@3.0.2: {} commander@7.2.0: {} commander@8.3.0: {} + commander@9.5.0: {} + comment-json@4.6.2: dependencies: array-timsort: 1.0.3 @@ -25310,6 +26819,8 @@ snapshots: common-path-prefix@3.0.0: {} + common-tags@1.8.2: {} + commondir@1.0.1: {} compress-commons@6.0.2: @@ -25338,6 +26849,29 @@ snapshots: compute-scroll-into-view@2.0.4: {} + concat-stream@1.6.2: + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + + confbox@0.1.8: {} + + confbox@0.2.4: {} + + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + + configstore@7.1.0: + dependencies: + atomically: 2.1.1 + dot-prop: 9.0.0 + graceful-fs: 4.2.11 + xdg-basedir: 5.1.0 + connect@3.7.0: dependencies: debug: 2.6.9 @@ -25347,6 +26881,8 @@ snapshots: transitivePeerDependencies: - supports-color + consola@3.4.2: {} + console-browserify@1.2.0: {} constants-browserify@1.0.0: {} @@ -25612,12 +27148,18 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.3.7: + dependencies: + ms: 2.1.3 + debug@4.4.3: dependencies: ms: 2.1.3 decamelize@1.2.0: {} + decamelize@6.0.1: {} + decimal.js-light@2.5.1: {} decode-named-character-reference@1.3.0: @@ -25638,8 +27180,17 @@ snapshots: deep-extend@0.6.0: {} + deep-is@0.1.4: {} + deepmerge@4.3.1: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + default-require-extensions@3.0.1: dependencies: strip-bom: 4.0.0 @@ -25656,12 +27207,16 @@ snapshots: define-lazy-prop@2.0.0: {} + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 + defu@6.1.7: {} + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -25703,6 +27258,8 @@ snapshots: inherits: 2.0.4 minimalistic-assert: 1.0.1 + destr@2.0.5: {} + destroy@1.2.0: {} detect-libc@2.1.2: {} @@ -25887,6 +27444,10 @@ snapshots: no-case: 3.0.4 tslib: 2.8.1 + dot-prop@9.0.0: + dependencies: + type-fest: 4.41.0 + dotenv-expand@12.0.3: dependencies: dotenv: 16.6.1 @@ -25982,6 +27543,11 @@ snapshots: encodeurl@2.0.0: {} + encoding-sniffer@0.2.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-encoding: 3.1.1 + end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -26002,12 +27568,19 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + entities@1.1.2: {} entities@2.2.0: {} entities@4.5.0: {} + entities@6.0.1: {} + entities@7.0.1: {} env-paths@2.2.1: {} @@ -26121,6 +27694,8 @@ snapshots: escape-carriage@1.3.1: {} + escape-goat@4.0.0: {} + escape-html@1.0.3: {} escape-string-regexp@1.0.5: {} @@ -26139,11 +27714,16 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-plugin-sonarjs@4.0.3: + eslint-plugin-no-unsanitized@4.1.5(eslint@9.39.4(jiti@2.7.0)): + dependencies: + eslint: 9.39.4(jiti@2.7.0) + + eslint-plugin-sonarjs@4.0.3(eslint@9.39.4(jiti@2.7.0)): dependencies: '@eslint-community/regexpp': 4.12.2 builtin-modules: 3.3.0 bytes: 3.1.2 + eslint: 9.39.4(jiti@2.7.0) functional-red-black-tree: 1.0.1 globals: 17.4.0 jsx-ast-utils-x: 0.1.0 @@ -26151,16 +27731,66 @@ snapshots: minimatch: 10.2.5 scslre: 0.3.0 semver: 7.7.4 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + eslint-visitor-keys@5.0.1: {} + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + esniff@2.0.1: dependencies: d: 1.0.2 @@ -26168,8 +27798,24 @@ snapshots: event-emitter: 0.3.5 type: 2.7.3 + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + espree@11.2.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 5.0.1 + esprima@4.0.1: {} + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 @@ -26680,6 +28326,8 @@ snapshots: transitivePeerDependencies: - supports-color + exsolve@1.0.8: {} + ext@1.7.0: dependencies: type: 2.7.3 @@ -26706,8 +28354,14 @@ snapshots: fast-json-parse@1.0.3: {} + fast-json-patch@3.1.1: {} + fast-json-stable-stringify@2.1.0: {} + fast-levenshtein@2.0.6: {} + + fast-redact@3.5.0: {} + fast-sha256@1.3.0: {} fast-string-truncated-width@3.0.3: {} @@ -26768,6 +28422,10 @@ snapshots: fflate@0.8.2: {} + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + file-type@22.0.1: dependencies: '@tokenizer/inflate': 0.4.1 @@ -26779,11 +28437,13 @@ snapshots: filesize@10.1.6: {} + filesize@11.0.17: {} + filing-cabinet@5.2.0: dependencies: app-module-path: 2.2.0 commander: 12.1.0 - enhanced-resolve: 5.20.0 + enhanced-resolve: 5.20.1 module-definition: 6.0.1 module-lookup-amd: 9.1.1 resolve: 1.22.11 @@ -26873,12 +28533,27 @@ snapshots: path-exists: 5.0.0 unicorn-magic: 0.1.0 + firefox-profile@4.7.0: + dependencies: + adm-zip: 0.5.17 + fs-extra: 11.3.5 + ini: 4.1.3 + minimist: 1.2.8 + xml2js: 0.6.2 + + first-chunk-stream@3.0.0: {} + flat-cache@3.2.0: dependencies: flatted: 3.4.1 keyv: 4.5.4 rimraf: 3.0.2 + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + flatted@3.4.1: {} flatted@3.4.2: {} @@ -26932,6 +28607,8 @@ snapshots: typescript: 5.9.3 webpack: 5.105.4(esbuild@0.27.4) + form-data-encoder@4.1.0: {} + form-data@4.0.5: dependencies: asynckit: 0.4.0 @@ -26946,6 +28623,8 @@ snapshots: dependencies: fd-package-json: 2.0.0 + formdata-node@6.0.3: {} + formdata-polyfill@4.0.10: dependencies: fetch-blob: 3.2.0 @@ -26978,6 +28657,12 @@ snapshots: jsonfile: 6.2.0 universalify: 2.0.1 + fs-extra@11.3.5: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-monkey@1.1.0: {} fsevents@2.3.2: @@ -26992,6 +28677,22 @@ snapshots: fuzzysort@3.1.0: {} + fx-runner@1.4.0: + dependencies: + commander: 2.9.0 + shell-quote: 1.8.4 + spawn-sync: 1.0.15 + when: 3.7.7 + which: 1.2.4 + winreg: 0.0.12 + + fx-runner@1.5.0: + dependencies: + commander: 12.1.0 + shell-quote: 1.8.4 + which: 4.0.0 + winreg: 0.0.12 + gaxios@7.1.4: dependencies: extend: 3.0.2 @@ -27042,6 +28743,8 @@ snapshots: get-package-type@0.1.0: {} + get-port-please@3.2.0: {} + get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 @@ -27055,12 +28758,18 @@ snapshots: getenv@2.0.0: {} + giget@3.3.0: {} + github-slugger@2.0.0: {} glob-parent@5.1.2: dependencies: is-glob: 4.0.3 + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + glob-to-regexp@0.4.1: {} glob@13.0.6: @@ -27085,6 +28794,8 @@ snapshots: is-windows: 0.2.0 which: 1.3.1 + globals@14.0.0: {} + globals@17.4.0: {} gonzales-pe@4.3.0: @@ -27106,8 +28817,12 @@ snapshots: gopd@1.2.0: {} + graceful-fs@4.2.10: {} + graceful-fs@4.2.11: {} + graceful-readlink@1.0.1: {} + grammy@1.43.0: dependencies: '@grammyjs/types': 3.27.3 @@ -27118,6 +28833,8 @@ snapshots: - encoding - supports-color + growly@1.3.0: {} + gzip-size@6.0.0: dependencies: duplexer: 0.1.2 @@ -27260,6 +28977,8 @@ snapshots: hono@4.12.18: {} + hookable@6.1.1: {} + hosted-git-info@10.1.1: dependencies: lru-cache: 11.2.7 @@ -27359,6 +29078,10 @@ snapshots: husky@9.1.7: {} + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + iconv-lite@0.7.2: dependencies: safer-buffer: 2.1.2 @@ -27404,18 +29127,24 @@ snapshots: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 + import-meta-resolve@4.2.0: {} + imurmurhash@0.1.4: {} indent-string@4.0.0: {} indent-string@5.0.0: {} + index-to-position@1.2.0: {} + inherits@2.0.4: {} ini@1.3.8: {} ini@4.1.1: {} + ini@4.1.3: {} + ini@6.0.0: {} ink@6.8.0(@types/react@19.2.14)(bufferutil@4.1.0)(react-devtools-core@6.1.5(bufferutil@4.1.0)(utf-8-validate@6.0.6))(react@19.2.6)(utf-8-validate@6.0.6): @@ -27469,6 +29198,10 @@ snapshots: ipaddr.js@1.9.1: {} + is-absolute@0.1.7: + dependencies: + is-relative: 0.1.3 + is-alphabetical@2.0.1: {} is-alphanumerical@2.0.1: @@ -27499,6 +29232,8 @@ snapshots: is-docker@2.2.1: {} + is-docker@3.0.0: {} + is-electron@2.2.2: {} is-extglob@2.1.1: {} @@ -27527,8 +29262,16 @@ snapshots: is-hexadecimal@2.0.1: {} + is-in-ci@1.0.0: {} + is-in-ci@2.0.0: {} + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-installed-globally@1.0.0: dependencies: global-directory: 4.0.1 @@ -27541,6 +29284,8 @@ snapshots: call-bind: 1.0.8 define-properties: 1.2.1 + is-npm@6.1.0: {} + is-number@7.0.0: {} is-obj@1.0.1: {} @@ -27549,8 +29294,16 @@ snapshots: is-plain-obj@4.1.0: {} + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + is-plain-object@5.0.0: {} + is-potential-custom-element-name@1.0.1: {} + + is-primitive@3.0.1: {} + is-promise@4.0.0: {} is-reference@1.2.1: @@ -27566,6 +29319,8 @@ snapshots: is-regexp@1.0.0: {} + is-relative@0.1.3: {} + is-stream@2.0.1: {} is-typed-array@1.1.15: @@ -27580,6 +29335,8 @@ snapshots: is-url@1.2.4: {} + is-utf8@0.2.1: {} + is-windows@0.2.0: {} is-windows@1.0.2: {} @@ -27588,12 +29345,22 @@ snapshots: dependencies: is-docker: 2.2.1 + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isarray@1.0.0: {} isarray@2.0.5: {} + isexe@1.1.2: {} + isexe@2.0.0: {} + isexe@3.1.5: {} + + isobject@3.0.1: {} + istanbul-lib-coverage@3.2.2: {} istanbul-lib-hook@3.0.0: @@ -27733,9 +29500,9 @@ snapshots: - babel-plugin-macros - supports-color - jest-cli@29.7.0(@types/node@24.12.4): + jest-cli@29.7.0(@types/node@24.12.4)(node-notifier@10.0.1): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(node-notifier@10.0.1) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 @@ -27746,15 +29513,17 @@ snapshots: jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest-cli@29.7.0(@types/node@25.5.2): + jest-cli@29.7.0(@types/node@25.5.2)(node-notifier@10.0.1): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(node-notifier@10.0.1) '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 chalk: 4.1.2 @@ -27765,15 +29534,17 @@ snapshots: jest-util: 29.7.0 jest-validate: 29.7.0 yargs: 17.7.2 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest-cli@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)): + jest-cli@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1): dependencies: - '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4)) + '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) '@jest/test-result': 30.3.0 '@jest/types': 30.3.0 chalk: 4.1.2 @@ -27783,6 +29554,8 @@ snapshots: jest-util: 30.3.0 jest-validate: 30.3.0 yargs: 17.7.2 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -27790,9 +29563,9 @@ snapshots: - supports-color - ts-node - jest-cli@30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4)): + jest-cli@30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1): dependencies: - '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4)) + '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) '@jest/test-result': 30.3.0 '@jest/types': 30.3.0 chalk: 4.1.2 @@ -27802,6 +29575,8 @@ snapshots: jest-util: 30.3.0 jest-validate: 30.3.0 yargs: 17.7.2 + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -28090,10 +29865,10 @@ snapshots: '@types/node': 24.12.4 jest-util: 30.3.0 - jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@25.5.2)): + jest-playwright-preset@4.0.0(jest-circus@29.7.0)(jest-environment-node@29.7.0)(jest-runner@29.7.0)(jest@29.7.0(@types/node@25.5.2)(node-notifier@10.0.1)): dependencies: expect-playwright: 0.8.0 - jest: 29.7.0(@types/node@25.5.2) + jest: 29.7.0(@types/node@25.5.2)(node-notifier@10.0.1) jest-circus: 29.7.0 jest-environment-node: 29.7.0 jest-process-manager: 0.4.0 @@ -28369,11 +30144,11 @@ snapshots: leven: 3.1.0 pretty-format: 30.3.0 - jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@25.5.2)): + jest-watch-typeahead@2.2.2(jest@29.7.0(@types/node@25.5.2)(node-notifier@10.0.1)): dependencies: ansi-escapes: 6.2.1 chalk: 5.6.2 - jest: 29.7.0(@types/node@25.5.2) + jest: 29.7.0(@types/node@25.5.2)(node-notifier@10.0.1) jest-regex-util: 29.6.3 jest-watcher: 29.7.0 slash: 5.1.0 @@ -28423,36 +30198,42 @@ snapshots: merge-stream: 2.0.0 supports-color: 8.1.1 - jest@29.7.0(@types/node@24.12.4): + jest@29.7.0(@types/node@24.12.4)(node-notifier@10.0.1): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(node-notifier@10.0.1) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@24.12.4) + jest-cli: 29.7.0(@types/node@24.12.4)(node-notifier@10.0.1) + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@29.7.0(@types/node@25.5.2): + jest@29.7.0(@types/node@25.5.2)(node-notifier@10.0.1): dependencies: - '@jest/core': 29.7.0 + '@jest/core': 29.7.0(node-notifier@10.0.1) '@jest/types': 29.6.3 import-local: 3.2.0 - jest-cli: 29.7.0(@types/node@25.5.2) + jest-cli: 29.7.0(@types/node@25.5.2)(node-notifier@10.0.1) + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)): + jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1): dependencies: - '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4)) + '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) '@jest/types': 30.3.0 import-local: 3.2.0 - jest-cli: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)) + jest-cli: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -28460,12 +30241,14 @@ snapshots: - supports-color - ts-node - jest@30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4)): + jest@30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1): dependencies: - '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4)) + '@jest/core': 30.3.0(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) '@jest/types': 30.3.0 import-local: 3.2.0 - jest-cli: 30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4)) + jest-cli: 30.3.0(@types/node@25.5.2)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) + optionalDependencies: + node-notifier: 10.0.1 transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -28491,6 +30274,8 @@ snapshots: jose@5.10.0: {} + jose@5.9.6: {} + jose@6.2.3: {} jotai-minidb@0.0.8(jotai@2.18.1(@babel/core@7.29.0)(@babel/template@7.28.6)(@types/react@19.2.14)(react@19.2.6)): @@ -28521,6 +30306,8 @@ snapshots: js-tokens@4.0.0: {} + js-tokens@9.0.1: {} + js-yaml@3.14.2: dependencies: argparse: 1.0.10 @@ -28540,8 +30327,14 @@ snapshots: json-buffer@3.0.1: {} + json-merge-patch@1.0.2: + dependencies: + fast-deep-equal: 3.1.3 + json-parse-even-better-errors@2.3.1: {} + json-parse-even-better-errors@3.0.2: {} + json-schema-to-ts@3.1.1: dependencies: '@babel/runtime': 7.29.2 @@ -28555,6 +30348,8 @@ snapshots: json-schema@0.4.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} + json-with-bigint@3.5.7: {} json5@2.2.3: {} @@ -28648,16 +30443,27 @@ snapshots: kubernetes-types@1.30.0: {} + ky@1.14.3: {} + kysely@0.29.2: {} lan-network@0.2.1: {} + latest-version@9.0.0: + dependencies: + package-json: 10.0.1 + lazystream@1.0.1: dependencies: readable-stream: 2.3.8 leven@3.1.0: {} + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + lexical@0.35.0: {} lie@3.3.0: @@ -28671,6 +30477,13 @@ snapshots: transitivePeerDependencies: - supports-color + lighthouse-logger@2.0.2: + dependencies: + debug: 4.4.3 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + lightningcss-darwin-arm64@1.30.1: optional: true @@ -28718,6 +30531,8 @@ snapshots: lines-and-columns@1.2.4: {} + lines-and-columns@2.0.4: {} + linkedom@0.18.12: dependencies: css-select: 5.2.2 @@ -28730,6 +30545,14 @@ snapshots: dependencies: uc.micro: 2.1.0 + listr2@10.2.1: + dependencies: + cli-truncate: 5.2.0 + eventemitter3: 5.0.4 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 10.0.0 + loader-runner@4.3.1: {} loader-utils@2.0.4: @@ -28740,6 +30563,12 @@ snapshots: loader-utils@3.3.1: {} + local-pkg@1.2.1: + dependencies: + mlly: 1.8.2 + pkg-types: 2.3.1 + quansync: 0.2.11 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -28791,6 +30620,14 @@ snapshots: chalk: 4.1.2 is-unicode-supported: 0.1.0 + log-update@6.1.0: + dependencies: + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + loglevel@1.9.2: {} long@5.3.2: {} @@ -28885,6 +30722,8 @@ snapshots: dependencies: tmpl: 1.0.5 + many-keys-map@3.0.3: {} + map-or-similar@1.5.0: {} markdown-extensions@2.0.0: {} @@ -29611,6 +31450,8 @@ snapshots: mimic-fn@2.1.0: {} + mimic-function@5.0.1: {} + mimic-response@3.1.0: {} min-indent@1.0.1: {} @@ -29661,6 +31502,13 @@ snapshots: mkdirp@1.0.4: {} + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + module-definition@6.0.1: dependencies: ast-module-types: 6.0.1 @@ -29718,12 +31566,25 @@ snapshots: optionalDependencies: msgpackr-extract: 3.0.3 + multimatch@6.0.0: + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 4.0.0 + array-union: 3.0.1 + minimatch: 3.1.5 + multipasta@0.2.7: {} multitars@1.0.0: {} + nano-spawn@2.1.0: {} + nanoid@3.3.11: {} + nanospinner@1.2.2: + dependencies: + picocolors: 1.1.1 + napi-postinstall@0.3.4: {} nativewind@5.0.0-preview.3(react-native-css@3.0.7(@expo/metro-config@55.0.21(bufferutil@4.1.0)(expo@55.0.24)(typescript@5.9.3)(utf-8-validate@6.0.6))(lightningcss@1.30.1)(react-native@0.83.6(@babel/core@7.29.0)(@types/react@19.2.14)(bufferutil@4.1.0)(react@19.2.0)(utf-8-validate@6.0.6))(react@19.2.0))(tailwindcss@4.2.4): @@ -29814,6 +31675,8 @@ snapshots: emojilib: 2.4.0 skin-tone: 2.0.0 + node-fetch-native@1.6.7: {} + node-fetch@2.6.7: dependencies: whatwg-url: 5.0.0 @@ -29848,6 +31711,15 @@ snapshots: node-int64@0.4.0: {} + node-notifier@10.0.1: + dependencies: + growly: 1.3.0 + is-wsl: 2.2.0 + semver: 7.7.4 + shellwords: 0.1.1 + uuid: 8.3.2 + which: 2.0.2 + node-polyfill-webpack-plugin@2.0.1(webpack@5.105.4(esbuild@0.27.4)): dependencies: assert: 2.1.0 @@ -29938,6 +31810,12 @@ snapshots: transitivePeerDependencies: - supports-color + nypm@0.6.7: + dependencies: + citty: 0.2.2 + pathe: 2.0.3 + tinyexec: 1.2.4 + oauth@0.9.15: {} ob1@0.83.7: @@ -29970,8 +31848,18 @@ snapshots: obug@2.1.1: {} + ofetch@1.5.1: + dependencies: + destr: 2.0.5 + node-fetch-native: 1.6.7 + ufo: 1.6.4 + + ohash@2.0.11: {} + oidc-token-hash@5.2.0: {} + on-exit-leak-free@2.1.2: {} + on-finished@2.3.0: dependencies: ee-first: 1.1.1 @@ -29994,6 +31882,19 @@ snapshots: dependencies: mimic-fn: 2.1.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + open@11.0.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.1.0 + wsl-utils: 0.3.1 + open@7.4.2: dependencies: is-docker: 2.2.1 @@ -30092,6 +31993,15 @@ snapshots: object-hash: 2.2.0 oidc-token-hash: 5.2.0 + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + ora@3.4.0: dependencies: chalk: 2.4.2 @@ -30117,6 +32027,8 @@ snapshots: os-homedir@1.0.2: {} + os-shim@0.1.3: {} + outvariant@1.4.0: {} oxc-parser@0.120.0: @@ -30287,6 +32199,13 @@ snapshots: package-json-from-dist@1.0.1: {} + package-json@10.0.1: + dependencies: + ky: 1.14.3 + registry-auth-token: 5.1.1 + registry-url: 6.0.1 + semver: 7.7.4 + pako@1.0.11: {} param-case@3.0.4: @@ -30323,6 +32242,20 @@ snapshots: json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 + parse-json@7.1.1: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + + parse-json@8.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + index-to-position: 1.2.0 + type-fest: 4.41.0 + parse-ms@2.1.0: {} parse-passwd@1.0.0: {} @@ -30331,6 +32264,19 @@ snapshots: dependencies: pngjs: 3.4.0 + parse5-htmlparser2-tree-adapter@7.1.0: + dependencies: + domhandler: 5.0.3 + parse5: 7.3.0 + + parse5-parser-stream@7.1.2: + dependencies: + parse5: 7.3.0 + + parse5@7.3.0: + dependencies: + entities: 6.0.1 + parseurl@1.3.3: {} partial-json@0.1.7: {} @@ -30376,6 +32322,10 @@ snapshots: sha.js: 2.4.12 to-buffer: 1.2.2 + pend@1.2.0: {} + + perfect-debounce@2.1.0: {} + pg-cloudflare@1.3.0: optional: true @@ -30419,6 +32369,44 @@ snapshots: pify@4.0.1: {} + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + + pino-abstract-transport@3.0.0: + dependencies: + split2: 4.2.0 + + pino-std-serializers@7.1.0: {} + + pino@10.3.1: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 3.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 4.2.0 + + pino@9.7.0: + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.5.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 3.2.0 + pirates@4.0.7: {} pkce-challenge@5.0.1: {} @@ -30431,6 +32419,18 @@ snapshots: dependencies: find-up: 6.3.0 + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-types@2.3.1: + dependencies: + confbox: 0.2.4 + exsolve: 1.0.8 + pathe: 2.0.3 + playwright-core@1.58.2: {} playwright-core@1.60.0: {} @@ -30548,6 +32548,8 @@ snapshots: dependencies: '@posthog/core': 1.4.0 + powershell-utils@0.1.0: {} + preact-render-to-string@5.2.6(preact@10.28.4): dependencies: preact: 10.28.4 @@ -30575,6 +32577,8 @@ snapshots: transitivePeerDependencies: - supports-color + prelude-ls@1.2.1: {} + pretty-error@4.0.0: dependencies: lodash: 4.18.1 @@ -30608,6 +32612,8 @@ snapshots: dependencies: fromentries: 1.3.2 + process-warning@5.0.0: {} + process@0.11.10: {} progress@2.0.3: {} @@ -30619,6 +32625,10 @@ snapshots: err-code: 2.0.3 retry: 0.12.0 + promise-toolbox@0.21.0: + dependencies: + make-error: 1.3.6 + promise@8.3.0: dependencies: asap: 2.0.6 @@ -30642,6 +32652,8 @@ snapshots: property-information@7.1.0: {} + proto-list@1.2.4: {} + protobufjs@8.0.3: dependencies: '@types/node': 24.12.4 @@ -30665,6 +32677,18 @@ snapshots: randombytes: 2.1.0 safe-buffer: 5.2.1 + publish-browser-extension@4.0.5: + dependencies: + cac: 6.7.14 + consola: 3.4.2 + dotenv: 17.3.1 + form-data-encoder: 4.1.0 + formdata-node: 6.0.3 + jsonwebtoken: 9.0.3 + listr2: 10.2.1 + ofetch: 1.5.1 + zod: 4.4.3 + pump@3.0.4: dependencies: end-of-stream: 1.4.5 @@ -30674,6 +32698,10 @@ snapshots: punycode@2.3.1: {} + pupa@3.3.0: + dependencies: + escape-goat: 4.0.0 + pure-rand@6.1.0: {} pure-rand@7.0.1: {} @@ -30690,6 +32718,8 @@ snapshots: dependencies: side-channel: 1.1.0 + quansync@0.2.11: {} + query-selector-shadow-dom@1.0.1: {} query-string@7.1.3: @@ -30707,6 +32737,8 @@ snapshots: dependencies: inherits: 2.0.4 + quick-format-unescaped@4.0.4: {} + quickjs-wasi@3.0.0: {} quote-unquote@1.0.0: {} @@ -30738,6 +32770,11 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + rc9@3.0.1: + dependencies: + defu: 6.1.7 + destr: 2.0.5 + rc@1.2.8: dependencies: deep-extend: 0.6.0 @@ -30781,11 +32818,6 @@ snapshots: transitivePeerDependencies: - supports-color - react-dom@19.2.4(react@19.2.6): - dependencies: - react: 19.2.6 - scheduler: 0.27.0 - react-dom@19.2.6(react@19.2.0): dependencies: react: 19.2.0 @@ -31097,6 +33129,10 @@ snapshots: readdirp@5.0.0: {} + real-require@0.2.0: {} + + real-require@1.0.0: {} + recast@0.23.11: dependencies: ast-types: 0.16.1 @@ -31209,6 +33245,14 @@ snapshots: unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 + registry-auth-token@5.1.1: + dependencies: + '@pnpm/npm-conf': 3.0.3 + + registry-url@6.0.1: + dependencies: + rc: 1.2.8 + regjsgen@0.8.0: {} regjsparser@0.13.0: @@ -31352,6 +33396,11 @@ snapshots: onetime: 5.1.2 signal-exit: 3.0.7 + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + ret@0.2.2: {} retry@0.12.0: {} @@ -31360,6 +33409,8 @@ snapshots: reusify@1.1.0: {} + rfdc@1.4.1: {} + rimraf@3.0.2: dependencies: glob: 13.0.6 @@ -31478,6 +33529,8 @@ snapshots: transitivePeerDependencies: - supports-color + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -31506,6 +33559,8 @@ snapshots: dependencies: regexp-tree: 0.1.27 + safe-stable-stringify@2.5.0: {} + safer-buffer@2.1.2: {} sass-loader@16.0.7(webpack@5.105.4(esbuild@0.27.4)): @@ -31517,7 +33572,7 @@ snapshots: sass-lookup@6.1.0: dependencies: commander: 12.1.0 - enhanced-resolve: 5.20.0 + enhanced-resolve: 5.20.1 sax@1.6.0: {} @@ -31542,6 +33597,8 @@ snapshots: refa: 0.12.1 regexp-ast-analysis: 0.7.1 + scule@1.3.0: {} + seedrandom@3.0.5: {} semver@6.3.1: {} @@ -31552,6 +33609,8 @@ snapshots: semver@7.7.4: {} + semver@7.8.2: {} + send@0.19.2: dependencies: debug: 2.6.9 @@ -31619,6 +33678,11 @@ snapshots: gopd: 1.2.0 has-property-descriptors: 1.0.2 + set-value@4.1.0: + dependencies: + is-plain-object: 2.0.4 + is-primitive: 3.0.1 + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} @@ -31672,6 +33736,8 @@ snapshots: shell-quote@1.8.4: {} + shellwords@0.1.1: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -31746,6 +33812,11 @@ snapshots: slash@5.1.0: {} + slice-ansi@7.1.2: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + slice-ansi@8.0.0: dependencies: ansi-styles: 6.2.3 @@ -31755,6 +33826,10 @@ snapshots: smol-toml@1.6.0: {} + sonic-boom@4.2.1: + dependencies: + atomic-sleep: 1.0.0 + sonner-native@0.23.1(87a488248bd28430641b1320077ef29b): dependencies: react: 19.2.0 @@ -31790,6 +33865,11 @@ snapshots: space-separated-tokens@2.0.2: {} + spawn-sync@1.0.15: + dependencies: + concat-stream: 1.6.2 + os-shim: 0.1.3 + spawn-wrap@2.0.0: dependencies: foreground-child: 2.0.0 @@ -31812,6 +33892,10 @@ snapshots: split2@4.2.0: {} + split@1.0.1: + dependencies: + through: 2.3.8 + sprintf-js@1.0.3: {} sqlite-vec-darwin-arm64@0.1.9: @@ -31981,10 +34065,21 @@ snapshots: dependencies: ansi-regex: 6.2.2 + strip-bom-buf@2.0.0: + dependencies: + is-utf8: 0.2.1 + + strip-bom-stream@4.0.0: + dependencies: + first-chunk-stream: 3.0.0 + strip-bom-buf: 2.0.0 + strip-bom@3.0.0: {} strip-bom@4.0.0: {} + strip-bom@5.0.0: {} + strip-final-newline@2.0.0: {} strip-indent@3.0.0: @@ -31997,8 +34092,14 @@ snapshots: strip-json-comments@3.1.1: {} + strip-json-comments@5.0.2: {} + strip-json-comments@5.0.3: {} + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + stripe@19.3.1(@types/node@24.12.4): dependencies: qs: 6.15.0 @@ -32019,6 +34120,12 @@ snapshots: structured-headers@0.4.1: {} + stubborn-fs@2.0.0: + dependencies: + stubborn-utils: 1.0.2 + + stubborn-utils@1.0.2: {} + style-loader@3.3.4(webpack@5.105.4(@swc/core@1.15.18)(esbuild@0.27.4)): dependencies: webpack: 5.105.4(@swc/core@1.15.18)(esbuild@0.27.4) @@ -32103,8 +34210,12 @@ snapshots: tailwindcss@4.2.4: {} + tailwindcss@4.3.1: {} + tapable@2.3.0: {} + tapable@2.3.3: {} + tar-stream@3.1.8: dependencies: b4a: 1.8.0 @@ -32207,8 +34318,18 @@ snapshots: third-party-capital@1.0.20: {} + thread-stream@3.2.0: + dependencies: + real-require: 0.2.0 + + thread-stream@4.2.0: + dependencies: + real-require: 1.0.0 + throat@5.0.0: {} + through@2.3.8: {} + timers-browserify@2.0.12: dependencies: setimmediate: 1.0.5 @@ -32219,6 +34340,8 @@ snapshots: tinyexec@1.0.4: {} + tinyexec@1.2.4: {} + tinyglobby@0.2.16: dependencies: fdir: 6.5.0(picomatch@4.0.4) @@ -32238,6 +34361,10 @@ snapshots: dependencies: tldts-core: 7.0.30 + tmp@0.2.5: {} + + tmp@0.2.7: {} + tmpl@1.0.5: {} to-buffer@1.2.2: @@ -32289,9 +34416,9 @@ snapshots: dependencies: typescript: 5.9.3 - ts-api-utils@2.5.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: 5.9.3 + typescript: 6.0.3 ts-dedent@2.2.0: {} @@ -32302,12 +34429,12 @@ snapshots: '@ts-graphviz/common': 2.1.5 '@ts-graphviz/core': 2.0.7 - ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.4)(jest-util@30.3.0)(jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)))(typescript@5.9.3): + ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(esbuild@0.27.4)(jest-util@30.3.0)(jest@30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4)) + jest: 30.3.0(@types/node@24.12.4)(esbuild-register@3.6.0(esbuild@0.27.4))(node-notifier@10.0.1) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -32323,12 +34450,12 @@ snapshots: esbuild: 0.27.4 jest-util: 30.3.0 - ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@29.7.0(@types/node@24.12.4))(typescript@5.9.3): + ts-jest@29.4.9(@babel/core@7.29.0)(@jest/transform@30.3.0)(@jest/types@30.3.0)(babel-jest@30.3.0(@babel/core@7.29.0))(jest-util@30.3.0)(jest@29.7.0(@types/node@24.12.4)(node-notifier@10.0.1))(typescript@5.9.3): dependencies: bs-logger: 0.2.6 fast-json-stable-stringify: 2.1.0 handlebars: 4.7.9 - jest: 29.7.0(@types/node@24.12.4) + jest: 29.7.0(@types/node@24.12.4)(node-notifier@10.0.1) json5: 2.2.3 lodash.memoize: 4.1.2 make-error: 1.3.6 @@ -32373,6 +34500,10 @@ snapshots: tw-animate-css@1.4.0: {} + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + type-detect@4.0.8: {} type-fest@0.21.3: {} @@ -32383,6 +34514,8 @@ snapshots: type-fest@2.19.0: {} + type-fest@3.13.1: {} + type-fest@4.41.0: {} type-fest@5.5.0: @@ -32409,12 +34542,16 @@ snapshots: dependencies: is-typedarray: 1.0.0 + typedarray@0.0.6: {} + typescript@5.9.3: {} typescript@6.0.3: {} uc.micro@2.1.0: {} + ufo@1.6.4: {} + uglify-js@3.19.3: optional: true @@ -32473,6 +34610,25 @@ snapshots: trough: 2.2.0 vfile: 6.0.3 + unimport@6.3.0(oxc-parser@0.120.0): + dependencies: + acorn: 8.16.0 + escape-string-regexp: 5.0.0 + estree-walker: 3.0.3 + local-pkg: 1.2.1 + magic-string: 0.30.21 + mlly: 1.8.2 + pathe: 2.0.3 + picomatch: 4.0.4 + pkg-types: 2.3.1 + scule: 1.3.0 + strip-literal: 3.1.0 + tinyglobby: 0.2.16 + unplugin: 3.0.0 + unplugin-utils: 0.3.1 + optionalDependencies: + oxc-parser: 0.120.0 + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 @@ -32508,11 +34664,22 @@ snapshots: unpipe@1.0.0: {} + unplugin-utils@0.3.1: + dependencies: + pathe: 2.0.3 + picomatch: 4.0.4 + unplugin@1.16.1: dependencies: acorn: 8.16.0 webpack-virtual-modules: 0.6.2 + unplugin@3.0.0: + dependencies: + '@jridgewell/remapping': 2.3.5 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + unrs-resolver@1.11.1: dependencies: napi-postinstall: 0.3.4 @@ -32537,12 +34704,27 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + upath@3.0.7: {} + update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: browserslist: 4.28.1 escalade: 3.2.0 picocolors: 1.1.1 + update-notifier@7.3.1: + dependencies: + boxen: 8.0.1 + chalk: 5.6.2 + configstore: 7.1.0 + is-in-ci: 1.0.0 + is-installed-globally: 1.0.0 + is-npm: 6.1.0 + latest-version: 9.0.0 + pupa: 3.3.0 + semver: 7.7.4 + xdg-basedir: 5.1.0 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -32686,6 +34868,27 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 + vite-node@6.0.0(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + dependencies: + cac: 7.0.0 + es-module-lexer: 2.0.0 + obug: 2.1.1 + pathe: 2.0.3 + vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + transitivePeerDependencies: + - '@types/node' + - '@vitejs/devtools' + - esbuild + - jiti + - less + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + vite@8.0.10(@types/node@22.19.19)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): dependencies: lightningcss: 1.30.1 @@ -32892,6 +35095,11 @@ snapshots: warn-once@0.1.1: {} + watchpack@2.4.4: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 @@ -32903,6 +35111,65 @@ snapshots: dependencies: defaults: 1.0.4 + web-ext-run@0.2.4: + dependencies: + '@babel/runtime': 7.28.2 + '@devicefarmer/adbkit': 3.3.8 + chrome-launcher: 1.2.0 + debounce: 1.2.1 + es6-error: 4.1.1 + firefox-profile: 4.7.0 + fx-runner: 1.4.0 + multimatch: 6.0.0 + node-notifier: 10.0.1 + parse-json: 7.1.1 + pino: 9.7.0 + promise-toolbox: 0.21.0 + set-value: 4.1.0 + source-map-support: 0.5.21 + strip-bom: 5.0.0 + strip-json-comments: 5.0.2 + tmp: 0.2.5 + update-notifier: 7.3.1 + watchpack: 2.4.4 + zip-dir: 2.0.0 + transitivePeerDependencies: + - supports-color + + web-ext@10.4.0(express@5.2.1)(jiti@2.7.0): + dependencies: + '@babel/runtime': 7.29.7 + '@devicefarmer/adbkit': 3.3.8 + addons-linter: 10.7.0(express@5.2.1)(jiti@2.7.0) + camelcase: 8.0.0 + chrome-launcher: 1.2.0 + debounce: 1.2.1 + decamelize: 6.0.1 + es6-error: 4.1.1 + firefox-profile: 4.7.0 + fx-runner: 1.5.0 + https-proxy-agent: 7.0.6 + jose: 5.9.6 + jszip: 3.10.1 + multimatch: 6.0.0 + open: 11.0.0 + parse-json: 8.3.0 + pino: 10.3.1 + promise-toolbox: 0.21.0 + source-map-support: 0.5.21 + strip-bom: 5.0.0 + strip-json-comments: 5.0.3 + tmp: 0.2.7 + update-notifier: 7.3.1 + watchpack: 2.5.1 + yargs: 17.7.2 + zip-dir: 2.0.0 + transitivePeerDependencies: + - express + - jiti + - safe-compare + - supports-color + web-push@3.6.7: dependencies: asn1.js: 5.4.1 @@ -33068,8 +35335,14 @@ snapshots: - esbuild - uglify-js + whatwg-encoding@3.1.1: + dependencies: + iconv-lite: 0.6.3 + whatwg-fetch@3.6.20: {} + whatwg-mimetype@4.0.0: {} + whatwg-url-minimum@0.1.2: {} whatwg-url@14.2.0: @@ -33082,6 +35355,10 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 + when-exit@2.1.5: {} + + when@3.7.7: {} + which-module@2.0.1: {} which-typed-array@1.1.20: @@ -33094,6 +35371,11 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 + which@1.2.4: + dependencies: + is-absolute: 0.1.7 + isexe: 1.1.2 + which@1.3.1: dependencies: isexe: 2.0.0 @@ -33102,15 +35384,27 @@ snapshots: dependencies: isexe: 2.0.0 + which@4.0.0: + dependencies: + isexe: 3.1.5 + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 + widest-line@5.0.0: + dependencies: + string-width: 7.2.0 + widest-line@6.0.0: dependencies: string-width: 8.2.0 + winreg@0.0.12: {} + + word-wrap@1.2.5: {} + wordwrap@1.0.0: {} workerd@1.20260603.1: @@ -33144,6 +35438,12 @@ snapshots: - bufferutil - utf-8-validate + wrap-ansi@10.0.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 8.2.0 + strip-ansi: 7.2.0 + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -33201,16 +35501,92 @@ snapshots: bufferutil: 4.1.0 utf-8-validate: 6.0.6 + wsl-utils@0.3.1: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 + + wxt@0.20.26(@types/node@24.12.4)(eslint@9.39.4(jiti@2.7.0))(jiti@2.7.0)(oxc-parser@0.120.0)(rollup@4.59.1)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4): + dependencies: + '@1natsu/wait-element': 4.2.0 + '@aklinker1/rollup-plugin-visualizer': 5.12.0(rollup@4.59.1) + '@webext-core/fake-browser': 1.5.2 + '@webext-core/isolated-element': 1.1.5 + '@webext-core/match-patterns': 1.0.3 + '@wxt-dev/browser': 0.1.43 + '@wxt-dev/storage': 1.2.8 + async-mutex: 0.5.0 + c12: 3.3.4(magicast@0.5.2) + cac: 7.0.0 + chokidar: 5.0.0 + ci-info: 4.4.0 + consola: 3.4.2 + defu: 6.1.7 + dotenv-expand: 12.0.3 + esbuild: 0.27.4 + filesize: 11.0.17 + get-port-please: 3.2.0 + giget: 3.3.0 + hookable: 6.1.1 + import-meta-resolve: 4.2.0 + is-wsl: 3.1.1 + json5: 2.2.3 + jszip: 3.10.1 + linkedom: 0.18.12 + magicast: 0.5.2 + nano-spawn: 2.1.0 + nanospinner: 1.2.2 + normalize-path: 3.0.0 + nypm: 0.6.7 + ohash: 2.0.11 + open: 11.0.0 + perfect-debounce: 2.1.0 + picomatch: 4.0.4 + prompts: 2.4.2 + publish-browser-extension: 4.0.5 + scule: 1.3.0 + tinyglobby: 0.2.16 + unimport: 6.3.0(oxc-parser@0.120.0) + vite: 8.0.10(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + vite-node: 6.0.0(@types/node@24.12.4)(esbuild@0.27.4)(jiti@2.7.0)(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.4) + web-ext-run: 0.2.4 + optionalDependencies: + eslint: 9.39.4(jiti@2.7.0) + transitivePeerDependencies: + - '@types/node' + - '@vitejs/devtools' + - canvas + - jiti + - less + - oxc-parser + - rolldown + - rollup + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + xcode@3.0.1: dependencies: simple-plist: 1.3.1 uuid: 7.0.3 + xdg-basedir@5.1.0: {} + xml2js@0.6.0: dependencies: sax: 1.6.0 xmlbuilder: 11.0.1 + xml2js@0.6.2: + dependencies: + sax: 1.6.0 + xmlbuilder: 11.0.1 + xml@1.0.1: {} xmlbuilder@11.0.1: {} @@ -33268,6 +35644,15 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yauzl@3.3.0: + dependencies: + buffer-crc32: 0.2.13 + pend: 1.2.0 + + yauzl@3.3.2: + dependencies: + pend: 1.2.0 + yocto-queue@0.1.0: {} yocto-queue@1.2.2: {} @@ -33287,6 +35672,11 @@ snapshots: cookie: 1.1.1 youch-core: 0.3.3 + zip-dir@2.0.0: + dependencies: + async: 3.2.6 + jszip: 3.10.1 + zip-stream@6.0.1: dependencies: archiver-utils: 5.0.2 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 0189b9f384..3718a9331d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -134,4 +134,5 @@ allowBuilds: koffi: false openclaw: false '@openrouter/sdk': false + spawn-sync: false tree-sitter-bash: false From c1a07cbaa3de80f4c34306f9817ebad68896f216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 15:01:14 +0200 Subject: [PATCH 02/51] chore(extension): update extension icon --- apps/extension/public/icon/128.png | Bin 3074 -> 18291 bytes apps/extension/public/icon/16.png | Bin 559 -> 1272 bytes apps/extension/public/icon/32.png | Bin 916 -> 535 bytes apps/extension/public/icon/48.png | Bin 1334 -> 3523 bytes apps/extension/public/icon/96.png | Bin 2366 -> 8780 bytes apps/extension/public/icon/icon.svg | 13 +++++++++++++ 6 files changed, 13 insertions(+) create mode 100644 apps/extension/public/icon/icon.svg diff --git a/apps/extension/public/icon/128.png b/apps/extension/public/icon/128.png index 9e35d130796978714468fa149241172744bf3992..40341f2bc246f635a6011e5c30ea16065a1b5f89 100644 GIT binary patch literal 18291 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

^u=CFN3&pQ}rr8f5Yk1apfP#{uCjfGn=amC= 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 Q9RL6T07*qoM6N<$g0^9zvj6}9 diff --git a/apps/extension/public/icon/16.png b/apps/extension/public/icon/16.png index cd09f8cfbc020b5a077c6c491e2be5f1cb75fb50..6d2f02ff761a12a0ebcd1e774921840854d82911 100644 GIT binary patch literal 1272 zcmeAS@N?(olHy`uVBq!ia0vp^0w65F1SAhIZYc#)3dtTpz6=aiY77hwEes65fI&pI$O^nA{^PBR+ z=|CaX64!{5l*E!$tK_0oAjM#0U}UCiV5Vzi6k=#(Wol_) z4mEy%kwaIa`>*Ls?x@;%xAoP{;EM}B1dBBMWG@uhvU1mHgQ!mhydDo-8oie3HDz9% zB5zS*(brVFaGA&%&Lra-7Me*9I?hk`4Jh1sWk*P_;^oaEQbz0j8t%J1DE)9>>Iu8< zEIsKD-+4qH*bAmKO?k7Wtl;LN{rrNF@5K+CRd=3fu+foY2A3$)rSxz5ny2UW6^R(k z-?N}~p>Ol;2Vn)%%|mKpX0erL{d>buyyhqG0T1I2$;771%O3yT@V%}`&d1H?JHt1I z9h^(AR_lZn#O3p_IX6Fln_ixK=G1wG`~^D%t?s{!W;LDdSKjzd`)=|DRm<5Aoa%3T zNf@1xYyR@7R`eR%&3W<8e-{Muy*t<@noxZ}Psq+jvYsz)NBVE&JwiK!*fn2Y@;dM{ zSlrmd?^5=G_@1WARk@NfM$>j4e7^pfdh`_Cj<`qV0X7r1H?^+~x2t%uXOZH@qVsV( zY|D!6J+2z@c5HX$Kk@F=(+7d?bNMeZ&PwpJFP8{d#3D9hyOF?ACH|1zSECgzbe`~Z z2$(gzRoz|4!NqlxlcmeRgXhNL_8C7~Oan@nJz|!4FL|4D-&)2akW!JmS^$yD(b{AxKov~ruvouvfdSa%-vgxf&=bWcAzvTNpWrE?Hv|3a zKA)7y(ZzAHeQVwOti&(B+Yc73{n;h7BvRHdIv?8RU-RJ2-f3|sI?kQmxGY0-wWI0Eb1gFt?uaXR zSL)dy&3iptcW3r3+3APB%`Zzie0u9?(F=mtzL{IByZp>yP4ptJIgdn6FDU$XJ+Zs- zkEZK!SKc#EZ1UQ+B_=EXd2C|DcIkDHM#3?k;@#=H7j9i=Dd%R!m)fM`GmoiwcKY9i zPtSHU7Hr(VQf$^DsjLHEitoRPx#1ZP1_K>z@;j|==^1poj6#7RU!RCoc6Q%y1hQ4sEL#7~ulxq)o`RdE7w zgE)ZX*)Ue(1mOgcm9Uy{0J%YqV3c5)af4VWtGxF0Fls17FMsBBUUz@_`s;p>Z`K&P z@byKnRdgL9BcAPx)vHta#e(k_EN+QtB~a;#B7vY4-MPwd0I*M%0Ii$vMXQ0J*IDiE zx*HeHO#2~|QUWDPMwmjovlOSF45Is5Q{nqwq^gh#fRPv6S}@*-M+8d*2rWit4ITS_ z^ytbtKuJ{`sekq^*1Fq2Q6!VC+_yqM_BS&24U;R^pbXJl`G*;GfNcmCK3lMl0-Hrz zlZ@@G=fbi@q^3H18y-Bk>ZD>QQnp<--S!4Mjcf|0_UyFw>5k3|J^y9Vpx(D#$yzYA zMJ45!LiwjLH{}tQqPyBLHCW_Tm2}#Z3g2l5mhUKLTz{e@} kanp*yqZ{*;IL-my0H@*7-mfAUfdBvi07*qoM6N<$g5$CJmH+?% diff --git a/apps/extension/public/icon/32.png b/apps/extension/public/icon/32.png index f51ce1b5c93db65ffd15c7440f98c9ff06e2d498..8845cadfab85d4660442c92ae510c49290937e06 100644 GIT binary patch literal 535 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq@N1SHpV7(M`Tl0AZa85pY67#JE_7#My5g&JNk zFq9fFFuY1&V6d9Oz#v{QXIG#NP=YPV+ua371Hn({-St3~8)H|2-Z zfkLV!t`Q|Ei6yC4$wjF^iowXh$V}J3OxMUL#L&pf)Y8htP}{)3%D~_eV~8D!hTQy= z%(P0}8YaiQX##4{fZI@#nVVW%l9*e7Th9^Cv#~%u-#uL%Ln00*CrGd^PDo*PixJAd z|L?#3g}%cqhYs~*=%q~oG delta 906 zcmV;519kkD1e6Dm7=H)`0001UdV2H#000SaNLh0L01FcU01FcV0GgZ_00001b5ch_ z0Itp)=>Px#1ZP1_K>z@;j|==^1poj8DM>^@RCoc!S4~nAK@@(kCs-;A;|;>nf>gl? z3@0G$B^efy=n79jasqH;4Y0_72MC@ZxdBm#E*WnS7nTbv{eOHtlbPxHNiqxxepRVT zcfam_)BWD}zDCH1!#lJ1=QkYzLKTQg1TaFtD>Sfey|Nw13Cv>jc4%%Q$sQXQ)5Zy* zb+&%lh8&pdK=X%LqOt7p-_p#5NNihWyASt-m}fv^KK5X9bks(t8ERmU(cy_w{V!^M6U)4jVW1E?-`C(i}Wn#qEX~Q9q>RVv)i?9v{+DOO!Au3^3Zbt z(FuMbihpd>RV5f63Q0dx)@KUFgzu&W$~4d_0OGBEGh1q?RcQa&5|F!(TVx g;?h2y@o4=A@LOl^19~-w00000NkvXXt^-0~f?80QJ^%m! diff --git a/apps/extension/public/icon/48.png b/apps/extension/public/icon/48.png index cb7a4494a5eb5d54abdf1903c6895d9fef60f55f..22722b22fd367c1b8a036d68f3f6f9bdce0919a7 100644 GIT binary patch literal 3523 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 delta 1327 zcmV+~1Px#1ZP1_K>z@;j|==^1poj9%Sl8*RCodHT0wT(HV~ZwwMo<{22)0j@ZAli#Ip&84}hAsEPnZ0vICTIil>g)=nMB5eRp{-n;rU zl5nIZozTq{LL5B**?A2)AhQ9D%laV^98KF_fMq|gbh0<75!N|t zS6;g9j_=BaTw}E;DX0ics46r6@nK}-+%qK_3>JspnwwjZ;Jx8YkUt0 z;8k!b;6|SD{1GDEy!%p;y*H@4XtA3`Rx}Q`E~IEtO7Yj^VM_$Zj=Xw0*xi|?vuD6K zFsJAAML@#H`Qy^Aru8d~*+L$gZnAsy`H!3U1jILxI1za!K)8?$c3G-L8-3b+lr#`y zXp#L8r+@atc_1t83Lv5R+M*|~kd=0YWCa;)P`l}(CqIGzr9)DKcld`%V}zz8iT;Bn z0wr98u7Q%2ZZ<8nO892LvY{Ek`e*aW;PJkqHCPQ4_XayBjkk8qbQ4*7Q2bcd_ZA*6 zbU*l~?vQ{u8KLQ<6c-|!cj?{=t%jzPrilSHsDGzqHmnGgPMWw>!Ph&1n@}}yZ|UZm zlwLZ3yn({y_xC54U@7EOHsmS9Ox%wtj5-FXeF zv3~|Q8xH5LngKt+62UHW5oszWvJhu!E5kerg!mxRG>kPsB|1^1%GuQgED7ViD4Mn5 zxzPX>^^#Dlq6y2&r9hhoKkd~D4qTq;78-+{P&!FoekyB*^2tIH9kueDB|Z$!M~-Aw zuYjY=+i<_YfnldVmOHa1f<<7&=L~{ET7Ss2S@GBRG+H6$abD4ugJ=8YlG02Qm|TwA z6~|HkC$f-|8N$Mimvb(OXN6Y*m$dtWH`+;?VFkFPLUhKqy`Eb#@%5?_^Dhe*yimOoLs!9bboBGb<2EWgNA%UMah2B zDtIxaxg`A$37Gwi3`wgP2t=OzX@4`=rkIRbNlQWFk|JO4^rG#EB2j-C$|~4rDvhoA zGr1@OO2Pi^N;kHK|71{qA96S36HTf1nb0gBaFKb-q<8q)Wk`U5Mv3!JsKJ!Llmig| z{?`gPQPn>@48Ai~??4K2FD)WqrXqmSJFT^`-buopHnKdR2ti1B(Eeq*Unse(gaO{9 l)xieG-o5X!8Pz*U_yT_&D{uF$1FQf5002ovPDHLkV1g|KZ?*sc diff --git a/apps/extension/public/icon/96.png b/apps/extension/public/icon/96.png index c28ad52d56fc409195f52f57c447442326d94b6b..2cf7916eb282b93ae30b3392063a19154d32390a 100644 GIT binary patch literal 8780 zcmZ{K1yoeu_wSh*x;sQ*KuSsJo{{eE97LoPkdz)2kq!ldFeY^!7NDZw|3AZfi>+6;3|#-M!PD`%orkB*bGQFL&llApO8{7S zR23c>yqw+6^hHrA&fXyAWRzd2!hgf#`&eFK(IhJ(b-!cpBWbHFrHyo^-y0f3ye3ce zjg73KmAJ*+zj_Inid&gp^0GGl72*mfsCs#i0FMpgo)iC7Bo=%5)|_rOXYE=(jX_2lmv=`cRFpSt3F1AMI-3rG((HJiS0+p(Rba=FX-87nC}hj z+ZVHjB`-9dkzs_!>nJb>{H{({wzlXO!eIU{H6T1S=9Z~tn-%QYmjZs{w3xH6zPRw0 zmTq{+J)e-wqd1AM#WCUWzx>E$f+OTehg2gj^3iZeZ|O3h7&xUplLy0YMf_-)=?)g% z5#fkH+!d)6AJD^U%Yq!r6}iFT8u{+di3y|Lq=hDG^IGDQvC$by)no&|?hhe|uG6D+ z0E@&O!s(-%T=xX67+E5?Fi%Qmby3YFBK$uN9g>kasi0zwTO-qZ|4RxC2jW zl@B{PK!D|;9Vr;m7&%R@r#!%i3wDG{*4|1O@%<@=gON>t2tvM5dCeJkwKqrL^oD7~ zJ+KU7&V|W%rsfjZxA5&670fj()(Dm8-Y`F#3Ho_1qcLKg#x;HAOiDah`X8jOv@=+z0gy{UuzOn z^q9X|3Ztgf!)#F7>}3}~?sXW+4?}pSO3DbEBt6Y~5Od;nR#C}cl)7y%+@dwTyvF-3 zFqAJiKX`X?&wV)*>!>JuN0~X0hf-TxWqFh4QyH$TX^TbCkFk?gi>e)`syBk#D?L76KKnUN zh`EUNAw&CC9{GR^*W6Bkg@bDZ!HQY%(QUY3wt}G;ogvY|cLE{hHdB)u*XGLoza;>6@Y)z7e7QY32^b2Mkw9lqK{qhu`m3S0 zN|QU{{s1jxRB?7~fB6P{H}~L#c}f*5+%7k6pS$Sb%qj%9(V3RIDdQfP_)`=Ubfa2k zNmQZMSZyZ2V@8ah4JtJ%6bVgj>~fOCoqTRg$4dKwq58zm{Lh?v$dr2lBi`FltfTIl zIKAwFXx0W?`UN6CCe#;#f~1X<_Yx5J)m~T}e3bX$)!Cme7F&q)h~F=;SGoTTcjj`x zM-0e{Z{Bp`?>UYQh~+z-xPDFm$EejtKyUrDjX-C{f1ww=jgieGf>%feilcX*%##55 zuzgm`toh={XPq$>R%;#GTH{XEAmO=UeLS@h&g{3Cs9soN+f&HO}t0K^|Ulvw)<@WDcJyN2Uz$%xp%Ikb{hei3)`?!*FH26I)mKT7V;@M zu@k?#(9KH}^DU0HNO5w9GK3QHOn+NYu*m0{VxcH8+Xd2>k(!DIC+& zBTW*5Sw8T_u70|<{gT#lKkgZ>nYM7`Lka{$Aw5^ji}l9VyzzQZZheBC|F9kH%`M4sddCbY_A=rLK$E#x^< z#qAV1=UoHFV8EKUm9NzMLRas`ZE#7`7?jKGY#sokj-+-941GU62xNY6Nr*hD^E-z2 z?f-Fs?foqD>93WLwI;pvX1&860Bv%T4*50FTw4*abfiXGd_kv-y=h<=mzuvJLSP`Z z^YrfzC0e#(M34MRFo;%;IRQ;koRH|UXzq<0>tR>N*60--v}V4j6+!hSKRYetS^LMI z(3xZRvq=!W%!IBV|JDdjrOs~fP>0h;&&KSe$YUtxRmZHWrV5VF$i^E@KznmXo{2E$ zQB$(wTdtKfNU^(Qz`PtyF~2dnW-jyg4QT`qJ{Ww3oc`?)8G)3) zY)SEez<{UpB@{IsBhm`wWS=*uFY8kV2vsbr-Q(H1mbKfM(n#Hpi`H*DpQbuDo%4p-|5skj1ZVcs{`WMXFf98^UQ_IdY7`d#6V z6MgtMiM`V2)AG{#Te3vkQ-2U|-jh`43U?6hSbB*reK(+oey%^5#1kw_36Zpp59CL# z91b5qqH&{z(G!&=16Nm;yPjZ~a+v}h*xlbgrwyh@3+EiV)5*3CCVg$E*3MU52j^Sp z7V2sZ55Pc?%NY~ggeC(Q^PG26J16g$55182c?b+s58nsF&+Hk|LfsO0@R#y?5@<|8 z!_ubU0}j&P8p9Awnca~}-dJ`g2_)br=MP+z^jBgKI8Mk3@eFP-CP5BsTk^qFN{&kX zIM&WTjTeqxbD~Ky$ZlS|$ftJgn)soQJB zdR1??3JCUkXAz?+^eK_1G8iU`{GeX^?O^CcvuJs!#|_5<@y^Z8&Ucgg`+N9<~% z4^N~jp?%jT^uu3*;Qmy`QdCuaB}#d^f0iQSz^C0=BSJS!BW@eaO+|6B5#;{Km4bW) zjleCk(mwFLnX^cJCqDf17{$F(>m~)FZ5r{KRuv)txK92jaeEpEZKUy;sjb*KKh&{* z0C%kcMk3VJ>;W-a=vNj|d{*Wdea_9yBN(JMYk&`1g?=@d0A6N%Yz(eO?leK*0;1Jq z8$`a3N2*u+T+nn%T8g80A{cEhjDK9?>3BVzoCYFqCp4gLzdRFb7uW-X+$n#m6}vOO zq=b&J?fw9k{;Spm0+(s`TwrV2h-xup&mTq~;6^|Ve%W;VfV5boozNktX%AenRNBk` zd4g`U_GTb)OY!>chqmf&?|qbsZBFF7QXS?rN29E@Ju{@xteo=cI|C*opOu=ZmkTGS z=&9{Ysdl;6Z}V`bZC7YO)z4r`?7B_~COEI5saC6OMldIGK8mmi=6UqHlQ3S8rQr^S zVb6+mq3SRjYhmbk4i`0*(g>bto(x0#P8EBrz&Vq}DfUFOOVh?ovy;%By1o()r8eD;_AhD#8=RFe}@8VFJSFE z7?tUqo(GbKJ}r2dBAC0}?mh$^SSNWLHo>jx-|HcbUR7j|Y?4)9YI&$gUCE+NDz3X3 z>8&n$wqsTF#;jZ=OfllOJIt)!I(WHHe1EBtT~E8USE}ytMr>2B&~DYFqe1evt|lZ8 z5O5>H^u%sj!%Uv?UO{sXY0Y`iwF}8_z;Wua7$_n2Uc+0EXqRV4A4HcbpFMt+%ZYQ~ zb@teK-sWDojqa|5!r?pqc!n;n1PjR=#d?#lLZqA4WGA95E^eY=)GWdy6Ypt1{-`MV zrSl#h`tN?hIJnJ)Nzi8!8_EoDx1enW^x-7^3G}Xj%yU^}<2b=Ew#rqFJU03$CJ9Q` zHcO91b_(AUM+&gJu}}Dxw6KoyG*GlwGMGuRg-O@ghnpGKn=8;uafd%KNu067w@Fmt zi>!Cta$uyNwp8AbsasW%u`){V>nUkjELuLeo}I@cbCR|xHy`SKSbKS%TkpZ?qG6v zJp5b_w?a%zZ)BpLw~uzgeCgG(805}83ahkdBBaE2GrRL(Hj^KDNvt}VZ4^kN^P}n$ z1ty4J7&qrr>9GZRL+Al5NbJ-V#XhDWrx})!%3#@bn5z<03+ZEh>_Hs0ctV$tE>zyQ zDsQl|JKrFTAe_Cy3P(;hr3+cqc!x#RvGk|d6!%p-_TYi*;n$#tZCM&D+Y}f^m@1?o zaf0-T!(IsTC`C`a@2lgGnOwX5G9zzIt28|mx;5>-ovrJYy#=u|M|_GnW~R7r5Th(+&>IoLQ4C`&@VtMj z@Vux>o#U@Vw#p?IS$2F#OSAyeJTe^Smm#Y=fOW+AQr=Dc-+V-jN&T%+9?WwSXW06j zn0!7eI*v)#;1>~F5Oixe`KOM8gnASge>1CE)Iy|iiMhC`|Dwz436qI>m8p#mnpSsswBA_Jiw?w0oV`5Sf$YynUeB`Q@SmdjH)O1@|Pa(B3Y zrpmE6Nav@FcYRJODY~yKXEal8Uq_17*DBa4g+8I&HA7=!h^tP1C8u2XVRpS=2Dzdq z&KOBxeVe1(I_Q5$#NBC;RZG7<$e)G_*e6YGe&B|Ec)<|`(J=3(GoLqk1P(+!gwgw- zaxFLqGV}nan*F2vcxw<}5K3KSqAN8!x8*!}K^%i!9q28BTq_+l2eB1;A*c4G=$tKc zcOgJPBC|&acH0Ns=)Xm1d=>Ad;=Crz(TAx1&llNrw;z7EveR(gdbc6ZG1W{VDpBNG z8R*S#R@Vl#9wXk6BR*e^ad!{}%yY~$gIWR)ChR_y%|j@19<`WBCd>MD&F0eTMiz>> zw!Uyfk9y_Gp)rasui`Agsxqf}cJKq>!OAv^_ckc)t}ca}^eV@KPPD&||1NH|R^u(! ztkXCeLZrxpXnATxQ&C(I6-H?O2Q$W_tOyI!p)O*(hEDZfCgGK+W}}XOqLA=~tSgRR zc(E&a>s`-qWYZE8mRGuJLP_1ZeHC^eLn;CbzA1Txz1K0yg}|I*9Vtisr>~$*?<7Mw znw!70D44u<*J+n)o=zERXH?SFmdXqv%3Li}x&TRYZ54Dmp4}^rkbyFTuDCRP=K)Cc zpEgpIMJaFfQ0PHgAPw3>5(X|uPRl^;{764!O>`dnD+$9O%J(yi0;;8={JXzq~Ca|)ur))IIgHH@hf{$B# z0sF9j3CKP(4#d*&weH3RD|IUjEjRuJT15WVKKEN_R|Qw?(TD8xlLj5Y=@`hYAE;wsW(ZJpr56{9D&?UN_B9VTn@ zmXp=>_gn9aO5N>GviTvWHBaS9FujW09attUFZPMhf4%GmaP5@_>s3SA(6pGKepv>1 zU5*D1QgPrI8#ta6T+u9`qs9wi6IKb?#77iv<&*g0PDk&Gje}NMh6DriuZ{3{{SC&2 z1>fNdn%#e-G-*ps3YmE6?1JOwC(#KJ(AHl~trbbC&Ju9cYoC>v{3b;|A{bX|9zgC# zhw9ZdY=k|tv^=IkE?hi42_A89fyOEmR^hJ6*4SGgo!_h0@IS%|7rN&x_(+MHy-z?a z-4#L?Bp;z8_CgBHvaZIg_eMfFDJ>9J*+{M(x7u^Gx#0E25XELTSaI6q1$C`GQ zHt}hl(6Q=4V~q!@U<*%nU@B7guf#!cUobs-EZi>bn(Lh<%giiA4X!RrDm=e|;>qEj z7LEXCdK^T&JwpqKJouJU%9+Gt{j1$i6uCZTSOgNO4X?0s%3DgYat^mF^MP93(x$z~jLSMY@3>*X7i+L6O@1>h0{Q04#(-yVDvEaZlSnr$3`dx%$gCJe$_}8=B z+Ku}WPyOR!ivRQU%qI$}-Mk2Lx3OA{bfH76m-5CFoU*$t5)d=|r8GE=*+YYf4y%de z%HzTqtnSuuL5T8u(?UXq8jUJPJ?9}Mcc^gT7U3$1;urfm?7WMfjMGikVxbI>0tNkFG|8;bvl$@cYh3x)baCE8H&%a@@`K zQk=6_AS27^fLmaSo*MLQuF#UnelRVQH(?EZt2+AS=aVCoLTi}7FR?^xmsh5RCl~z4 zvS#~}4Ph$GP3VmdIIu2s_hxWB#Hz-5$v1gaBv15eiLyJ6iaUAzK5y$>A*%$WK5b~M zYMg=wU-LWXS33u2QMF6I4Otr5A#5fpao_rK9``p<8i)_{+R*~s-E{yHq>!*CS+~{e zNln_lBum*7S0887nGL*+EuBuxSsbY=)pEBeS8CmE#ca}QeKoVkp1=a7^L>)nED|7cqfre!y~`6cWP&7g@paJ)N4b593fTCJAujk zw)=DnJ+!*YMgjDvnZ|!@UK57>Cans#`bzn{p1l4BpX`3_>(gHrl?3Mg)&#tbga1lj z%DQVm(7{IW+8Y638acNnQfl>2%||DXZSvw|XIiy>*Mn@cnq zLO0^5eM1+4%$rOYs^~kdEY3F$2)SgcQeb$F9dX;&9#>7{n>S2HwDx7;k)87$vLOYe znx0i19X@(9bM;ZA8&Ug0yGSv8l*I_|16`iE;b&Jsk}-GS1uFGb-+T?4TGd(Q{$eXl z85N}9N7DNI)e$DHRa=+)-aaJ~rz4i=@#}94QnZpEfcW$*E^OxQj~i?h#GeGe|C!lT zu>+;#7lK6!`OA&-+_xZwyF3##cMj@rj4FGQU3`A3VVlb;gPX9AUAxpfS5%yoaGLW{ zb*ZH8&Yc_EkKi=OC}`2~-uNoi^YVF7I#6@{8KC%@fa%-f*atUn{n;qdT={Y`zK5Yz zUwvdSEczE^DGSlh?8q1#neel}HePh{CT)R{X7sntuwFwL6!Mk}bHj2x zRE-Fb+0N%Npt#A)9~a%A9q2)XT(3!I#+^wpZa=yEyK|Kke9Xf$$_-$lZp3!vgTSjHI18XE3FW z5%e(jT(*m%HsCFpmlUNO}>}z*?{2BxGKpLN{+g56|g8>C}obmzF#k8(;JT zhGM^pG|DYcmyo=_NQEMy=~unSHbV}+tgesGIt2CSB?nTfP|4G3vcPDE-j!hx!jo

^u=CFN3&pQ}rr8f5Yk1apfP#{uCjfGn=amC= zj&>UdDVc0l%Qa(Vv!>d4+xz?)djECB=_OpJUVC-k=^p-v2H9!bCeL3tgUopV-8c0Z z3~<2ULw*Zz1V?|d^>O!2J&p&+e%{T!{!(|oFuLJyYTyT^@2E6GwK}cUy_;ALd?xLi z(!L^3=xyQY{ZiaKnz5*sh&pjvsIEJSl(wB4s2aD_;ua}}(UerpOiR+1>lUhw981(w zombz8f@$<7MrZOb4*9+J9_cPaK-h0%$0&{zFo= z=7h8G)2hGi0rh;24s`v(H0sn&T2<;%feWSQ7Sq;<6UQr&HYBglae*7NTmm@C?6*l; z&3kL<;$d~64UksDO;UZPMJRq+N~&h2B@v_7u>x7^j zgYtt;2389BB`c|34zFZY5UMJ};TD)LMA^wIAuR2(^f$`b>*ZG#5RYk~%=% zrxT>Eg#FT2tWW9{=AEx)R19|l;{^^)&nCRlx330x}#6(KQ zx$A~-S0!6{vhov9Q#~wSyWGkLHX%+ zX(i>rYC%gxVDU40$R%Qd# z40PinKFN&}f1n#ToV&d?Nc!V)Prd1V0L9LT>@=mz(*Oe=+4oR@19}|%GuWyaV@k3Z zBLUySt6yYyJjZ1Q83@ceryUu(#cg?2QL1vXTL4vGV$O(AVbE?eWFb*A>5H%=%{4HE6!obO+(p&me;)#RaAp zq?~)Y$5&Io{FSmVq4{(Tnr#d44N4}7yGHLz#$n@7i;~F+eoRl})nAlk3dkUX9S&!)snu?!3hswJ)wB`Jv|saDBFsX&Us$iT=<*T78I$SB0n*vi1j z%FsyLz`)AD;Jn7U?ZXlR|0J4Z5)~F%@UU*oY-2ps^?RYv_r1&Q_0n{% z$=m#|{a3ly{`~L1^>5ZHaxiDC(~`On^Qinl@9dR*e6k72+CPqzb8e|C*_QvAwd0=9 zY~HLcDZ9{pi$c#_h`x52bLslJ2yP9&r+hUVw^+&A)OR+l_F}PVRC>@O&R9O1V@HkB zgHwWx=Su|(_`4g7gIL`D2{871viRlYtY$wPe2jO&SLsLpx2|VeP+Onq&i3V7>3(j{ zpV{&)R;Mp28ML;AG$!u5$n^EvW513KI!1?2@y8i7nVBtMkYEd_zS69~JBK0lP*Wkp z*=xbm6R-bybhJQkldiOu)Tv7gRNo)h*b(;8o2TZfRRN#b@-$Va^y@!m0-_iv{GVa= z(3EXK49A6oSNF^-JMl;JD5JA>J^O0KVZDazSGO?a|K74rL4zD$lRtWD;RwvCXXDODjM7lPyAZ|3T)xik<>rmL@&dj$JpMQN<%EkH-&yRrw0{+6R+tPIOZ`&*1_maz^A3y?-cI74q@~|DY2il4 zkH7AwRqVAem)N)c`j$icw!|*nu>0mb&V}~vnGZ`AJocVY{_mr!^-c%dhKpia#jm-{Lf3|a+!X-tV!kf;UngmY*{uA zhwhmQ7HHQmsF$v@t^TXj5iI0jZ>B6Y?_8HB%jsj{+zTs%9}DD2>fPaAtvu;J%NGWn z&+>cfTdR(;POavXXY2Q4ar@zopr0CW%M4*&oF delta 1171 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 diff --git a/apps/extension/public/icon/48.png b/apps/extension/public/icon/48.png index 22722b22fd367c1b8a036d68f3f6f9bdce0919a7..7b60547e109372549b8d4e0bdcc4ad04dd6c39c0 100644 GIT binary patch delta 3779 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

%MK<|4>cg`HSf&!|*4 z?)PITQ_RZ(3c5}e`fvZjSZ}!APVP?fv&@dqi;}bYxX2WB0npZYoCQP8Wf&1GXdYZ6 z0F%80^5|pfJTS;=wp4vf%3V3Q%WRzvt+qQ@IU2>P(0#SY(Kq_v6+D-QlN=X&n__1u&e_Hi!l1ut?6ld%kOS3d0lp;<;HMNZoK3f5HI6|uRU z>a5To`3Cggs3MNRTs+Ae&!r3|wtY&BlZj+Qsj%>$Y>yaOS$R#Y1Fte7OmN;!Fp&I} za7KmXuWS4}eo~UuzFe=B4vZ|5n`su_zhTZKt-kk*MR6#!>}vGi8kgr|&0{zf!6O?z zO1b-slj{MGj@xy5YvKQf%hDo!+l9MCe`MA5ZbeK!HE>OQRZPU~_H} zh3v-)-cMg_f3MHmuj^qo9T#GEm8lO=@cLQVr#&DZidqinn+8e=d5facPGf!JEVS_5 zESDQ>m1YSqCgeGcUTr+6To+46r2MZvnlamWo>1rPad!n+5v(J^=-0x?~BLOef5|zkKMck37%~& zFk&(C2=tWnYy(8_(Krq|ZNL%%^Yr6AU_~c) zXT=oqM=FpFAdbBkt|VRlB=~@ClM+qxUh*eo;fIbJ0=W|}&5T^D&@l$9K>2wddxQ2z zl}ZzqjAQvC=(}hxm&bVYdue?-|Cx%R%yr*sDaMVIiCc*A(ks;Ji=AosaZq|$dxGW` zk7cZ*pMC{I9`TgZh`Mk-dEW;;*4%pr8RimSbwrOzY=}3C+uHqooe(__{Ub2Xz}mz z=7r~pRvMp0laS_Bw}2Nb{(eBT zaeuUc=#uea=W@HPkLa^W*XN5=@^NdebJ1K&um_i?c`{Pfi)US#>w0(tAey>L%j1II zNqy{>Lh7n9PDjaRUF=l(Y#Pk482*Nw-|WjJVZ68P`IBOy=nS&}KY96xsaFco7`4Zp zVVgn)nYiq)T-STLmmyXU{DR!CmKhrjmH$jK9PlHZl~L?tvhiF~n={&IqgaeuULahz zeEK16NS@aRP1Xn;vMJ~GA}aUSPxVEVkhfb0mizL3>V=FbRM{w$omUa~!09n`FF6WH z;hU&HQGri?I&?R#hBoA#%423ZLB#)a2SU#c - - - - - - - - - - - + + + From 9ef105542ca80337698cbb4ef3f1e41914352245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 15:11:06 +0200 Subject: [PATCH 04/51] feat(extension): make sidebar toggle reliable --- apps/extension/entrypoints/content/index.tsx | 37 +++++++++++--- apps/extension/entrypoints/popup/app.tsx | 48 ++++++++++++++++--- .../src/shared/runtime-errors.test.ts | 20 ++++++++ apps/extension/src/shared/runtime-errors.ts | 4 ++ apps/extension/wxt.config.ts | 2 +- 5 files changed, 96 insertions(+), 15 deletions(-) create mode 100644 apps/extension/src/shared/runtime-errors.test.ts create mode 100644 apps/extension/src/shared/runtime-errors.ts diff --git a/apps/extension/entrypoints/content/index.tsx b/apps/extension/entrypoints/content/index.tsx index 70593911fb..141f9d8970 100644 --- a/apps/extension/entrypoints/content/index.tsx +++ b/apps/extension/entrypoints/content/index.tsx @@ -17,9 +17,22 @@ import { type SidebarSubscriber = (isOpen: boolean) => void; type RuntimeMessageListener = Parameters[0]; type SendResponse = Parameters[2]; +interface KiloContentScriptState { + isStarted?: boolean; +} const subscribers = new Set(); let isSidebarOpen = DEFAULT_SIDEBAR_PREFERENCES.isOpen; +const KILO_CONTENT_SCRIPT_STATE_KEY = '__kiloContentScriptState__'; + +const getContentScriptState = (): KiloContentScriptState => { + const scope = globalThis as typeof globalThis & { + [KILO_CONTENT_SCRIPT_STATE_KEY]?: KiloContentScriptState; + }; + + scope[KILO_CONTENT_SCRIPT_STATE_KEY] ??= {}; + return scope[KILO_CONTENT_SCRIPT_STATE_KEY]; +}; const notifySubscribers = (): void => { for (const subscriber of subscribers) { @@ -57,18 +70,15 @@ const KiloSidebar = (): React.JSX.Element | null => { } return ( -

+ ); }; @@ -100,6 +115,14 @@ const handleSidebarMessage = (message: unknown, sendResponse: SendResponse): boo export default defineContentScript({ cssInjectionMode: 'ui', async main(ctx): Promise { + const contentScriptState = getContentScriptState(); + + if (contentScriptState.isStarted === true) { + return; + } + + contentScriptState.isStarted = true; + const storedPreferences = normalizeSidebarPreferences( await storage.getItem(SIDEBAR_PREFERENCES_STORAGE_KEY) ); diff --git a/apps/extension/entrypoints/popup/app.tsx b/apps/extension/entrypoints/popup/app.tsx index 11bd06ef62..85ffacc67d 100644 --- a/apps/extension/entrypoints/popup/app.tsx +++ b/apps/extension/entrypoints/popup/app.tsx @@ -6,10 +6,12 @@ import { isSidebarStateMessage, } from '@/src/shared/messages'; import type { GetSidebarStateMessage, ToggleSidebarMessage } from '@/src/shared/messages'; +import { isMissingContentScriptConnectionError } from '@/src/shared/runtime-errors'; type PopupRequestMessage = GetSidebarStateMessage | ToggleSidebarMessage; const unavailableStatus = 'Sidebar is unavailable on this page.'; +const sidebarContentScriptPath = '/content-scripts/content.js'; const getSidebarStatus = (isOpen: boolean): string => { if (isOpen) { @@ -27,6 +29,21 @@ const getToggleLabel = (isOpen: boolean | undefined): string => { return 'Show sidebar'; }; +const getErrorMessage = (error: unknown): string => { + if (error instanceof Error) { + return error.message; + } + + return unavailableStatus; +}; + +const injectSidebarContentScript = async (tabId: number): Promise => { + await browser.scripting.executeScript({ + files: [sidebarContentScriptPath], + target: { tabId }, + }); +}; + export const App = (): React.JSX.Element => { const [isSidebarOpen, setIsSidebarOpen] = useState(); const [status, setStatus] = useState('Ready'); @@ -43,7 +60,24 @@ export const App = (): React.JSX.Element => { throw new TypeError('No active tab is available.'); } - const response: unknown = await browser.tabs.sendMessage(activeTab.id, message); + const tabId = activeTab.id; + const response: unknown = await (async (): Promise => { + try { + return await browser.tabs.sendMessage(tabId, message); + } catch (error) { + if (!isMissingContentScriptConnectionError(error)) { + throw error; + } + + try { + await injectSidebarContentScript(tabId); + } catch { + throw new Error(unavailableStatus); + } + + return browser.tabs.sendMessage(tabId, message); + } + })(); if (!isSidebarStateMessage(response)) { throw new TypeError('The tab returned an unexpected sidebar response.'); @@ -53,7 +87,9 @@ export const App = (): React.JSX.Element => { setStatus(getSidebarStatus(response.isOpen)); } catch (error) { setIsSidebarOpen(undefined); - setStatus(error instanceof Error ? error.message : unavailableStatus); + setStatus( + isMissingContentScriptConnectionError(error) ? unavailableStatus : getErrorMessage(error) + ); } }; @@ -64,11 +100,9 @@ export const App = (): React.JSX.Element => { return (
-

Kilo

+

Kilo

Hello world

-

- Toggle the floating sidebar on the current page. -

+

Toggle the sidebar on the current page.

@@ -77,7 +111,7 @@ export const App = (): React.JSX.Element => {
-
-

- This full-height sidebar is rendered by the Kilo extension. -

+
+
+
+

Current tab

+ + Connected + +
+
+ +
+
+

No actions yet

+

+ Tools for this tab will appear here. +

+
+
); diff --git a/apps/extension/entrypoints/popup/app.tsx b/apps/extension/entrypoints/popup/app.tsx index e8ce0bb90f..c7e3001caf 100644 --- a/apps/extension/entrypoints/popup/app.tsx +++ b/apps/extension/entrypoints/popup/app.tsx @@ -7,6 +7,7 @@ import { } from '@/src/shared/messages'; import type { GetSidebarStateMessage, ToggleSidebarMessage } from '@/src/shared/messages'; import { isMissingContentScriptConnectionError } from '@/src/shared/runtime-errors'; +import { KiloMark } from '@/src/shared/kilo-mark'; import { selectPopupTargetTabId } from '@/src/shared/tabs'; type PopupRequestMessage = GetSidebarStateMessage | ToggleSidebarMessage; @@ -155,28 +156,47 @@ export const App = (): React.JSX.Element => { void sendSidebarMessage(createGetSidebarStateMessage()); }, []); + const isConnected = isSidebarOpen !== undefined; + return ( -
-
-

Kilo

-

Hello world

-

Toggle the sidebar on the current page.

+
+
+
+ + + +
+

+ Kilo +

+

Sidebar

+
+
-
-

Sidebar

-

{status}

+
+
+
+

Current tab

+ +
+

+ {status} +

+
+ +
- -
); }; diff --git a/apps/extension/src/shared/kilo-mark.tsx b/apps/extension/src/shared/kilo-mark.tsx new file mode 100644 index 0000000000..32c0d2c577 --- /dev/null +++ b/apps/extension/src/shared/kilo-mark.tsx @@ -0,0 +1,22 @@ +import type { JSX } from 'react'; + +interface KiloMarkProps { + className?: string; +} + +export const KiloMark = ({ className }: KiloMarkProps): JSX.Element => ( + +); From 31ffdc139cd875b10bb354a37a67520c45ea422c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 15:49:13 +0200 Subject: [PATCH 07/51] feat(extension): use native side panel --- apps/extension/entrypoints/background.ts | 12 +- apps/extension/entrypoints/content/index.tsx | 178 --------------- apps/extension/entrypoints/content/style.css | 1 - apps/extension/entrypoints/popup/app.tsx | 202 ------------------ apps/extension/entrypoints/popup/index.html | 13 -- apps/extension/entrypoints/sidepanel/app.tsx | 38 ++++ .../entrypoints/sidepanel/index.html | 12 ++ .../entrypoints/{popup => sidepanel}/main.tsx | 2 +- .../{popup => sidepanel}/style.css | 3 +- apps/extension/scripts/debug-chrome.ts | 9 +- apps/extension/src/shared/messages.test.ts | 42 ---- apps/extension/src/shared/messages.ts | 53 ----- .../src/shared/runtime-errors.test.ts | 20 -- apps/extension/src/shared/runtime-errors.ts | 4 - apps/extension/src/shared/side-panel.test.ts | 21 ++ apps/extension/src/shared/side-panel.ts | 7 + apps/extension/src/shared/storage.test.ts | 33 --- apps/extension/src/shared/storage.ts | 24 --- apps/extension/src/shared/tabs.test.ts | 48 ----- apps/extension/src/shared/tabs.ts | 32 --- apps/extension/tests/e2e/sidebar.test.ts | 92 ++++++-- apps/extension/wxt.config.ts | 2 - 22 files changed, 173 insertions(+), 675 deletions(-) delete mode 100644 apps/extension/entrypoints/content/index.tsx delete mode 100644 apps/extension/entrypoints/content/style.css delete mode 100644 apps/extension/entrypoints/popup/app.tsx delete mode 100644 apps/extension/entrypoints/popup/index.html create mode 100644 apps/extension/entrypoints/sidepanel/app.tsx create mode 100644 apps/extension/entrypoints/sidepanel/index.html rename apps/extension/entrypoints/{popup => sidepanel}/main.tsx (82%) rename apps/extension/entrypoints/{popup => sidepanel}/style.css (67%) delete mode 100644 apps/extension/src/shared/messages.test.ts delete mode 100644 apps/extension/src/shared/messages.ts delete mode 100644 apps/extension/src/shared/runtime-errors.test.ts delete mode 100644 apps/extension/src/shared/runtime-errors.ts create mode 100644 apps/extension/src/shared/side-panel.test.ts create mode 100644 apps/extension/src/shared/side-panel.ts delete mode 100644 apps/extension/src/shared/storage.test.ts delete mode 100644 apps/extension/src/shared/storage.ts delete mode 100644 apps/extension/src/shared/tabs.test.ts delete mode 100644 apps/extension/src/shared/tabs.ts diff --git a/apps/extension/entrypoints/background.ts b/apps/extension/entrypoints/background.ts index a67f570adf..ec09e45626 100644 --- a/apps/extension/entrypoints/background.ts +++ b/apps/extension/entrypoints/background.ts @@ -1,3 +1,13 @@ +import { enableActionClickSidePanel } from '@/src/shared/side-panel'; + export default defineBackground(() => { - browser.runtime.onInstalled.addListener(() => {}); + const sidePanel = ( + globalThis as typeof globalThis & { + chrome?: { + sidePanel?: Parameters[0]; + }; + } + ).chrome?.sidePanel; + + void enableActionClickSidePanel(sidePanel); }); diff --git a/apps/extension/entrypoints/content/index.tsx b/apps/extension/entrypoints/content/index.tsx deleted file mode 100644 index 23359ca707..0000000000 --- a/apps/extension/entrypoints/content/index.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import './style.css'; -import { browser, createShadowRootUi, defineContentScript, storage } from '#imports'; -import React, { useEffect, useState } from 'react'; -import { createRoot } from 'react-dom/client'; -import type { Root } from 'react-dom/client'; -import { - createSidebarStateMessage, - isGetSidebarStateMessage, - isToggleSidebarMessage, -} from '@/src/shared/messages'; -import { KiloMark } from '@/src/shared/kilo-mark'; -import { - DEFAULT_SIDEBAR_PREFERENCES, - SIDEBAR_PREFERENCES_STORAGE_KEY, - normalizeSidebarPreferences, -} from '@/src/shared/storage'; - -type SidebarSubscriber = (isOpen: boolean) => void; -type RuntimeMessageListener = Parameters[0]; -type SendResponse = Parameters[2]; -interface KiloContentScriptState { - isStarted?: boolean; -} - -const subscribers = new Set(); -let isSidebarOpen = DEFAULT_SIDEBAR_PREFERENCES.isOpen; -const KILO_CONTENT_SCRIPT_STATE_KEY = '__kiloContentScriptState__'; - -const getContentScriptState = (): KiloContentScriptState => { - const scope = globalThis as typeof globalThis & { - [KILO_CONTENT_SCRIPT_STATE_KEY]?: KiloContentScriptState; - }; - - scope[KILO_CONTENT_SCRIPT_STATE_KEY] ??= {}; - return scope[KILO_CONTENT_SCRIPT_STATE_KEY]; -}; - -const notifySubscribers = (): void => { - for (const subscriber of subscribers) { - subscriber(isSidebarOpen); - } -}; - -const setSidebarOpen = async (nextIsOpen: boolean): Promise => { - isSidebarOpen = nextIsOpen; - notifySubscribers(); - await storage.setItem(SIDEBAR_PREFERENCES_STORAGE_KEY, { isOpen: nextIsOpen }); -}; - -const toggleSidebar = async (): Promise => { - await setSidebarOpen(!isSidebarOpen); - return isSidebarOpen; -}; - -const subscribeToSidebarState = (subscriber: SidebarSubscriber): (() => void) => { - subscribers.add(subscriber); - subscriber(isSidebarOpen); - - return (): void => { - subscribers.delete(subscriber); - }; -}; - -const KiloSidebar = (): React.JSX.Element | null => { - const [isOpen, setIsOpen] = useState(isSidebarOpen); - - useEffect(() => subscribeToSidebarState(setIsOpen), []); - - if (!isOpen) { - return null; - } - - return ( - - ); -}; - -const handleSidebarMessage = (message: unknown, sendResponse: SendResponse): boolean => { - if (isToggleSidebarMessage(message)) { - void (async (): Promise => { - const nextIsOpen = await toggleSidebar(); - sendResponse(createSidebarStateMessage(nextIsOpen)); - })(); - return true; - } - - if (isGetSidebarStateMessage(message)) { - sendResponse(createSidebarStateMessage(isSidebarOpen)); - } - - return false; -}; - -export default defineContentScript({ - cssInjectionMode: 'ui', - async main(ctx): Promise { - const contentScriptState = getContentScriptState(); - - if (contentScriptState.isStarted === true) { - return; - } - - contentScriptState.isStarted = true; - - const storedPreferences = normalizeSidebarPreferences( - await storage.getItem(SIDEBAR_PREFERENCES_STORAGE_KEY) - ); - isSidebarOpen = storedPreferences.isOpen; - - browser.runtime.onMessage.addListener((message, _sender, sendResponse) => - handleSidebarMessage(message, sendResponse) - ); - - const ui = await createShadowRootUi(ctx, { - anchor: 'body', - isolateEvents: true, - name: 'kilo-sidebar', - onMount: container => { - const root = createRoot(container); - root.render( - - - - ); - return root; - }, - onRemove: root => { - root?.unmount(); - }, - position: 'overlay', - zIndex: 2_147_483_647, - }); - - ui.mount(); - }, - matches: [''], -}); diff --git a/apps/extension/entrypoints/content/style.css b/apps/extension/entrypoints/content/style.css deleted file mode 100644 index d4b5078586..0000000000 --- a/apps/extension/entrypoints/content/style.css +++ /dev/null @@ -1 +0,0 @@ -@import 'tailwindcss'; diff --git a/apps/extension/entrypoints/popup/app.tsx b/apps/extension/entrypoints/popup/app.tsx deleted file mode 100644 index c7e3001caf..0000000000 --- a/apps/extension/entrypoints/popup/app.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { browser } from '#imports'; -import React, { useEffect, useState } from 'react'; -import { - createGetSidebarStateMessage, - createToggleSidebarMessage, - isSidebarStateMessage, -} from '@/src/shared/messages'; -import type { GetSidebarStateMessage, ToggleSidebarMessage } from '@/src/shared/messages'; -import { isMissingContentScriptConnectionError } from '@/src/shared/runtime-errors'; -import { KiloMark } from '@/src/shared/kilo-mark'; -import { selectPopupTargetTabId } from '@/src/shared/tabs'; - -type PopupRequestMessage = GetSidebarStateMessage | ToggleSidebarMessage; -interface ChromeScriptingApi { - executeScript(injection: { - files: string[]; - target: { - tabId: number; - }; - }): Promise; -} - -const unavailableStatus = 'Sidebar is unavailable on this page.'; -const sidebarContentScriptPath = 'content-scripts/content.js'; -const sidebarMessageRetryDelayMs = 50; -const sidebarMessageRetryLimit = 20; - -const getSidebarStatus = (isOpen: boolean): string => { - if (isOpen) { - return 'Sidebar visible'; - } - - return 'Sidebar hidden'; -}; - -const getToggleLabel = (isOpen: boolean | undefined): string => { - if (isOpen === true) { - return 'Hide sidebar'; - } - - return 'Show sidebar'; -}; - -const getErrorMessage = (error: unknown): string => { - if (error instanceof Error) { - return error.message; - } - - return unavailableStatus; -}; - -const injectSidebarContentScript = async (tabId: number): Promise => { - const chromeScripting = ( - globalThis as typeof globalThis & { chrome?: { scripting?: ChromeScriptingApi } } - ).chrome?.scripting; - - if (!chromeScripting) { - throw new Error('Chrome scripting API is unavailable.'); - } - - await chromeScripting.executeScript({ - files: [sidebarContentScriptPath], - target: { tabId }, - }); -}; - -const delay = (delayMs: number): Promise => - // eslint-disable-next-line promise/avoid-new -- Browser timers are callback based. - new Promise(resolve => { - setTimeout(resolve, delayMs); - }); - -const sendSidebarMessageToTab = async ( - tabId: number, - message: PopupRequestMessage, - retryLimit: number -): Promise => { - let lastMissingConnectionError = new Error('Sidebar content script is unavailable.'); - - for (let attempt = 0; attempt < retryLimit; attempt += 1) { - try { - // eslint-disable-next-line no-await-in-loop -- Each retry depends on the previous missing-receiver result. - const response: unknown = await browser.tabs.sendMessage(tabId, message); - return response; - } catch (error) { - if (!isMissingContentScriptConnectionError(error)) { - throw error; - } - - lastMissingConnectionError = error; - // eslint-disable-next-line no-await-in-loop -- Backoff is intentional between receiver checks. - await delay(sidebarMessageRetryDelayMs); - } - } - - throw lastMissingConnectionError; -}; - -const getTargetTabId = async (): Promise => { - const [activeTab] = await browser.tabs.query({ - active: true, - currentWindow: true, - }); - const tabs = await browser.tabs.query({ currentWindow: true }); - const extensionOrigin = new URL(browser.runtime.getURL('/')).origin; - const tabId = selectPopupTargetTabId(activeTab, tabs, extensionOrigin); - - if (typeof tabId !== 'number') { - throw new TypeError('No active tab is available.'); - } - - return tabId; -}; - -export const App = (): React.JSX.Element => { - const [isSidebarOpen, setIsSidebarOpen] = useState(); - const [status, setStatus] = useState('Ready'); - - const sendSidebarMessage = async (message: PopupRequestMessage): Promise => { - try { - setStatus('Connecting to this tab...'); - const tabId = await getTargetTabId(); - const response: unknown = await (async (): Promise => { - try { - return await sendSidebarMessageToTab(tabId, message, 1); - } catch (error) { - if (!isMissingContentScriptConnectionError(error)) { - throw error; - } - - try { - await injectSidebarContentScript(tabId); - } catch { - throw new Error(unavailableStatus); - } - - return sendSidebarMessageToTab(tabId, message, sidebarMessageRetryLimit); - } - })(); - - if (!isSidebarStateMessage(response)) { - throw new TypeError('The tab returned an unexpected sidebar response.'); - } - - setIsSidebarOpen(response.isOpen); - setStatus(getSidebarStatus(response.isOpen)); - } catch (error) { - setIsSidebarOpen(undefined); - setStatus( - isMissingContentScriptConnectionError(error) ? unavailableStatus : getErrorMessage(error) - ); - } - }; - - useEffect(() => { - void sendSidebarMessage(createGetSidebarStateMessage()); - }, []); - - const isConnected = isSidebarOpen !== undefined; - - return ( -
-
-
- - - -
-

- Kilo -

-

Sidebar

-
-
-
- -
-
-
-

Current tab

- -
-

- {status} -

-
- - -
-
- ); -}; diff --git a/apps/extension/entrypoints/popup/index.html b/apps/extension/entrypoints/popup/index.html deleted file mode 100644 index ed4cb94947..0000000000 --- a/apps/extension/entrypoints/popup/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - Default Popup Title - - - -
- - - diff --git a/apps/extension/entrypoints/sidepanel/app.tsx b/apps/extension/entrypoints/sidepanel/app.tsx new file mode 100644 index 0000000000..306280d803 --- /dev/null +++ b/apps/extension/entrypoints/sidepanel/app.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { KiloMark } from '@/src/shared/kilo-mark'; + +export const App = (): React.JSX.Element => ( +
+
+
+ + + +
+

Kilo

+

Native side panel

+
+
+
+ +
+
+
+

Current tab

+ + Connected + +
+
+ +
+
+

No actions yet

+

+ Tools for this tab will appear here. +

+
+
+
+
+); diff --git a/apps/extension/entrypoints/sidepanel/index.html b/apps/extension/entrypoints/sidepanel/index.html new file mode 100644 index 0000000000..10a373be0b --- /dev/null +++ b/apps/extension/entrypoints/sidepanel/index.html @@ -0,0 +1,12 @@ + + + + + + Kilo + + +
+ + + diff --git a/apps/extension/entrypoints/popup/main.tsx b/apps/extension/entrypoints/sidepanel/main.tsx similarity index 82% rename from apps/extension/entrypoints/popup/main.tsx rename to apps/extension/entrypoints/sidepanel/main.tsx index 80212b7de5..73b7ee90ab 100644 --- a/apps/extension/entrypoints/popup/main.tsx +++ b/apps/extension/entrypoints/sidepanel/main.tsx @@ -6,7 +6,7 @@ import { App } from './app'; const root = document.querySelector('#root'); if (!(root instanceof HTMLElement)) { - throw new Error('Popup root element was not found.'); + throw new Error('Side panel root element was not found.'); } createRoot(root).render( diff --git a/apps/extension/entrypoints/popup/style.css b/apps/extension/entrypoints/sidepanel/style.css similarity index 67% rename from apps/extension/entrypoints/popup/style.css rename to apps/extension/entrypoints/sidepanel/style.css index 29ec5dc737..b9a1b57b45 100644 --- a/apps/extension/entrypoints/popup/style.css +++ b/apps/extension/entrypoints/sidepanel/style.css @@ -3,10 +3,11 @@ html, body, #root { + min-height: 100%; min-width: 20rem; } body { + background: #09090b; margin: 0; - overflow: hidden; } diff --git a/apps/extension/scripts/debug-chrome.ts b/apps/extension/scripts/debug-chrome.ts index 447d342728..8a4ab27bc9 100644 --- a/apps/extension/scripts/debug-chrome.ts +++ b/apps/extension/scripts/debug-chrome.ts @@ -17,7 +17,7 @@ const startFixtureServer = async (): Promise<{ close: () => Promise; url:

Kilo extension debug fixture

-

This page exists so content scripts run in a normal HTTP tab.

+

This page exists so the extension can be tested next to a normal HTTP tab.

@@ -70,12 +70,13 @@ const extensionId = new URL(serviceWorker.url()).host; const fixturePage = await context.newPage(); await fixturePage.goto(fixture.url); -const popupPage = await context.newPage(); -await popupPage.goto(`chrome-extension://${extensionId}/popup.html`); +const sidePanelPage = await context.newPage(); +await sidePanelPage.goto(`chrome-extension://${extensionId}/sidepanel.html`); console.log(`Extension ID: ${extensionId}`); console.log(`Fixture page: ${fixture.url}`); -console.log(`Popup page: chrome-extension://${extensionId}/popup.html`); +console.log(`Side panel page: chrome-extension://${extensionId}/sidepanel.html`); +console.log("Click the extension toolbar icon to open Chrome's native side panel."); console.log('Press Ctrl+C to close the debug browser.'); const cleanup = async (): Promise => { diff --git a/apps/extension/src/shared/messages.test.ts b/apps/extension/src/shared/messages.test.ts deleted file mode 100644 index 748627927b..0000000000 --- a/apps/extension/src/shared/messages.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - createGetSidebarStateMessage, - createSidebarStateMessage, - createToggleSidebarMessage, - isGetSidebarStateMessage, - isSidebarStateMessage, - isToggleSidebarMessage, -} from './messages'; - -describe('sidebar messages', () => { - it('creates a toggle message with the stable extension protocol type', () => { - expect.assertions(1); - expect(createToggleSidebarMessage()).toStrictEqual({ - type: 'kilo.sidebar.toggle', - }); - }); - - it('creates a state request message with the stable extension protocol type', () => { - expect.assertions(1); - expect(createGetSidebarStateMessage()).toStrictEqual({ - type: 'kilo.sidebar.getState', - }); - }); - - it('creates a sidebar state response with an explicit boolean state', () => { - expect.assertions(1); - expect(createSidebarStateMessage(true)).toStrictEqual({ - isOpen: true, - type: 'kilo.sidebar.state', - }); - }); - - it('accepts only the known sidebar message shapes', () => { - expect.assertions(5); - expect(isToggleSidebarMessage({ type: 'kilo.sidebar.toggle' })).toBe(true); - expect(isGetSidebarStateMessage({ type: 'kilo.sidebar.getState' })).toBe(true); - expect(isSidebarStateMessage({ isOpen: false, type: 'kilo.sidebar.state' })).toBe(true); - expect(isSidebarStateMessage({ type: 'kilo.sidebar.state' })).toBe(false); - expect(isToggleSidebarMessage({ type: 'kilo.sidebar.unknown' })).toBe(false); - }); -}); diff --git a/apps/extension/src/shared/messages.ts b/apps/extension/src/shared/messages.ts deleted file mode 100644 index 5ddee29a4e..0000000000 --- a/apps/extension/src/shared/messages.ts +++ /dev/null @@ -1,53 +0,0 @@ -const GET_SIDEBAR_STATE_MESSAGE_TYPE = 'kilo.sidebar.getState'; -const SIDEBAR_STATE_MESSAGE_TYPE = 'kilo.sidebar.state'; -const TOGGLE_SIDEBAR_MESSAGE_TYPE = 'kilo.sidebar.toggle'; - -interface ToggleSidebarMessage { - readonly type: typeof TOGGLE_SIDEBAR_MESSAGE_TYPE; -} - -interface GetSidebarStateMessage { - readonly type: typeof GET_SIDEBAR_STATE_MESSAGE_TYPE; -} - -interface SidebarStateMessage { - readonly isOpen: boolean; - readonly type: typeof SIDEBAR_STATE_MESSAGE_TYPE; -} - -export type SidebarRequestMessage = GetSidebarStateMessage | ToggleSidebarMessage; - -export const createToggleSidebarMessage = (): ToggleSidebarMessage => ({ - type: TOGGLE_SIDEBAR_MESSAGE_TYPE, -}); - -export const createGetSidebarStateMessage = (): GetSidebarStateMessage => ({ - type: GET_SIDEBAR_STATE_MESSAGE_TYPE, -}); - -export const createSidebarStateMessage = (isOpen: boolean): SidebarStateMessage => ({ - isOpen, - type: SIDEBAR_STATE_MESSAGE_TYPE, -}); - -export const isToggleSidebarMessage = (value: unknown): value is ToggleSidebarMessage => - isObjectWithType(value, TOGGLE_SIDEBAR_MESSAGE_TYPE); - -export const isGetSidebarStateMessage = (value: unknown): value is GetSidebarStateMessage => - isObjectWithType(value, GET_SIDEBAR_STATE_MESSAGE_TYPE); - -export const isSidebarStateMessage = (value: unknown): value is SidebarStateMessage => - isRecord(value) && - value['type'] === SIDEBAR_STATE_MESSAGE_TYPE && - typeof value['isOpen'] === 'boolean'; - -const isRecord = (value: unknown): value is Record => - typeof value === 'object' && value !== null; - -const isObjectWithType = ( - value: unknown, - type: TType -): value is { readonly type: TType } => isRecord(value) && value['type'] === type; - -export type { GetSidebarStateMessage, SidebarStateMessage, ToggleSidebarMessage }; -export { GET_SIDEBAR_STATE_MESSAGE_TYPE, SIDEBAR_STATE_MESSAGE_TYPE, TOGGLE_SIDEBAR_MESSAGE_TYPE }; diff --git a/apps/extension/src/shared/runtime-errors.test.ts b/apps/extension/src/shared/runtime-errors.test.ts deleted file mode 100644 index 77aa81cc7d..0000000000 --- a/apps/extension/src/shared/runtime-errors.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { isMissingContentScriptConnectionError } from './runtime-errors'; - -describe('runtime errors', () => { - it('recognizes browser errors raised when a tab has no content script receiver', () => { - expect.assertions(3); - - expect( - isMissingContentScriptConnectionError( - new Error('Could not establish connection. Receiving end does not exist.') - ) - ).toBe(true); - expect( - isMissingContentScriptConnectionError( - new Error('Could not establish connection. Receiving end does not exist') - ) - ).toBe(true); - expect(isMissingContentScriptConnectionError(new Error('Permission denied.'))).toBe(false); - }); -}); diff --git a/apps/extension/src/shared/runtime-errors.ts b/apps/extension/src/shared/runtime-errors.ts deleted file mode 100644 index b352f9df63..0000000000 --- a/apps/extension/src/shared/runtime-errors.ts +++ /dev/null @@ -1,4 +0,0 @@ -const MISSING_CONTENT_SCRIPT_CONNECTION_ERROR = 'Receiving end does not exist'; - -export const isMissingContentScriptConnectionError = (error: unknown): error is Error => - error instanceof Error && error.message.includes(MISSING_CONTENT_SCRIPT_CONNECTION_ERROR); diff --git a/apps/extension/src/shared/side-panel.test.ts b/apps/extension/src/shared/side-panel.test.ts new file mode 100644 index 0000000000..ae1fe855e0 --- /dev/null +++ b/apps/extension/src/shared/side-panel.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from 'vitest'; +import { enableActionClickSidePanel } from './side-panel'; + +describe('side panel behavior', () => { + it('opens the native side panel from the extension action click', async () => { + const calls: { openPanelOnActionClick: boolean }[] = []; + + await enableActionClickSidePanel({ + setPanelBehavior: options => { + calls.push(options); + return Promise.resolve(); + }, + }); + + expect(calls).toStrictEqual([{ openPanelOnActionClick: true }]); + }); + + it('ignores browsers without the native side panel API', async () => { + await expect(enableActionClickSidePanel()).resolves.toBeUndefined(); + }); +}); diff --git a/apps/extension/src/shared/side-panel.ts b/apps/extension/src/shared/side-panel.ts new file mode 100644 index 0000000000..482f093a1c --- /dev/null +++ b/apps/extension/src/shared/side-panel.ts @@ -0,0 +1,7 @@ +export interface NativeSidePanelApi { + setPanelBehavior(options: { openPanelOnActionClick: boolean }): Promise; +} + +export const enableActionClickSidePanel = async (sidePanel?: NativeSidePanelApi): Promise => { + await sidePanel?.setPanelBehavior({ openPanelOnActionClick: true }); +}; diff --git a/apps/extension/src/shared/storage.test.ts b/apps/extension/src/shared/storage.test.ts deleted file mode 100644 index f911845a7a..0000000000 --- a/apps/extension/src/shared/storage.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { - DEFAULT_SIDEBAR_PREFERENCES, - SIDEBAR_PREFERENCES_STORAGE_KEY, - normalizeSidebarPreferences, -} from './storage'; - -describe('sidebar storage', () => { - it('uses a local WXT storage key for sidebar preferences', () => { - expect.assertions(1); - expect(SIDEBAR_PREFERENCES_STORAGE_KEY).toBe('local:sidebarPreferences'); - }); - - it('keeps the sidebar closed by default', () => { - expect.assertions(1); - expect(DEFAULT_SIDEBAR_PREFERENCES).toStrictEqual({ isOpen: false }); - }); - - it('normalizes valid persisted sidebar preferences', () => { - expect.assertions(1); - expect(normalizeSidebarPreferences({ isOpen: true })).toStrictEqual({ - isOpen: true, - }); - }); - - it('falls back to defaults for invalid persisted values', () => { - expect.assertions(2); - expect(normalizeSidebarPreferences()).toStrictEqual(DEFAULT_SIDEBAR_PREFERENCES); - expect(normalizeSidebarPreferences({ isOpen: 'yes' })).toStrictEqual( - DEFAULT_SIDEBAR_PREFERENCES - ); - }); -}); diff --git a/apps/extension/src/shared/storage.ts b/apps/extension/src/shared/storage.ts deleted file mode 100644 index 12a3bfc09a..0000000000 --- a/apps/extension/src/shared/storage.ts +++ /dev/null @@ -1,24 +0,0 @@ -export const SIDEBAR_PREFERENCES_STORAGE_KEY = 'local:sidebarPreferences'; - -export interface SidebarPreferences { - readonly isOpen: boolean; -} - -export const DEFAULT_SIDEBAR_PREFERENCES: SidebarPreferences = { - isOpen: false, -}; - -export const normalizeSidebarPreferences = (value?: unknown): SidebarPreferences => { - if ( - typeof value === 'object' && - value !== null && - 'isOpen' in value && - typeof value.isOpen === 'boolean' - ) { - return { - isOpen: value.isOpen, - }; - } - - return DEFAULT_SIDEBAR_PREFERENCES; -}; diff --git a/apps/extension/src/shared/tabs.test.ts b/apps/extension/src/shared/tabs.test.ts deleted file mode 100644 index 94688361cc..0000000000 --- a/apps/extension/src/shared/tabs.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { selectPopupTargetTabId } from './tabs'; - -describe('popup tab selection', () => { - it('uses the active tab when the popup is opened from the toolbar', () => { - expect.assertions(1); - - expect( - selectPopupTargetTabId( - { id: 10, url: 'http://127.0.0.1:3000/' }, - [{ id: 10, url: 'http://127.0.0.1:3000/' }], - 'chrome-extension://kilo' - ) - ).toBe(10); - }); - - it('falls back to the most recently accessed non-popup tab when debugging popup.html directly', () => { - expect.assertions(1); - - expect( - selectPopupTargetTabId( - { id: 30, url: 'chrome-extension://kilo/popup.html' }, - [ - { id: 10, lastAccessed: 100, url: 'http://127.0.0.1:3000/' }, - { id: 20, lastAccessed: 200, url: 'http://127.0.0.1:3001/' }, - { id: 30, lastAccessed: 300, url: 'chrome-extension://kilo/popup.html' }, - ], - 'chrome-extension://kilo' - ) - ).toBe(20); - }); - - it('falls back to a visible http tab when the active extension page URL is hidden', () => { - expect.assertions(1); - - expect( - selectPopupTargetTabId( - { id: 30, lastAccessed: 300 }, - [ - { id: 10, lastAccessed: 100 }, - { id: 20, lastAccessed: 200, url: 'http://127.0.0.1:3001/' }, - { id: 30, lastAccessed: 300 }, - ], - 'chrome-extension://kilo' - ) - ).toBe(20); - }); -}); diff --git a/apps/extension/src/shared/tabs.ts b/apps/extension/src/shared/tabs.ts deleted file mode 100644 index 20effee300..0000000000 --- a/apps/extension/src/shared/tabs.ts +++ /dev/null @@ -1,32 +0,0 @@ -export interface PopupTargetTab { - readonly id?: number | undefined; - readonly lastAccessed?: number | undefined; - readonly url?: string | undefined; -} - -export const selectPopupTargetTabId = ( - activeTab: PopupTargetTab | undefined, - tabs: readonly PopupTargetTab[], - extensionOrigin: string -): number | undefined => { - const fallbackTabs = tabs - .filter(tab => typeof tab.id === 'number' && tab.id !== activeTab?.id) - .toSorted((left, right) => (right.lastAccessed ?? 0) - (left.lastAccessed ?? 0)); - - if (activeTab?.url === undefined) { - const visibleWebTab = fallbackTabs.find(tab => /^https?:\/\//.test(tab.url ?? '')); - - if (typeof visibleWebTab?.id === 'number') { - return visibleWebTab.id; - } - } - - if ( - typeof activeTab?.id === 'number' && - (activeTab.url === undefined || !activeTab.url.startsWith(extensionOrigin)) - ) { - return activeTab.id; - } - - return fallbackTabs[0]?.id; -}; diff --git a/apps/extension/tests/e2e/sidebar.test.ts b/apps/extension/tests/e2e/sidebar.test.ts index fc9b34eb35..af6937a885 100644 --- a/apps/extension/tests/e2e/sidebar.test.ts +++ b/apps/extension/tests/e2e/sidebar.test.ts @@ -1,13 +1,28 @@ /* eslint-disable import/no-nodejs-modules, promise/avoid-new, promise/prefer-await-to-callbacks */ import { chromium, expect, test } from '@playwright/test'; -import { access, mkdtemp, rm } from 'node:fs/promises'; +import { access, mkdtemp, readFile, rm } from 'node:fs/promises'; import { createServer } from 'node:http'; import { tmpdir } from 'node:os'; import { join, resolve as resolvePath } from 'node:path'; -import type { BrowserContext, Page } from '@playwright/test'; +import type { BrowserContext } from '@playwright/test'; const extensionPath = resolvePath(import.meta.dirname, '../../.output/chrome-mv3'); +interface ExtensionManifest { + readonly action: + | { + readonly default_popup: string | undefined; + } + | undefined; + readonly content_scripts: unknown[] | undefined; + readonly permissions: string[] | undefined; + readonly side_panel: + | { + readonly default_path: string | undefined; + } + | undefined; +} + const startFixtureServer = async (): Promise<{ close: () => Promise; url: string }> => { const server = createServer((_request, response) => { response.writeHead(200, { 'content-type': 'text/html; charset=utf-8' }); @@ -76,9 +91,62 @@ const launchExtensionContext = async (): Promise<{ return { context, extensionId, userDataDir }; }; -const getSidebar = (page: Page) => page.locator('kilo-sidebar aside'); +const isRecord = (value: unknown): value is Record => + typeof value === 'object' && value !== null; + +const getStringArray = (value: unknown): string[] | undefined => { + if (!Array.isArray(value) || !value.every(item => typeof item === 'string')) { + return undefined; + } + + return value; +}; + +const getAction = (value: unknown): ExtensionManifest['action'] => { + if (!isRecord(value)) { + return undefined; + } + + return { + default_popup: typeof value['default_popup'] === 'string' ? value['default_popup'] : undefined, + }; +}; + +const getSidePanel = (value: unknown): ExtensionManifest['side_panel'] => { + if (!isRecord(value)) { + return undefined; + } + + return { + default_path: typeof value['default_path'] === 'string' ? value['default_path'] : undefined, + }; +}; + +const readOutputManifest = async (): Promise => { + const manifestText = await readFile(join(extensionPath, 'manifest.json'), 'utf8'); + const manifest: unknown = JSON.parse(manifestText); + + if (!isRecord(manifest)) { + throw new TypeError('Extension manifest was not an object.'); + } + + return { + action: getAction(manifest['action']), + content_scripts: Array.isArray(manifest['content_scripts']) + ? manifest['content_scripts'] + : undefined, + permissions: getStringArray(manifest['permissions']), + side_panel: getSidePanel(manifest['side_panel']), + }; +}; + +test('native side panel is outside the page DOM', async () => { + const manifest = await readOutputManifest(); + expect(manifest.side_panel?.default_path).toBe('sidepanel.html'); + expect(manifest.permissions).toContain('sidePanel'); + expect(manifest.action?.default_popup).toBeUndefined(); + expect(manifest.content_scripts).toBeUndefined(); -test('popup toggles the full-height sidebar on a normal page', async () => { const fixture = await startFixtureServer(); const { context, extensionId, userDataDir } = await launchExtensionContext(); @@ -86,19 +154,11 @@ test('popup toggles the full-height sidebar on a normal page', async () => { const page = await context.newPage(); await page.goto(fixture.url); - const popup = await context.newPage(); - await popup.goto(`chrome-extension://${extensionId}/popup.html`); - await popup.getByRole('button', { name: 'Show sidebar' }).click(); - await expect(popup.getByText('Sidebar visible')).toBeVisible(); - - const sidebar = getSidebar(page); - await expect(sidebar).toBeVisible(); - await expect(sidebar).toHaveCSS('position', 'fixed'); - await expect(sidebar).toHaveCSS('right', '0px'); - await expect(sidebar).toHaveCSS('top', '0px'); + await expect(page.locator('kilo-sidebar')).toHaveCount(0); - await popup.getByRole('button', { name: 'Hide sidebar' }).click(); - await expect(sidebar).toBeHidden(); + const sidePanel = await context.newPage(); + await sidePanel.goto(`chrome-extension://${extensionId}/sidepanel.html`); + await expect(sidePanel.getByText('Native side panel')).toBeVisible(); } finally { await context.close(); await fixture.close(); diff --git a/apps/extension/wxt.config.ts b/apps/extension/wxt.config.ts index cd3b21494d..c063dbfa1f 100644 --- a/apps/extension/wxt.config.ts +++ b/apps/extension/wxt.config.ts @@ -16,9 +16,7 @@ export default defineConfig({ }, }, description: 'Kilo browser extension.', - host_permissions: ['http://127.0.0.1/*', 'http://localhost/*'], name: 'Kilo Extension', - permissions: ['activeTab', 'scripting', 'storage'], }, modules: ['@wxt-dev/module-react'], vite: () => ({ From 20fa2e58c444dc3a19496bf9927316d187111aab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:09:34 +0200 Subject: [PATCH 08/51] feat(extension): gate side panel with device auth --- apps/extension/entrypoints/sidepanel/app.tsx | 281 +++++++++++++++--- .../entrypoints/sidepanel/auth-views.tsx | 185 ++++++++++++ apps/extension/src/shared/auth.test.ts | 154 ++++++++++ apps/extension/src/shared/auth.ts | 222 ++++++++++++++ apps/extension/src/shared/side-panel.test.ts | 1 - apps/extension/src/shared/side-panel.ts | 2 +- apps/extension/src/types/import-meta.d.ts | 3 + apps/extension/tests/e2e/sidebar.test.ts | 6 +- apps/extension/wxt.config.ts | 2 + 9 files changed, 815 insertions(+), 41 deletions(-) create mode 100644 apps/extension/entrypoints/sidepanel/auth-views.tsx create mode 100644 apps/extension/src/shared/auth.test.ts create mode 100644 apps/extension/src/shared/auth.ts create mode 100644 apps/extension/src/types/import-meta.d.ts diff --git a/apps/extension/entrypoints/sidepanel/app.tsx b/apps/extension/entrypoints/sidepanel/app.tsx index 306280d803..3387c6e183 100644 --- a/apps/extension/entrypoints/sidepanel/app.tsx +++ b/apps/extension/entrypoints/sidepanel/app.tsx @@ -1,38 +1,243 @@ -import React from 'react'; -import { KiloMark } from '@/src/shared/kilo-mark'; - -export const App = (): React.JSX.Element => ( -
-
-
- - - -
-

Kilo

-

Native side panel

-
-
-
- -
-
-
-

Current tab

- - Connected - -
-
- -
-
-

No actions yet

-

- Tools for this tab will appear here. -

-
-
-
-
-); +import { browser, storage } from '#imports'; +import { useCallback, useEffect, useRef, useState } from 'react'; +import type { JSX } from 'react'; +import { + clearStoredAuth, + createDeviceAuthRequest, + getKiloApiBaseUrl, + loadStoredAuth, + pollDeviceAuthCode, + saveStoredAuth, + validateAuthToken, +} from '@/src/shared/auth'; +import type { FetchLike, StoredAuth } from '@/src/shared/auth'; +import { + LoadingView, + PendingView, + SignedInView, + SignedOutView, + ValidationErrorView, +} from './auth-views'; + +const pollIntervalMs = 3000; +const apiBaseUrl = getKiloApiBaseUrl(); +const fetchFromWindow: FetchLike = (input, init) => fetch(input, init); + +type PanelState = + | { + readonly message?: string; + readonly status: 'checking' | 'signedOut' | 'starting'; + } + | { + readonly code: string; + readonly status: 'pending'; + readonly verificationUrl: string; + } + | { + readonly auth: StoredAuth; + readonly status: 'signedIn'; + } + | { + readonly status: 'validationError'; + }; + +export const App = (): JSX.Element => { + const [state, setState] = useState({ status: 'checking' }); + const abortRef = useRef(null); + const pollTimeoutRef = useRef | null>(null); + + const stopPolling = useCallback((): void => { + if (pollTimeoutRef.current !== null) { + clearTimeout(pollTimeoutRef.current); + pollTimeoutRef.current = null; + } + + abortRef.current?.abort(); + abortRef.current = null; + }, []); + + const validateStoredAuth = useCallback(async (): Promise => { + stopPolling(); + setState({ status: 'checking' }); + + const storedAuth = await loadStoredAuth(storage); + if (!storedAuth) { + setState({ status: 'signedOut' }); + return; + } + + const abort = new AbortController(); + abortRef.current = abort; + const result = await validateAuthToken({ + apiBaseUrl, + fetch: fetchFromWindow, + signal: abort.signal, + token: storedAuth.token, + }); + + if (abort.signal.aborted) { + return; + } + + if (result.status === 'valid') { + await saveStoredAuth(storage, result.auth); + setState({ auth: result.auth, status: 'signedIn' }); + return; + } + + if (result.status === 'invalid') { + await clearStoredAuth(storage); + setState({ message: 'Your session expired. Sign in again.', status: 'signedOut' }); + return; + } + + setState({ status: 'validationError' }); + }, [stopPolling]); + + useEffect(() => { + void validateStoredAuth(); + + return () => { + stopPolling(); + }; + }, [stopPolling, validateStoredAuth]); + + const cancelSignIn = useCallback((): void => { + stopPolling(); + setState({ status: 'signedOut' }); + }, [stopPolling]); + + const signOut = useCallback((): void => { + stopPolling(); + void (async (): Promise => { + await clearStoredAuth(storage); + setState({ status: 'signedOut' }); + })(); + }, [stopPolling]); + + const startPolling = useCallback( + (code: string): void => { + const tick = async (): Promise => { + const abort = abortRef.current; + + if (abort === null) { + return; + } + + try { + const result = await pollDeviceAuthCode({ + apiBaseUrl, + code, + fetch: fetchFromWindow, + signal: abort.signal, + }); + + if (abort.signal.aborted) { + return; + } + + switch (result.status) { + case 'pending': { + pollTimeoutRef.current = setTimeout(() => { + void tick(); + }, pollIntervalMs); + return; + } + case 'approved': { + stopPolling(); + await saveStoredAuth(storage, result.auth); + setState({ auth: result.auth, status: 'signedIn' }); + return; + } + case 'denied': { + stopPolling(); + setState({ message: 'Access was denied.', status: 'signedOut' }); + return; + } + case 'expired': { + stopPolling(); + setState({ message: 'Your sign-in code expired.', status: 'signedOut' }); + } + } + } catch (error) { + if (error instanceof Error && error.name === 'AbortError') { + return; + } + + stopPolling(); + setState({ message: 'Sign in failed. Try again.', status: 'signedOut' }); + } + }; + + void tick(); + }, + [stopPolling] + ); + + const startSignIn = useCallback((): void => { + stopPolling(); + setState({ status: 'starting' }); + + void (async (): Promise => { + try { + const authRequest = await createDeviceAuthRequest({ + apiBaseUrl, + fetch: fetchFromWindow, + }); + const abort = new AbortController(); + abortRef.current = abort; + + setState({ + code: authRequest.code, + status: 'pending', + verificationUrl: authRequest.verificationUrl, + }); + await browser.tabs.create({ url: authRequest.verificationUrl }); + startPolling(authRequest.code); + } catch { + setState({ message: 'Failed to start sign in. Try again.', status: 'signedOut' }); + } + })(); + }, [startPolling, stopPolling]); + + if (state.status === 'checking') { + return ; + } + + if (state.status === 'starting') { + return ; + } + + if (state.status === 'signedOut') { + return ; + } + + if (state.status === 'pending') { + return ( + { + void browser.tabs.create({ url: state.verificationUrl }); + }} + /> + ); + } + + if (state.status === 'validationError') { + return ( + { + void validateStoredAuth(); + }} + onSignInAgain={startSignIn} + /> + ); + } + + if (state.status === 'signedIn') { + return ; + } + + return ; +}; diff --git a/apps/extension/entrypoints/sidepanel/auth-views.tsx b/apps/extension/entrypoints/sidepanel/auth-views.tsx new file mode 100644 index 0000000000..2f4b9b0c01 --- /dev/null +++ b/apps/extension/entrypoints/sidepanel/auth-views.tsx @@ -0,0 +1,185 @@ +import type { JSX, ReactNode } from 'react'; +import type { StoredAuth } from '@/src/shared/auth'; +import { KiloMark } from '@/src/shared/kilo-mark'; + +const Header = (): JSX.Element => ( +
+
+ + + +
+

Kilo

+

Browser side panel

+
+
+
+); + +const Shell = ({ children }: { children: ReactNode }): JSX.Element => ( +
+
+ {children} +
+); + +export const LoadingView = (): JSX.Element => ( + +
+

Checking session...

+
+
+); + +export const SignedOutView = ({ + isStarting, + message, + onSignIn, +}: { + isStarting: boolean; + message: string | undefined; + onSignIn: () => void; +}): JSX.Element => ( + +
+
+

Sign in to continue

+

+ Use your Kilo account to unlock extension tools. +

+
+ + {message === undefined ? null : ( +

+ {message} +

+ )} + + +
+
+); + +export const PendingView = ({ + code, + onCancel, + onOpen, +}: { + code: string; + onCancel: () => void; + onOpen: () => void; +}): JSX.Element => ( + +
+
+

Complete sign in

+

Approve this code in the browser window.

+
+ +
+

Code

+

+ {code} +

+
+ +
+ + +
+
+
+); + +export const ValidationErrorView = ({ + onRetry, + onSignInAgain, +}: { + onRetry: () => void; + onSignInAgain: () => void; +}): JSX.Element => ( + +
+
+

Session check failed

+

+ Kilo could not validate your saved session. +

+
+
+ + +
+
+
+); + +export const SignedInView = ({ + auth, + onSignOut, +}: { + auth: StoredAuth; + onSignOut: () => void; +}): JSX.Element => ( + +
+
+
+
+

Current tab

+ {auth.userEmail === undefined ? null : ( +

{auth.userEmail}

+ )} +
+ +
+
+ +
+
+

No actions yet

+

+ Tools for this tab will appear here. +

+
+
+
+
+); diff --git a/apps/extension/src/shared/auth.test.ts b/apps/extension/src/shared/auth.test.ts new file mode 100644 index 0000000000..7051fc0f3f --- /dev/null +++ b/apps/extension/src/shared/auth.test.ts @@ -0,0 +1,154 @@ +import { describe, expect, it } from 'vitest'; +import { + AUTH_STORAGE_KEY, + clearStoredAuth, + createDeviceAuthRequest, + loadStoredAuth, + normalizeStoredAuth, + pollDeviceAuthCode, + saveStoredAuth, + validateAuthToken, +} from './auth'; +import type { AuthStorageArea, FetchLike } from './auth'; + +const jsonResponse = (body: unknown, init: ResponseInit = {}): Response => + Response.json(body, { + ...init, + }); + +const createStorage = (initialValue?: unknown): AuthStorageArea & { value: unknown } => { + let storedValue = initialValue; + + return { + getItem: key => { + expect(key).toBe(AUTH_STORAGE_KEY); + return storedValue; + }, + removeItem: key => { + expect(key).toBe(AUTH_STORAGE_KEY); + storedValue = undefined; + }, + setItem: (key, value) => { + expect(key).toBe(AUTH_STORAGE_KEY); + storedValue = value; + }, + get value() { + return storedValue; + }, + }; +}; + +describe('extension auth storage', () => { + it('normalizes valid stored auth and rejects malformed values', () => { + expect(normalizeStoredAuth({ token: 'token-1', userEmail: 'user@kilo.ai' })).toStrictEqual({ + token: 'token-1', + userEmail: 'user@kilo.ai', + }); + expect(normalizeStoredAuth({ token: 'token-1' })).toStrictEqual({ + token: 'token-1', + userEmail: undefined, + }); + expect(normalizeStoredAuth({ token: '', userEmail: 'user@kilo.ai' })).toBeUndefined(); + expect(normalizeStoredAuth({ userEmail: 'user@kilo.ai' })).toBeUndefined(); + }); + + it('loads, saves, and clears auth through the configured storage key', async () => { + const storage = createStorage({ token: 'token-1', userEmail: 'user@kilo.ai' }); + + await expect(loadStoredAuth(storage)).resolves.toStrictEqual({ + token: 'token-1', + userEmail: 'user@kilo.ai', + }); + + await saveStoredAuth(storage, { token: 'token-2', userEmail: undefined }); + expect(storage.value).toStrictEqual({ token: 'token-2', userEmail: undefined }); + + await clearStoredAuth(storage); + expect(storage.value).toBeUndefined(); + }); +}); + +describe('device auth API client', () => { + it('creates a device auth request using app mode', async () => { + const seenRequests: string[] = []; + const fetch: FetchLike = input => { + seenRequests.push(String(input)); + return jsonResponse( + { + code: 'ABCD-2345', + verificationUrl: 'https://app.kilo.ai/device-auth?code=ABCD-2345&app=1', + }, + { status: 200 } + ); + }; + + await expect( + createDeviceAuthRequest({ apiBaseUrl: 'https://app.kilo.ai/', fetch }) + ).resolves.toStrictEqual({ + code: 'ABCD-2345', + verificationUrl: 'https://app.kilo.ai/device-auth?code=ABCD-2345&app=1', + }); + expect(seenRequests).toStrictEqual(['https://app.kilo.ai/api/device-auth/codes?app=1']); + }); + + it('maps poll status codes to pending, approved, denied, and expired states', async () => { + const pollWithResponse = (response: Response) => + pollDeviceAuthCode({ + apiBaseUrl: 'https://app.kilo.ai', + code: 'ABCD-2345', + fetch: () => response, + }); + + await expect( + pollWithResponse(jsonResponse({ status: 'pending' }, { status: 202 })) + ).resolves.toStrictEqual({ status: 'pending' }); + await expect( + pollWithResponse( + jsonResponse({ status: 'approved', token: 'token-1', userEmail: 'user@kilo.ai' }) + ) + ).resolves.toStrictEqual({ + auth: { token: 'token-1', userEmail: 'user@kilo.ai' }, + status: 'approved', + }); + await expect( + pollWithResponse(jsonResponse({ status: 'denied' }, { status: 403 })) + ).resolves.toStrictEqual({ status: 'denied' }); + await expect( + pollWithResponse(jsonResponse({ status: 'expired' }, { status: 410 })) + ).resolves.toStrictEqual({ status: 'expired' }); + }); + + it('validates stored tokens with the user endpoint', async () => { + const seenHeaders: string[] = []; + const fetch: FetchLike = (_input, init) => { + seenHeaders.push(String(new Headers(init?.headers).get('authorization'))); + return jsonResponse({ google_user_email: 'user@kilo.ai' }); + }; + + await expect( + validateAuthToken({ apiBaseUrl: 'https://app.kilo.ai', fetch, token: 'token-1' }) + ).resolves.toStrictEqual({ + auth: { token: 'token-1', userEmail: 'user@kilo.ai' }, + status: 'valid', + }); + expect(seenHeaders).toStrictEqual(['Bearer token-1']); + }); + + it('returns invalid for rejected tokens and error for failed validation checks', async () => { + await expect( + validateAuthToken({ + apiBaseUrl: 'https://app.kilo.ai', + fetch: () => jsonResponse({ error: 'Unauthorized' }, { status: 401 }), + token: 'bad-token', + }) + ).resolves.toStrictEqual({ status: 'invalid' }); + + await expect( + validateAuthToken({ + apiBaseUrl: 'https://app.kilo.ai', + fetch: () => jsonResponse({ error: 'Server error' }, { status: 500 }), + token: 'token-1', + }) + ).resolves.toStrictEqual({ status: 'error' }); + }); +}); diff --git a/apps/extension/src/shared/auth.ts b/apps/extension/src/shared/auth.ts new file mode 100644 index 0000000000..f0d5afc6cb --- /dev/null +++ b/apps/extension/src/shared/auth.ts @@ -0,0 +1,222 @@ +export const AUTH_STORAGE_KEY = 'local:kiloAuth'; +export const DEFAULT_KILO_API_BASE_URL = 'https://app.kilo.ai'; + +export interface StoredAuth { + readonly token: string; + readonly userEmail: string | undefined; +} + +type MaybePromise = Promise | Value; + +export interface AuthStorageArea { + getItem(key: typeof AUTH_STORAGE_KEY): MaybePromise; + removeItem(key: typeof AUTH_STORAGE_KEY): MaybePromise; + setItem(key: typeof AUTH_STORAGE_KEY, value: StoredAuth): MaybePromise; +} + +export type FetchLike = (input: string, init?: RequestInit) => MaybePromise; + +export interface DeviceAuthRequest { + readonly code: string; + readonly verificationUrl: string; +} + +export type DeviceAuthPollResult = + | { + readonly status: 'approved'; + readonly auth: StoredAuth; + } + | { + readonly status: 'denied' | 'expired' | 'pending'; + }; + +export type TokenValidationResult = + | { + readonly status: 'valid'; + readonly auth: StoredAuth; + } + | { + readonly status: 'error' | 'invalid'; + }; + +interface ApiClientOptions { + readonly apiBaseUrl: string; + readonly fetch: FetchLike; +} + +interface PollDeviceAuthCodeOptions extends ApiClientOptions { + readonly code: string; + readonly signal?: AbortSignal; +} + +interface ValidateAuthTokenOptions extends ApiClientOptions { + readonly token: string; + readonly signal?: AbortSignal; +} + +const trimTrailingSlash = (value: string): string => value.replace(/\/+$/, ''); + +const isRecord = (value: unknown): value is Record => + typeof value === 'object' && value !== null; + +const getOptionalString = (value: unknown): string | undefined => + typeof value === 'string' && value.length > 0 ? value : undefined; + +export const getKiloApiBaseUrl = (): string => { + const configuredUrl = import.meta.env.VITE_KILO_API_BASE_URL; + + if (typeof configuredUrl === 'string' && configuredUrl.trim().length > 0) { + return trimTrailingSlash(configuredUrl.trim()); + } + + return DEFAULT_KILO_API_BASE_URL; +}; + +export const normalizeStoredAuth = (value: unknown): StoredAuth | undefined => { + if (!isRecord(value)) { + return undefined; + } + + const token = getOptionalString(value['token']); + + if (token === undefined) { + return undefined; + } + + return { + token, + userEmail: getOptionalString(value['userEmail']), + }; +}; + +export const loadStoredAuth = async ( + storageArea: AuthStorageArea +): Promise => + normalizeStoredAuth(await storageArea.getItem(AUTH_STORAGE_KEY)); + +export const saveStoredAuth = async ( + storageArea: AuthStorageArea, + auth: StoredAuth +): Promise => { + await storageArea.setItem(AUTH_STORAGE_KEY, auth); +}; + +export const clearStoredAuth = async (storageArea: AuthStorageArea): Promise => { + await storageArea.removeItem(AUTH_STORAGE_KEY); +}; + +const parseDeviceAuthRequest = (value: unknown): DeviceAuthRequest => { + if (!isRecord(value)) { + throw new TypeError('Device auth response was not an object.'); + } + + const code = getOptionalString(value['code']); + const verificationUrl = getOptionalString(value['verificationUrl']); + + if (code === undefined || verificationUrl === undefined) { + throw new TypeError('Device auth response did not include a code and verification URL.'); + } + + return { code, verificationUrl }; +}; + +const parseApprovedAuth = (value: unknown): StoredAuth => { + if (!isRecord(value)) { + throw new TypeError('Device auth poll response was not an object.'); + } + + const token = getOptionalString(value['token']); + + if (token === undefined) { + throw new TypeError('Device auth poll response did not include a token.'); + } + + return { + token, + userEmail: getOptionalString(value['userEmail']), + }; +}; + +export const createDeviceAuthRequest = async ({ + apiBaseUrl, + fetch, +}: ApiClientOptions): Promise => { + const response = await fetch(`${trimTrailingSlash(apiBaseUrl)}/api/device-auth/codes?app=1`, { + headers: { 'Content-Type': 'application/json' }, + method: 'POST', + }); + + if (!response.ok) { + throw new Error('Failed to start sign in.'); + } + + const data: unknown = await response.json(); + return parseDeviceAuthRequest(data); +}; + +export const pollDeviceAuthCode = async ({ + apiBaseUrl, + code, + fetch, + signal, +}: PollDeviceAuthCodeOptions): Promise => { + const requestInit: RequestInit = signal === undefined ? {} : { signal }; + const response = await fetch( + `${trimTrailingSlash(apiBaseUrl)}/api/device-auth/codes/${encodeURIComponent(code)}`, + requestInit + ); + + switch (response.status) { + case 200: { + const data: unknown = await response.json(); + return { auth: parseApprovedAuth(data), status: 'approved' }; + } + case 202: { + return { status: 'pending' }; + } + case 403: { + return { status: 'denied' }; + } + case 410: { + return { status: 'expired' }; + } + default: { + throw new Error('Failed to check sign-in status.'); + } + } +}; + +export const validateAuthToken = async ({ + apiBaseUrl, + fetch, + signal, + token, +}: ValidateAuthTokenOptions): Promise => { + const requestInit: RequestInit = { + headers: { Authorization: `Bearer ${token}` }, + ...(signal === undefined ? {} : { signal }), + }; + const response = await fetch(`${trimTrailingSlash(apiBaseUrl)}/api/user`, requestInit); + + if (response.status === 401 || response.status === 403) { + return { status: 'invalid' }; + } + + if (!response.ok) { + return { status: 'error' }; + } + + const data: unknown = await response.json(); + + if (!isRecord(data)) { + return { auth: { token, userEmail: undefined }, status: 'valid' }; + } + + return { + auth: { + token, + userEmail: getOptionalString(data['google_user_email']), + }, + status: 'valid', + }; +}; diff --git a/apps/extension/src/shared/side-panel.test.ts b/apps/extension/src/shared/side-panel.test.ts index ae1fe855e0..e53954a550 100644 --- a/apps/extension/src/shared/side-panel.test.ts +++ b/apps/extension/src/shared/side-panel.test.ts @@ -8,7 +8,6 @@ describe('side panel behavior', () => { await enableActionClickSidePanel({ setPanelBehavior: options => { calls.push(options); - return Promise.resolve(); }, }); diff --git a/apps/extension/src/shared/side-panel.ts b/apps/extension/src/shared/side-panel.ts index 482f093a1c..56aa5046b8 100644 --- a/apps/extension/src/shared/side-panel.ts +++ b/apps/extension/src/shared/side-panel.ts @@ -1,5 +1,5 @@ export interface NativeSidePanelApi { - setPanelBehavior(options: { openPanelOnActionClick: boolean }): Promise; + setPanelBehavior(options: { openPanelOnActionClick: boolean }): Promise | void; } export const enableActionClickSidePanel = async (sidePanel?: NativeSidePanelApi): Promise => { diff --git a/apps/extension/src/types/import-meta.d.ts b/apps/extension/src/types/import-meta.d.ts new file mode 100644 index 0000000000..e9f168e266 --- /dev/null +++ b/apps/extension/src/types/import-meta.d.ts @@ -0,0 +1,3 @@ +interface ImportMetaEnv { + readonly VITE_KILO_API_BASE_URL?: string; +} diff --git a/apps/extension/tests/e2e/sidebar.test.ts b/apps/extension/tests/e2e/sidebar.test.ts index af6937a885..ddb73c3fe8 100644 --- a/apps/extension/tests/e2e/sidebar.test.ts +++ b/apps/extension/tests/e2e/sidebar.test.ts @@ -15,6 +15,7 @@ interface ExtensionManifest { } | undefined; readonly content_scripts: unknown[] | undefined; + readonly host_permissions: string[] | undefined; readonly permissions: string[] | undefined; readonly side_panel: | { @@ -135,6 +136,7 @@ const readOutputManifest = async (): Promise => { content_scripts: Array.isArray(manifest['content_scripts']) ? manifest['content_scripts'] : undefined, + host_permissions: getStringArray(manifest['host_permissions']), permissions: getStringArray(manifest['permissions']), side_panel: getSidePanel(manifest['side_panel']), }; @@ -143,6 +145,7 @@ const readOutputManifest = async (): Promise => { test('native side panel is outside the page DOM', async () => { const manifest = await readOutputManifest(); expect(manifest.side_panel?.default_path).toBe('sidepanel.html'); + expect(manifest.host_permissions).toContain('https://app.kilo.ai/*'); expect(manifest.permissions).toContain('sidePanel'); expect(manifest.action?.default_popup).toBeUndefined(); expect(manifest.content_scripts).toBeUndefined(); @@ -158,7 +161,8 @@ test('native side panel is outside the page DOM', async () => { const sidePanel = await context.newPage(); await sidePanel.goto(`chrome-extension://${extensionId}/sidepanel.html`); - await expect(sidePanel.getByText('Native side panel')).toBeVisible(); + await expect(sidePanel.getByRole('button', { name: 'Sign in' })).toBeVisible(); + await expect(sidePanel.getByText('No actions yet')).toBeHidden(); } finally { await context.close(); await fixture.close(); diff --git a/apps/extension/wxt.config.ts b/apps/extension/wxt.config.ts index c063dbfa1f..ebe58541d7 100644 --- a/apps/extension/wxt.config.ts +++ b/apps/extension/wxt.config.ts @@ -16,7 +16,9 @@ export default defineConfig({ }, }, description: 'Kilo browser extension.', + host_permissions: ['https://app.kilo.ai/*', 'http://127.0.0.1/*', 'http://localhost/*'], name: 'Kilo Extension', + permissions: ['storage'], }, modules: ['@wxt-dev/module-react'], vite: () => ({ From 68acf613bb2981ca7af7c72aa37a52adf45edb1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:14:41 +0200 Subject: [PATCH 09/51] style(extension): use kilo logo in side panel header --- .../entrypoints/sidepanel/auth-views.tsx | 13 ++++------ apps/extension/src/shared/kilo-logo.tsx | 24 +++++++++++++++++++ apps/extension/src/shared/kilo-mark.tsx | 22 ----------------- 3 files changed, 28 insertions(+), 31 deletions(-) create mode 100644 apps/extension/src/shared/kilo-logo.tsx delete mode 100644 apps/extension/src/shared/kilo-mark.tsx diff --git a/apps/extension/entrypoints/sidepanel/auth-views.tsx b/apps/extension/entrypoints/sidepanel/auth-views.tsx index 2f4b9b0c01..7db3466879 100644 --- a/apps/extension/entrypoints/sidepanel/auth-views.tsx +++ b/apps/extension/entrypoints/sidepanel/auth-views.tsx @@ -1,17 +1,12 @@ import type { JSX, ReactNode } from 'react'; import type { StoredAuth } from '@/src/shared/auth'; -import { KiloMark } from '@/src/shared/kilo-mark'; +import { KiloLogo } from '@/src/shared/kilo-logo'; const Header = (): JSX.Element => (
-
- - - -
-

Kilo

-

Browser side panel

-
+
+ +

Kilo

); diff --git a/apps/extension/src/shared/kilo-logo.tsx b/apps/extension/src/shared/kilo-logo.tsx new file mode 100644 index 0000000000..a32323203a --- /dev/null +++ b/apps/extension/src/shared/kilo-logo.tsx @@ -0,0 +1,24 @@ +import type { JSX } from 'react'; + +interface KiloLogoProps { + className?: string; +} + +export const KiloLogo = ({ className }: KiloLogoProps): JSX.Element => ( + +); diff --git a/apps/extension/src/shared/kilo-mark.tsx b/apps/extension/src/shared/kilo-mark.tsx deleted file mode 100644 index 32c0d2c577..0000000000 --- a/apps/extension/src/shared/kilo-mark.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import type { JSX } from 'react'; - -interface KiloMarkProps { - className?: string; -} - -export const KiloMark = ({ className }: KiloMarkProps): JSX.Element => ( - -); From 77113e98d24cb258ef8ef788cbcba7478316eaca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:15:33 +0200 Subject: [PATCH 10/51] style(extension): simplify side panel header logo --- apps/extension/entrypoints/sidepanel/auth-views.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/extension/entrypoints/sidepanel/auth-views.tsx b/apps/extension/entrypoints/sidepanel/auth-views.tsx index 7db3466879..f2c791c891 100644 --- a/apps/extension/entrypoints/sidepanel/auth-views.tsx +++ b/apps/extension/entrypoints/sidepanel/auth-views.tsx @@ -4,9 +4,9 @@ import { KiloLogo } from '@/src/shared/kilo-logo'; const Header = (): JSX.Element => (
-
+
-

Kilo

+ Kilo
); From ea5d8d0de9574171f179e163d5d9d5fbe26dd668 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:27:06 +0200 Subject: [PATCH 11/51] feat(extension): target local backend in dev --- apps/extension/src/shared/auth.test.ts | 39 +++++++++++++++++++++++++- apps/extension/src/shared/auth.ts | 5 ++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/apps/extension/src/shared/auth.test.ts b/apps/extension/src/shared/auth.test.ts index 7051fc0f3f..fb4974074d 100644 --- a/apps/extension/src/shared/auth.test.ts +++ b/apps/extension/src/shared/auth.test.ts @@ -1,8 +1,11 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { AUTH_STORAGE_KEY, + DEFAULT_KILO_API_BASE_URL, + DEFAULT_LOCAL_KILO_API_BASE_URL, clearStoredAuth, createDeviceAuthRequest, + getKiloApiBaseUrl, loadStoredAuth, normalizeStoredAuth, pollDeviceAuthCode, @@ -38,6 +41,40 @@ const createStorage = (initialValue?: unknown): AuthStorageArea & { value: unkno }; }; +const withStubbedEnv = (env: Record, assertion: () => void): void => { + vi.unstubAllEnvs(); + + for (const [key, value] of Object.entries(env)) { + vi.stubEnv(key, value); + } + + try { + assertion(); + } finally { + vi.unstubAllEnvs(); + } +}; + +describe('extension auth configuration', () => { + it('defaults local extension development to the local web backend', () => { + withStubbedEnv({ COMMAND: 'serve' }, () => { + expect(getKiloApiBaseUrl()).toBe(DEFAULT_LOCAL_KILO_API_BASE_URL); + }); + }); + + it('defaults production builds to the hosted backend', () => { + withStubbedEnv({ COMMAND: 'build' }, () => { + expect(getKiloApiBaseUrl()).toBe(DEFAULT_KILO_API_BASE_URL); + }); + }); + + it('lets an explicit backend URL override the build-mode default', () => { + withStubbedEnv({ COMMAND: 'serve', VITE_KILO_API_BASE_URL: ' http://localhost:3001/ ' }, () => { + expect(getKiloApiBaseUrl()).toBe('http://localhost:3001'); + }); + }); +}); + describe('extension auth storage', () => { it('normalizes valid stored auth and rejects malformed values', () => { expect(normalizeStoredAuth({ token: 'token-1', userEmail: 'user@kilo.ai' })).toStrictEqual({ diff --git a/apps/extension/src/shared/auth.ts b/apps/extension/src/shared/auth.ts index f0d5afc6cb..58a834c1e0 100644 --- a/apps/extension/src/shared/auth.ts +++ b/apps/extension/src/shared/auth.ts @@ -1,5 +1,6 @@ export const AUTH_STORAGE_KEY = 'local:kiloAuth'; export const DEFAULT_KILO_API_BASE_URL = 'https://app.kilo.ai'; +export const DEFAULT_LOCAL_KILO_API_BASE_URL = 'http://localhost:3000'; export interface StoredAuth { readonly token: string; @@ -69,6 +70,10 @@ export const getKiloApiBaseUrl = (): string => { return trimTrailingSlash(configuredUrl.trim()); } + if (import.meta.env.COMMAND === 'serve') { + return DEFAULT_LOCAL_KILO_API_BASE_URL; + } + return DEFAULT_KILO_API_BASE_URL; }; From 0229a68a8d321c39209ffc160e297125cad72845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:30:05 +0200 Subject: [PATCH 12/51] chore(extension): run dev server on port 3001 --- apps/extension/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/extension/package.json b/apps/extension/package.json index 90983e7d1b..b4f61f38d0 100644 --- a/apps/extension/package.json +++ b/apps/extension/package.json @@ -5,7 +5,7 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "wxt", + "dev": "wxt --port 3001", "dev:firefox": "wxt -b firefox --mv3", "debug:chrome": "pnpm run build && tsx scripts/debug-chrome.ts", "build": "wxt build", From fd5de6659bc84f0ddcb92a4568eec208bc279662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:33:43 +0200 Subject: [PATCH 13/51] style(extension): align account controls in header --- .../entrypoints/sidepanel/auth-views.tsx | 66 ++++++++++++------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/apps/extension/entrypoints/sidepanel/auth-views.tsx b/apps/extension/entrypoints/sidepanel/auth-views.tsx index f2c791c891..2b9ea4cf1e 100644 --- a/apps/extension/entrypoints/sidepanel/auth-views.tsx +++ b/apps/extension/entrypoints/sidepanel/auth-views.tsx @@ -2,18 +2,56 @@ import type { JSX, ReactNode } from 'react'; import type { StoredAuth } from '@/src/shared/auth'; import { KiloLogo } from '@/src/shared/kilo-logo'; -const Header = (): JSX.Element => ( +const HeaderAccountControls = ({ + auth, + onSignOut, +}: { + auth: StoredAuth; + onSignOut: () => void; +}): JSX.Element => ( +
+ {auth.userEmail === undefined ? null : ( +

{auth.userEmail}

+ )} + +
+); + +const Header = ({ + auth, + onSignOut, +}: { + auth?: StoredAuth | undefined; + onSignOut?: (() => void) | undefined; +}): JSX.Element => (
-
+
Kilo + {auth === undefined || onSignOut === undefined ? null : ( + + )}
); -const Shell = ({ children }: { children: ReactNode }): JSX.Element => ( +const Shell = ({ + auth, + children, + onSignOut, +}: { + auth?: StoredAuth | undefined; + children: ReactNode; + onSignOut?: (() => void) | undefined; +}): JSX.Element => (
-
+
{children}
); @@ -147,26 +185,8 @@ export const SignedInView = ({ auth: StoredAuth; onSignOut: () => void; }): JSX.Element => ( - +
-
-
-
-

Current tab

- {auth.userEmail === undefined ? null : ( -

{auth.userEmail}

- )} -
- -
-
-

No actions yet

From 339465f329e835c84564506fc7e7f73428b352ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 16:59:46 +0200 Subject: [PATCH 14/51] feat(extension): add debugger html length probe --- apps/extension/entrypoints/background.ts | 83 ++++++++- apps/extension/entrypoints/sidepanel/app.tsx | 38 +++- .../entrypoints/sidepanel/auth-views.tsx | 93 +++++++++- .../entrypoints/sidepanel/use-tab-debugger.ts | 130 ++++++++++++++ .../extension/src/shared/tab-debugger.test.ts | 79 +++++++++ apps/extension/src/shared/tab-debugger.ts | 162 ++++++++++++++++++ apps/extension/tests/e2e/sidebar.test.ts | 1 + apps/extension/wxt.config.ts | 2 +- 8 files changed, 576 insertions(+), 12 deletions(-) create mode 100644 apps/extension/entrypoints/sidepanel/use-tab-debugger.ts create mode 100644 apps/extension/src/shared/tab-debugger.test.ts create mode 100644 apps/extension/src/shared/tab-debugger.ts diff --git a/apps/extension/entrypoints/background.ts b/apps/extension/entrypoints/background.ts index ec09e45626..6b32dc7eeb 100644 --- a/apps/extension/entrypoints/background.ts +++ b/apps/extension/entrypoints/background.ts @@ -1,13 +1,90 @@ import { enableActionClickSidePanel } from '@/src/shared/side-panel'; +import { + GET_TAB_HTML_LENGTH_MESSAGE, + LIST_INSPECTABLE_TABS_MESSAGE, + getTabHtmlLength, + isTabDebuggerRequest, + listInspectableTabs, +} from '@/src/shared/tab-debugger'; +import type { + ChromeDebuggerApi, + TabDebuggerRequest, + TabDebuggerResponse, +} from '@/src/shared/tab-debugger'; + +interface ChromeRuntimeApi { + readonly onMessage?: { + readonly addListener: ( + listener: ( + message: unknown, + sender: unknown, + sendResponse: (response: TabDebuggerResponse) => void + ) => boolean | void + ) => void; + }; +} + +const handleTabDebuggerRequest = async ({ + debuggerApi, + request, +}: { + debuggerApi: ChromeDebuggerApi | undefined; + request: TabDebuggerRequest; +}): Promise => { + if (debuggerApi === undefined) { + return { error: 'Debugger API is unavailable.', ok: false }; + } + + try { + if (request.type === LIST_INSPECTABLE_TABS_MESSAGE) { + return { + ok: true, + tabs: await listInspectableTabs(debuggerApi), + type: LIST_INSPECTABLE_TABS_MESSAGE, + }; + } + + return { + length: await getTabHtmlLength(debuggerApi, request.tabId), + ok: true, + type: GET_TAB_HTML_LENGTH_MESSAGE, + }; + } catch (error) { + return { + error: error instanceof Error ? error.message : 'Debugger request failed.', + ok: false, + }; + } +}; export default defineBackground(() => { - const sidePanel = ( + const chromeApi = ( globalThis as typeof globalThis & { chrome?: { + debugger?: ChromeDebuggerApi; + runtime?: ChromeRuntimeApi; sidePanel?: Parameters[0]; }; } - ).chrome?.sidePanel; + ).chrome; + + void enableActionClickSidePanel(chromeApi?.sidePanel); + + chromeApi?.runtime?.onMessage?.addListener((message, sender, sendResponse) => { + void sender; + + if (!isTabDebuggerRequest(message)) { + return; + } + + void (async (): Promise => { + const response = await handleTabDebuggerRequest({ + debuggerApi: chromeApi.debugger, + request: message, + }); + sendResponse(response); + })(); - void enableActionClickSidePanel(sidePanel); + return true; + }); }); diff --git a/apps/extension/entrypoints/sidepanel/app.tsx b/apps/extension/entrypoints/sidepanel/app.tsx index 3387c6e183..e0c71528b2 100644 --- a/apps/extension/entrypoints/sidepanel/app.tsx +++ b/apps/extension/entrypoints/sidepanel/app.tsx @@ -18,6 +18,7 @@ import { SignedOutView, ValidationErrorView, } from './auth-views'; +import { useTabDebugger } from './use-tab-debugger'; const pollIntervalMs = 3000; const apiBaseUrl = getKiloApiBaseUrl(); @@ -43,6 +44,17 @@ type PanelState = export const App = (): JSX.Element => { const [state, setState] = useState({ status: 'checking' }); + const { + htmlLength, + inspectableTabs, + isLoadingTabs, + isMeasuringHtml, + loadInspectableTabs, + measureSelectedTabHtml, + selectTab, + selectedTabId, + tabDebuggerError, + } = useTabDebugger(); const abortRef = useRef(null); const pollTimeoutRef = useRef | null>(null); @@ -102,6 +114,14 @@ export const App = (): JSX.Element => { }; }, [stopPolling, validateStoredAuth]); + useEffect(() => { + if (state.status !== 'signedIn') { + return; + } + + void loadInspectableTabs(); + }, [loadInspectableTabs, state.status]); + const cancelSignIn = useCallback((): void => { stopPolling(); setState({ status: 'signedOut' }); @@ -236,7 +256,23 @@ export const App = (): JSX.Element => { } if (state.status === 'signedIn') { - return ; + return ( + { + void loadInspectableTabs(); + }} + onSelectTab={selectTab} + onSignOut={signOut} + selectedTabId={selectedTabId} + tabDebuggerError={tabDebuggerError} + /> + ); } return ; diff --git a/apps/extension/entrypoints/sidepanel/auth-views.tsx b/apps/extension/entrypoints/sidepanel/auth-views.tsx index 2b9ea4cf1e..90828cbf0e 100644 --- a/apps/extension/entrypoints/sidepanel/auth-views.tsx +++ b/apps/extension/entrypoints/sidepanel/auth-views.tsx @@ -1,6 +1,7 @@ -import type { JSX, ReactNode } from 'react'; +import type { ChangeEvent, JSX, ReactNode } from 'react'; import type { StoredAuth } from '@/src/shared/auth'; import { KiloLogo } from '@/src/shared/kilo-logo'; +import type { InspectableTab } from '@/src/shared/tab-debugger'; const HeaderAccountControls = ({ auth, @@ -56,6 +57,24 @@ const Shell = ({
); +const getMeasureButtonLabel = ({ + htmlLength, + isMeasuringHtml, +}: { + htmlLength: number | undefined; + isMeasuringHtml: boolean; +}): string => { + if (isMeasuringHtml) { + return 'Measuring...'; + } + + if (htmlLength === undefined) { + return 'Measure HTML'; + } + + return `HTML length: ${htmlLength.toLocaleString()}`; +}; + export const LoadingView = (): JSX.Element => (
@@ -180,19 +199,79 @@ export const ValidationErrorView = ({ export const SignedInView = ({ auth, + htmlLength, + inspectableTabs, + isLoadingTabs, + isMeasuringHtml, + onMeasureHtml, + onRefreshTabs, + onSelectTab, onSignOut, + selectedTabId, + tabDebuggerError, }: { auth: StoredAuth; + htmlLength: number | undefined; + inspectableTabs: InspectableTab[]; + isLoadingTabs: boolean; + isMeasuringHtml: boolean; + onMeasureHtml: () => void; + onRefreshTabs: () => void; + onSelectTab: (tabId: number) => void; onSignOut: () => void; + selectedTabId: number | undefined; + tabDebuggerError: string | undefined; }): JSX.Element => (
-
-
-

No actions yet

-

- Tools for this tab will appear here. -

+
+
+
+ + +
+ + + + + + {tabDebuggerError === undefined ? null : ( +

{tabDebuggerError}

+ )}
diff --git a/apps/extension/entrypoints/sidepanel/use-tab-debugger.ts b/apps/extension/entrypoints/sidepanel/use-tab-debugger.ts new file mode 100644 index 0000000000..60d9e598f5 --- /dev/null +++ b/apps/extension/entrypoints/sidepanel/use-tab-debugger.ts @@ -0,0 +1,130 @@ +import { browser } from '#imports'; +import { useCallback, useState } from 'react'; +import { + GET_TAB_HTML_LENGTH_MESSAGE, + LIST_INSPECTABLE_TABS_MESSAGE, + isTabDebuggerResponse, +} from '@/src/shared/tab-debugger'; +import type { + InspectableTab, + TabDebuggerRequest, + TabDebuggerResponse, +} from '@/src/shared/tab-debugger'; + +const getErrorMessage = (error: unknown, fallback: string): string => + error instanceof Error ? error.message : fallback; + +const sendTabDebuggerRequest = async ( + request: TabDebuggerRequest +): Promise => { + const response: unknown = await browser.runtime.sendMessage(request); + + if (!isTabDebuggerResponse(response)) { + return { error: 'Extension background returned an invalid response.', ok: false }; + } + + return response; +}; + +export const useTabDebugger = (): { + readonly htmlLength: number | undefined; + readonly inspectableTabs: InspectableTab[]; + readonly isLoadingTabs: boolean; + readonly isMeasuringHtml: boolean; + readonly loadInspectableTabs: () => Promise; + readonly measureSelectedTabHtml: () => void; + readonly selectTab: (tabId: number) => void; + readonly selectedTabId: number | undefined; + readonly tabDebuggerError: string | undefined; +} => { + const [htmlLength, setHtmlLength] = useState(); + const [inspectableTabs, setInspectableTabs] = useState([]); + const [isLoadingTabs, setIsLoadingTabs] = useState(false); + const [isMeasuringHtml, setIsMeasuringHtml] = useState(false); + const [selectedTabId, setSelectedTabId] = useState(); + const [tabDebuggerError, setTabDebuggerError] = useState(); + + const loadInspectableTabs = useCallback(async (): Promise => { + setIsLoadingTabs(true); + setTabDebuggerError(undefined); + + try { + const response = await sendTabDebuggerRequest({ type: LIST_INSPECTABLE_TABS_MESSAGE }); + + if (!response.ok) { + throw new Error(response.error); + } + + if (response.type !== LIST_INSPECTABLE_TABS_MESSAGE) { + throw new Error('Extension background returned the wrong response.'); + } + + setInspectableTabs(response.tabs); + setSelectedTabId(currentTabId => { + if (currentTabId !== undefined && response.tabs.some(tab => tab.id === currentTabId)) { + return currentTabId; + } + + return response.tabs[0]?.id; + }); + } catch (error) { + setInspectableTabs([]); + setSelectedTabId(undefined); + setTabDebuggerError(getErrorMessage(error, 'Failed to load tabs.')); + } finally { + setIsLoadingTabs(false); + } + }, []); + + const selectTab = useCallback((tabId: number): void => { + setHtmlLength(undefined); + setSelectedTabId(tabId); + setTabDebuggerError(undefined); + }, []); + + const measureSelectedTabHtml = useCallback((): void => { + if (selectedTabId === undefined) { + setTabDebuggerError('Select a tab first.'); + return; + } + + setHtmlLength(undefined); + setIsMeasuringHtml(true); + setTabDebuggerError(undefined); + + void (async (): Promise => { + try { + const response = await sendTabDebuggerRequest({ + tabId: selectedTabId, + type: GET_TAB_HTML_LENGTH_MESSAGE, + }); + + if (!response.ok) { + throw new Error(response.error); + } + + if (response.type !== GET_TAB_HTML_LENGTH_MESSAGE) { + throw new Error('Extension background returned the wrong response.'); + } + + setHtmlLength(response.length); + } catch (error) { + setTabDebuggerError(getErrorMessage(error, 'Failed to measure HTML.')); + } finally { + setIsMeasuringHtml(false); + } + })(); + }, [selectedTabId]); + + return { + htmlLength, + inspectableTabs, + isLoadingTabs, + isMeasuringHtml, + loadInspectableTabs, + measureSelectedTabHtml, + selectTab, + selectedTabId, + tabDebuggerError, + }; +}; diff --git a/apps/extension/src/shared/tab-debugger.test.ts b/apps/extension/src/shared/tab-debugger.test.ts new file mode 100644 index 0000000000..1588f5be5f --- /dev/null +++ b/apps/extension/src/shared/tab-debugger.test.ts @@ -0,0 +1,79 @@ +import { describe, expect, it } from 'vitest'; +import { HTML_LENGTH_EXPRESSION, getTabHtmlLength, listInspectableTabs } from './tab-debugger'; +import type { ChromeDebuggerApi, ChromeDebuggerTargetInfo } from './tab-debugger'; + +const createDebuggerApi = ({ + sendCommand, + targets, +}: { + sendCommand?: ChromeDebuggerApi['sendCommand']; + targets?: ChromeDebuggerTargetInfo[]; +} = {}): ChromeDebuggerApi & { calls: string[] } => { + const calls: string[] = []; + + return { + attach: target => { + calls.push(`attach:${target.tabId}`); + }, + calls, + detach: target => { + calls.push(`detach:${target.tabId}`); + }, + getTargets: () => + targets ?? [ + { tabId: 1, title: 'Kilo', type: 'page', url: 'https://app.kilo.ai/' }, + { tabId: 2, title: 'Chrome settings', type: 'page', url: 'chrome://settings' }, + { title: 'Extension worker', type: 'service_worker', url: 'chrome-extension://id/bg.js' }, + { tabId: 3, title: 'Local app', type: 'page', url: 'http://localhost:3001/' }, + ], + sendCommand: + sendCommand ?? + ((_target, _method, _params) => { + calls.push('sendCommand'); + return { result: { type: 'number', value: 42 } }; + }), + }; +}; + +describe('tab debugger helpers', () => { + it('lists only normal inspectable page tabs', async () => { + await expect(listInspectableTabs(createDebuggerApi())).resolves.toStrictEqual([ + { id: 1, title: 'Kilo', url: 'https://app.kilo.ai/' }, + { id: 3, title: 'Local app', url: 'http://localhost:3001/' }, + ]); + }); + + it('evaluates and returns the selected tab html length', async () => { + const calls: unknown[] = []; + const debuggerApi = createDebuggerApi({ + sendCommand: (target, method, params) => { + calls.push({ method, params, target }); + return { result: { type: 'number', value: 12_345 } }; + }, + }); + + await expect(getTabHtmlLength(debuggerApi, 7)).resolves.toBe(12_345); + expect(debuggerApi.calls).toStrictEqual(['attach:7', 'detach:7']); + expect(calls).toStrictEqual([ + { + method: 'Runtime.evaluate', + params: { + expression: HTML_LENGTH_EXPRESSION, + returnByValue: true, + }, + target: { tabId: 7 }, + }, + ]); + }); + + it('detaches from the tab when evaluation fails', async () => { + const debuggerApi = createDebuggerApi({ + sendCommand: () => { + throw new Error('Evaluation failed.'); + }, + }); + + await expect(getTabHtmlLength(debuggerApi, 7)).rejects.toThrow('Evaluation failed.'); + expect(debuggerApi.calls).toStrictEqual(['attach:7', 'detach:7']); + }); +}); diff --git a/apps/extension/src/shared/tab-debugger.ts b/apps/extension/src/shared/tab-debugger.ts new file mode 100644 index 0000000000..7eb9b7096f --- /dev/null +++ b/apps/extension/src/shared/tab-debugger.ts @@ -0,0 +1,162 @@ +export const DEBUGGER_PROTOCOL_VERSION = '1.3'; +export const HTML_LENGTH_EXPRESSION = 'document.documentElement.outerHTML.length'; +export const LIST_INSPECTABLE_TABS_MESSAGE = 'kilo.tabs.listInspectable'; +export const GET_TAB_HTML_LENGTH_MESSAGE = 'kilo.tabs.getHtmlLength'; + +export interface ChromeDebuggerTargetInfo { + readonly attached?: boolean; + readonly tabId?: number; + readonly title?: string; + readonly type?: string; + readonly url?: string; +} + +export interface ChromeDebuggerTarget { + readonly tabId: number; +} + +export interface ChromeDebuggerApi { + readonly attach: (target: ChromeDebuggerTarget, requiredVersion: string) => Promise | void; + readonly detach: (target: ChromeDebuggerTarget) => Promise | void; + readonly getTargets: () => Promise | ChromeDebuggerTargetInfo[]; + readonly sendCommand: ( + target: ChromeDebuggerTarget, + method: string, + commandParams?: Record + ) => unknown; +} + +export interface InspectableTab { + readonly id: number; + readonly title: string; + readonly url: string; +} + +export type TabDebuggerRequest = + | { + readonly type: typeof LIST_INSPECTABLE_TABS_MESSAGE; + } + | { + readonly tabId: number; + readonly type: typeof GET_TAB_HTML_LENGTH_MESSAGE; + }; + +export type TabDebuggerResponse = + | { + readonly ok: true; + readonly tabs: InspectableTab[]; + readonly type: typeof LIST_INSPECTABLE_TABS_MESSAGE; + } + | { + readonly length: number; + readonly ok: true; + readonly type: typeof GET_TAB_HTML_LENGTH_MESSAGE; + } + | { + readonly error: string; + readonly ok: false; + }; + +const isRecord = (value: unknown): value is Record => + typeof value === 'object' && value !== null; + +const isNormalPageUrl = (url: string | undefined): url is string => + url?.startsWith('http://') === true || url?.startsWith('https://') === true; + +export const listInspectableTabs = async ( + debuggerApi: ChromeDebuggerApi +): Promise => { + const targets = await debuggerApi.getTargets(); + + return targets + .filter( + ( + target + ): target is ChromeDebuggerTargetInfo & { readonly tabId: number; readonly url: string } => + target.type === 'page' && typeof target.tabId === 'number' && isNormalPageUrl(target.url) + ) + .map(target => { + const title = target.title?.trim(); + + return { + id: target.tabId, + title: title === undefined || title === '' ? target.url : title, + url: target.url, + }; + }); +}; + +export const getTabHtmlLength = async ( + debuggerApi: ChromeDebuggerApi, + tabId: number +): Promise => { + const target = { tabId }; + let attached = false; + + await debuggerApi.attach(target, DEBUGGER_PROTOCOL_VERSION); + attached = true; + + try { + const response = await debuggerApi.sendCommand(target, 'Runtime.evaluate', { + expression: HTML_LENGTH_EXPRESSION, + returnByValue: true, + }); + + if (!isRecord(response)) { + throw new Error('Debugger did not return an HTML length.'); + } + + const { exceptionDetails, result } = response; + + if (exceptionDetails !== undefined) { + throw new Error('Page evaluation failed.'); + } + + if (!isRecord(result) || typeof result['value'] !== 'number') { + throw new Error('Debugger did not return an HTML length.'); + } + + return result['value']; + } finally { + if (attached) { + await debuggerApi.detach(target); + } + } +}; + +export const isTabDebuggerRequest = (value: unknown): value is TabDebuggerRequest => { + if (!isRecord(value) || typeof value['type'] !== 'string') { + return false; + } + + if (value['type'] === LIST_INSPECTABLE_TABS_MESSAGE) { + return true; + } + + return value['type'] === GET_TAB_HTML_LENGTH_MESSAGE && typeof value['tabId'] === 'number'; +}; + +export const isTabDebuggerResponse = (value: unknown): value is TabDebuggerResponse => { + if (!isRecord(value) || typeof value['ok'] !== 'boolean') { + return false; + } + + if (!value['ok']) { + return typeof value['error'] === 'string'; + } + + if (value['type'] === LIST_INSPECTABLE_TABS_MESSAGE) { + return ( + Array.isArray(value['tabs']) && + value['tabs'].every( + tab => + isRecord(tab) && + typeof tab['id'] === 'number' && + typeof tab['title'] === 'string' && + typeof tab['url'] === 'string' + ) + ); + } + + return value['type'] === GET_TAB_HTML_LENGTH_MESSAGE && typeof value['length'] === 'number'; +}; diff --git a/apps/extension/tests/e2e/sidebar.test.ts b/apps/extension/tests/e2e/sidebar.test.ts index ddb73c3fe8..04166b5cf1 100644 --- a/apps/extension/tests/e2e/sidebar.test.ts +++ b/apps/extension/tests/e2e/sidebar.test.ts @@ -146,6 +146,7 @@ test('native side panel is outside the page DOM', async () => { const manifest = await readOutputManifest(); expect(manifest.side_panel?.default_path).toBe('sidepanel.html'); expect(manifest.host_permissions).toContain('https://app.kilo.ai/*'); + expect(manifest.permissions).toContain('debugger'); expect(manifest.permissions).toContain('sidePanel'); expect(manifest.action?.default_popup).toBeUndefined(); expect(manifest.content_scripts).toBeUndefined(); diff --git a/apps/extension/wxt.config.ts b/apps/extension/wxt.config.ts index ebe58541d7..6cde2e3c17 100644 --- a/apps/extension/wxt.config.ts +++ b/apps/extension/wxt.config.ts @@ -18,7 +18,7 @@ export default defineConfig({ description: 'Kilo browser extension.', host_permissions: ['https://app.kilo.ai/*', 'http://127.0.0.1/*', 'http://localhost/*'], name: 'Kilo Extension', - permissions: ['storage'], + permissions: ['debugger', 'storage'], }, modules: ['@wxt-dev/module-react'], vite: () => ({ From 381b0c2621be75bf1caabaf73f1f2bb06eed0bbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 17:08:27 +0200 Subject: [PATCH 15/51] style(extension): add agent chat placeholder shell --- .../sidepanel/agent-chat-panel.tsx | 186 ++++++++++++++++++ apps/extension/entrypoints/sidepanel/app.tsx | 38 +--- .../entrypoints/sidepanel/auth-views.tsx | 93 +-------- .../src/shared/agent-chat-placeholder.test.ts | 29 +++ .../src/shared/agent-chat-placeholder.ts | 39 ++++ 5 files changed, 258 insertions(+), 127 deletions(-) create mode 100644 apps/extension/entrypoints/sidepanel/agent-chat-panel.tsx create mode 100644 apps/extension/src/shared/agent-chat-placeholder.test.ts create mode 100644 apps/extension/src/shared/agent-chat-placeholder.ts diff --git a/apps/extension/entrypoints/sidepanel/agent-chat-panel.tsx b/apps/extension/entrypoints/sidepanel/agent-chat-panel.tsx new file mode 100644 index 0000000000..9f982ddfbe --- /dev/null +++ b/apps/extension/entrypoints/sidepanel/agent-chat-panel.tsx @@ -0,0 +1,186 @@ +import { useMemo, useState } from 'react'; +import type { ChangeEvent, JSX, ReactNode } from 'react'; +import { getDefaultAgentPanelState } from '@/src/shared/agent-chat-placeholder'; +import type { AgentChatMessage, AgentPanelFooterState } from '@/src/shared/agent-chat-placeholder'; + +const modeOptions = [ + { label: 'Safe', value: 'safe' }, + { label: 'Dangerous', value: 'dangerous' }, +] as const; + +const modelOptions = ['Claude Sonnet 4', 'Claude Opus 4', 'GPT-5'] as const; +const effortOptions = ['low', 'medium', 'high'] as const; + +const isThinkingEffort = (value: string): value is AgentPanelFooterState['thinkingEffort'] => + value === 'low' || value === 'medium' || value === 'high'; + +const FieldLabel = ({ children, htmlFor }: { children: string; htmlFor: string }): JSX.Element => ( + +); + +const SelectControl = ({ + children, + id, + label, + onChange, + value, +}: { + children: ReactNode; + id: string; + label: string; + onChange: (value: string) => void; + value: string; +}): JSX.Element => ( +
+ {label} + +
+); + +const ModeControl = ({ + mode, + onChange, +}: { + mode: 'dangerous' | 'safe'; + onChange: (mode: 'dangerous' | 'safe') => void; +}): JSX.Element => ( +
+

Mode

+
+ {modeOptions.map(option => ( + + ))} +
+
+); + +const Message = ({ message }: { message: AgentChatMessage }): JSX.Element => { + const isUser = message.role === 'user'; + + return ( +
+
+

{message.body}

+
+
+ ); +}; + +export const AgentChatPanel = (): JSX.Element => { + const initialState = useMemo(() => getDefaultAgentPanelState(), []); + const [draft, setDraft] = useState(initialState.draft); + const [mode, setMode] = useState(initialState.footer.mode); + const [model, setModel] = useState(initialState.footer.model); + const [thinkingEffort, setThinkingEffort] = useState(initialState.footer.thinkingEffort); + + return ( +
+
+
+

Agent

+

+ Placeholder conversation for the selected browser tab. +

+
+ +
+ {initialState.messages.map(message => ( + + ))} +
+
+ +
{ + event.preventDefault(); + }} + > + +

%MK<|4>cg`HSf&!|*4 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 diff --git a/apps/extension/public/icon/icon.svg b/apps/extension/public/icon/icon.svg new file mode 100644 index 0000000000..e47ccc6f03 --- /dev/null +++ b/apps/extension/public/icon/icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + From c288663deb2f128b8df7b7e893aa737ccec05971 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20=C5=A0=C4=87eki=C4=87?= Date: Mon, 22 Jun 2026 15:02:35 +0200 Subject: [PATCH 03/51] chore(extension): refine extension logo icon --- apps/extension/public/icon/128.png | Bin 18291 -> 8384 bytes apps/extension/public/icon/16.png | Bin 1272 -> 1219 bytes apps/extension/public/icon/32.png | Bin 535 -> 2679 bytes apps/extension/public/icon/48.png | Bin 3523 -> 3860 bytes apps/extension/public/icon/96.png | Bin 8780 -> 5458 bytes apps/extension/public/icon/icon.svg | 18 ++++++------------ 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/apps/extension/public/icon/128.png b/apps/extension/public/icon/128.png index 40341f2bc246f635a6011e5c30ea16065a1b5f89..8dbb8fbcc2cbe55b1ff9ee20c40e81964f1eae68 100644 GIT binary patch literal 8384 zcmb7p2T)W^w{4#p7&3z(h>`{n5Rfc6jRXZGN|Y>7Kr%x{&L^S>N)Sm(5+!GloQ6*_ z2q;OCAQB|!oF2Zv>Q&uWb>FRbs?OO}-MzcJ_CC9MtzIv+HSbc8ULyqnP^hXX-M_H# z-wG0ICsP)W&T^KNB`vdk?2#h7C#4l4le)T- zvb*^^!^fl`nmVMJ3TMP&211&(J?J4p`V4w@fKt3{O@Oxyvw8*S$#q^`0wJv7LI_Ji zC85wOpgSzAS=*|G+AuMSEbdt|RgRP>SP9v?3arw70c+R0yT-$^-O&6%msS>P`7KtMZoQJ3AX-FlfeN^X>hgrJ@^oUD@S0`E2u4QlX(G5Y z*4+29B})KlT+j~!yz}N{_>@Ry-(Ar7uCWnpxgTQPr=&xE>D}$2vp`66htNQ8PM5DC z>j!o#$iBn`U%0F;)$ui&YB|lE*xa>v0ATu8xuc59%^`A~(5MLy+^2 zPcumxsQy#bI6hNHYk>-1cz!YTnfic(_~<1#w15a(z3mhFrDvMqzeeH?Ab)HIzhBg$9qWWYL{Q9K~^lv(#$#&@xx@r z5yXF9gYd(3(EXmvB@JkPDS>)!KmRLpsL8Fv5L$~CQ>D&5*H-EiwoKb z!4(sZgjn8p$mpP_OROxPvvs>bz-2{LIVE{`FR~bSsKv~-_;`@s7%b34@niBdg6@+%N=a*w><>hc7I2fS zK)`)p1}i@!bJFSM#bd_wfdjHT;8so1s381o`>i7Pg8UJ(CPz*+v9k3JZwwcx&0nuP zaA`d+Xsdq-g4HL^Xkc7CE=c9-5^Jb#YcAy0T%NFl%8@PaH3!~{n*Nd;fHgrk&3TdE zWhotr19ld|vP_oeA^|K!CDI3LyKjnhyI&$zcDN`J65H7POt70J?#lq*-R_)bjO+N| zA%m@zcjm%pYxO~vt6KR-$d-xUQ!9(jv+beepyZvgA#~C|KW+y`hUlxWrnfiqii4KN zkvbtCKjh7H``JKLcLR;OX*iUULA7;Y)qgfWwd23#5;RYiy2aFb4}2B>tfv_MQ_~q_ zMI)yDY_5HzF4fJvo5kD-{pb&#i~>aVnUzRO<7OAd6?S(KAk5$Qh!o}+#Bpu(#XiwS zzfxj%m%>h0;WdCso=YBC32wlSqm-S@peXS0^(a`j=dmbz5FxSvwN!@HF{O7WTwy|l zX}ydhq|(X@7hstuwhYwrzrJMv?a)s!{f<~~QQPRBSqKsRYD|Dd`{xSq*gVgzt*2>a z0DGk4ERh~#0jtk}Rp<`{wvu^wVc~pKb}dJmyJ+4YEVBj}NOaA`xz?T76W~3Y2hIYwIgEfueVNIkiX zXNz1x8A&u7&n^MQ#p?;C;9Z`6#57CuRj`c6MPX?zTfd6Ea-$1 zGZMcO`c_jNjdyb_iLsduR`?dQJ!m)p=Eah5D6H|yFC|dZsYCiL^AnkQtq?-nx5eU& zPKNKq%j(;VZ)M8OVUMt*TL|J;9ehL>c_qF81D-`hf=dq-o>$Ue>@=_z5$2}{EK{X! z&W9#O1)OC{nRVF!$8C+5=4rf&k>rRD0eT9IwAAiy%to7kfr38RE3Fb7?Z^xy!o1%W z1uWYb%Xig*f{5u$ERE*ipXdK@gMjw+QDW?K?W{_Z*{o<`wNK>O9?f7tKW3qwytkG_b(%R~Cv5 z-Pm;>pna$6)vm(h&QIY>kGKxzp_RQ=2?mUh_ZkQIiYzQb<=m?9xQ1OzsyQc&mW&i; z>gqSx9G=pMPL8mVg`W|U_&|D&hBXW@{nt@IKEP$(xp}D0k@4<;B7Gu=wg^-o#Vt1> zI({UIp|N@ubOE*QI0t|k4mSkfSpxid@!pj?H{KB05|do)?QkwM(;9k`RIB%Z`sl3D zd^M@c>t0+ZJ7^TJUP5}k!`(K4DT`D0g|IW9gk!;pz`+y|#>AvCvxK&T1|g~NgvfG# zR|9(Fb(^Mww=4$756-{y&ZC)|B(|FT&iSD*pP3NA_oC9^_D|HZt?2DKs$y*rmQ_oX zerG;#!)DhAn3MN;3SA~=2OnmxC4O@M( zN8l{G5Do39u*hbj_`FJSWbdnv1-M$wyw--6oWFP|{^Hk4{&4;vcl(~LJeKuX>$!pz zLHg%t&mPJkXUNC$N8=D6i| zo;JPVjVnEDst&Cc@PI<}nE$ykd^O^y20>!d_D>Dq)MRqVjNRM)hZPtEnQcz)t^-cN zx?j)ep&P5!3h9ztcMRz8?;9+V5F0v8K2t!&yvAD|yH<63?(+(A9)w-XO0bs@ns0Z{ zqsm_(p3gnqS~E{VuRoEdzImrK@FMALDOQk~(5!3oK zOmb&U+7@l!^AUevmo`-qI>K4HxanXE$uS7p(}Jn)ZE)w)L@81FW^z^qWF=yC2Hcp3 z4y$7$4=u#OzoHnA23p?~YUe!N22xgP)9gnN72|H)Nhm>8fE^1ZzNnhT?3?8~%R5a? zEZlz=G}~-7&qu)Yy{kZzA-i5~&3~K%_eSH?vU_Q+0?7!bl~YleQ-U>tsESb6z8Y{W z|HFq9U$0pnfV_TFC6LJS(f2}L=$f-jM)-)Le&FFQiQ1euUtVtN(}M>Ms{@T>%5UWQ zmh-S8aYiGHw|eF71zQ-E92;wa7WG{%f(?tJdOl;aU6Q8fi8{)09qv*?`Mk~Fj&?cx zM~7$=br~@3CiZ~U_EX(VMuI3c=6Cn!ufWOGWQYl~ zp`MOYIXo#K_nugnKRNv%3D${zPLR1ZKfNc1%8{@6)(7@(EWeJm<+_&V(K(Vt7Ck9$ ze+A#>VKR=eS?yRtV5B0tWhSdpUEgX%Rb_}vf~Vy;++x3Mo8D)U?kBYT+A-CH`cd&| ziyrWH)>6T}^;gy8JU%l*RJvUA-mphhLK>;|+?JygI5~fPl@i0=65dP<-|b}{*mQya zL8IT3_wS`KnIox~-b!oK#Or^UW%nYR3Fvi27Cf#Dl)~fn4P~Ke{@54l!&9=m5qSn8 zKDn(7Vg}cBLW5L zzg#%gNV!=OtSRCg-LHYW+L2v~Oz-~i3-Zni!_x`Pbl})z#f%`j@~~uFlipq zPbiJ8W(>Q~ zZvea2x~3&Oo(#9hx;^Rv8h7PzDSU&qm6W#rR;HdAwHXjx@nwl5+Re!-08E)q#ep+2 z>!vN=)@*`iB!WE~SG`!^6>cJA z^lYhVHf7gy!O$eI1+Sni_bU=Whk#nG?=OxS0$6?Ws%xgq;tv`=TI`WdkPI{w7qOpM zEG_orLG~E4dhL^)hF-!)1Ew|lt1oCMY9Ra*Q}lPO0otDBj&Y{nb+XixGYk5G@?2>7 zqNr}$Be{5eNn`6!5B@Q|sW8FS8D3m<-y!v>w4YJanE@eN0=M5dV9QujYEeF+_>d1T z_XtmjjR$!h*(7ca$P(8ygsruID{7n?STJouc3qX&`pL#KmHV%?-?_40%FBBF3!+aY z{2xA=Q7ZyeWW8VO&v2ra_a{fk%lsDnzA!P=#&}Lh!sq@y3q~H>^I*_s#^|)Mj;|`+ z6RdfprVgR~DDhPK7r6NVNBg5q6J);<{t@$KjsSd9Nv33^4cB%L+NRL?M_LI-D~;C9 zhl;SiwDFF9%)WZFsUvgj;3O+k*|nP@iP09XC|eOJkQI>xGLWmk1Y!f?7f-LUX@eF& z9^6lZ0moc4(;wn!9sX5-b#b&LfUD=9@%{?FYxw9e^c|t*NtEy)w@>gPv)e82R0f6R z#0_SyHe6+H(3Gk<&{rN77LJTXwX!241IJaU|v&=`LD+>}h>iSO~2>madn^pT!3>K_&LS zo-M4)+_96-OlZcTS586?$?=j?UbRG#{0p?>1&w02>FjeuM`WU;_L)pJ*p8kUx_RBS z9=)CI$JxjFTrEPIO%qI%jP$pJ|I?}Z87yx76n>N1I2PDI&6x5%`Eaeb3#eoC## z=nIc5^{;?7wCv0*&>0TG0?mRgI^upc(Ji)hG4{Wi$lPx z2>ojBy!(YluG%Cteu#9gCMDi6#E)3LKACyub2}jVR6wFJRcIZA<;6SdP6&>gn+Wa) zPFlM)temxu+BFBRIh6LPNeWva*ea&vdKo=tUuTm1H1`^^u*C3(%CYw z(U*S_LAT{PO7n_i+^iM&U~hElu`G7#gLnb>%dV}!G5d#!`hCT#GRmquGZzU|T(rti zds_Zf5^$$f?m`E1Gb~K-XW#BtHTg`qLaXhFwJ@e_g4(D_2S`ccp ze;CdO!>v|)a6v|Zw+kFkd~r^Gc;tSUagC?TKu>Gs?qP#m2HhhZA)jNVOob59bYXHQ z&z*17wofM){&}Jcmb{BUh6i8`Pf8xM2{c?>3|;11({6WGjrAHiB44`fB>6^9Tllah zkZ3w;cRU2FKRIfv0lhQR+n^zBeFT~QYvw2oA~;^`Hp&%$(CU}E$~|;3i4sv=oLLxy z!0l9iXPECX!L-Fphzs!eWXw{NH;Su+md@_Wli-)qc^bEKf7;EpnMt$?wPBwBv3gO2 zZ-2Eq(m9j_L=x(Q`SD!)=ga=^YR$MDVFwPu4XiwE^a8K21CH0ycjPkI2s&+spL0y% z3Q!o00G{YjQwN{pa3MnV$&%R&yjbin4&Olb<=IFl0YcyNSaA!YgTRp!9q=NLQHH?M zFCxrnNk|cX)5fIJo4|tXAh)l0VsG`Z4CjL5CyM_1sf;Tz!s8jW|B99PL?xh-sx2OA zxSWxEwxHOHvP@~Tx?1+tW|OM8;dGHc!l9c|0Qp18NtXy_k7Ch5Xq%-lPZ)hCq(t8V zYQ#x--z{z9hPz}|ePDZj-$ORI;I7CEMA%(r6&>g8oXjU3LgMXj2_?3R3?Sh2Mw9^_ zlQJ+*qY0EtXEYDHH|VMuIp+iya7CFSr)3ydNU#>70jVtBWo9Ipe8Vh{%$SgiaVE5j_1965jN%Lj*1}>Z@INIp|~;R#KtVe zBAAg4`Z>V79i(y|ZJ(C_H8Aw&;(vp!^7?r3Jzth9lekv-gm2)54^tjdiDeJh0%GM1 zXD9}nefvqH=3byWtOxfTCdnfnUyDCs#;#6C1pw-G-jDt~lQscW#HmI5TDH~J!PfQ& z8}-fuLd@ZjXcdCMp72~Jx?K@%tIN|x%3-?jyAAc~#w+ml@|sa~OnBt-$)}&ao!{Gw z`E1VC#2!^ONR8P>$u2H<;bQhB`j9IDw(DO&Z0q(uC~&S_VhfsotTpGyw%$Y!zxSt< zCvf}KkWhr|I2Fr&&7YlJ0|`AiVZc-?))<;?A9QsB6VAthv=|BA?t9)kFD}8~pB|U{ z@IJ0q-y?I(SfP;v-(m>CjOcQgo4HHGaj!Ab%`aAN2r9GaF)u2XZ@*WwYPfm{yf6N- zfrfDoPHzW>x5L{$OMDkZXd83$jq6+QRAx#I4y+fD-m7%7szYA?OhW{%6jzLgoUfK9 zU#_cCJ3T&eq%M|jLT&`d*p}$(U6jmQV&OYkki^*c-m5ui-^*Z`ZQqN@;TIK={`1T` z3im|YDF5&KZBJl6+G_yZBPFijeLn0>jq9^CvI;yxX4 zJt?fY!>iX=n&;e=k`%x?OSl8+U7oog!n|y+Ue=2wPG-^5VU>?G*?v- zsQBl%@qs;_I&PRTuIk=Qb%&FUGdTA+e*jbqo!%1OX!ADzRKg^nXn&E2 z)6xct^uzS{a%e1QV3Pxu9Y0G3B~@!_Jhz^kY${HQU0bYnLLSeV14%X9hm_Xl#UmB_ z>74P$4GaPn6B=?wndX;tB=fuYK*H+E5YzOlLAyC{;_q@>uCP)(Et>R5hDlr@PZlOH z_*khpUc~Nm?aCbP@|BB=>nr(#a^tC_{f(WHbHFOE^@MynKy3aY{J>f658BOl{euli zVoO+*rZ$ek+;`94mJovQ`ys`Q*h4gr%tqC=Lg7K{EA`m-kjH=r7h*OrO&W!La+QV* zgMN{y6RFvBkj8#VXVdHgvJn4?&w4{Sl&NT0;k#Y%0U)y`Olk0E#;Yu8?o)MuQBAU1 zJy=ePw=p91bro-zJ(PD#PjQKG*BX`+4(S zIq?*I6juq|?9L6^St<;()Ko1(SiLU(h{()>cURDqoL4a}hCMv+{E&$$%I);zwid$l z%peW=n?W9v+WTXz6mgcT(=4FuHFIm5BSZ7aaB0vOdp{60sB#Qfhil0kElAy3bMlJ` z{_G#)V}O02d)8R6yxK1PkEpS@5y7(Bt{Amh3P@8)(Kh!A<41o2Z;m1MN3tJQ%|NfN z|K9ZZGjQ;EEqN3C!}AXdM9)4{8%#lKnelmM#k~=!!f3j88=UK&F@u$U=0N^mX{@$- z<{B?lWl_CD-FXxSBSDwa_ZLU95FMjibnw2s|27Bw)xyP}3iE?6owJ)-g#c6Df_THA zsjx!~N331y5L(J)YW{P!!}GDvMfUQdpQb$P~iJ(L_LYJ^uU7 zu&8SRA-``b&xrz*uJ8g28>IVo)6$DkbyGGcBB+CXIHV9BXA(;Z{KR z1?F*Nsva!9RNdT~y-9`LVBGz_+SPq|Qh{z~G(m^f!bR8f`Y?r+820r)Jk{%QXbYMP zI6PPYHXM!P**ctF9e&~n*A89CuyqcxOXz?~vVmHhjlAvQ+ z*1)B2+C@Kcyp(ERWTgLxmvx&gDp1|Z2H*a=7*73_kDIdh*6IMlg5dcT&f|Z{;K(GOywKhYq57%+ xEnvy}o@{G#V;7L4zHq;IfV%ZRsNm=5@qcxEE$-)GFZ6w&s;sG0q+t2>5W2x~msgg- zTF0co7h^kSnu|wYVsV$zbvJ+RZXs&sYJqORL*9piT)cu@4)r}!axX)aRo%9AM^6%2M#(b(d~wN)Im^e zQiv&~FRY02qO2X(iGKJ)cf&Q|L6;MWTlR+^FwE6$6b-;WoApPm81y^LGb8g*6OMBSsCd@liRH}?VIXg5eVv0M0MkSf@>h9N@WU`VsNU|z__gs(j#$JCtm`x-qX zK(HBr(|0$JQ5#Qopt`FHzU}?EywL!czo@X@J3;A(j%IfWct7&ZS({w z<88b&sA=2y6u4}<<^VrRP6Q0n(GC^iTMZryLf&uG4d@;K7kc>qzj-N%OT1Y_p`K665~uXRDA`wQpx2yRzf8 z5R$&OLU_@jNX6KB$|KD8_y=Sr0R9wn2Xoh0NC*1o-FGSswTG5h#vp>o$Xftp@5v(f zxwFu3jARpoBPXh>pPerxeLI09yeP#&WV0EiVcyVw>sV{8I4zoo9fZt==$ii<81*fT&Rlze?3=*A?FDBkMn7i?{ zgJu!ll&GhZa8p7)SqP)weZm!MMskXdJ6On9!iu)vF;V+d(W$>Q1b%#(9&+u3=ypE_ z*FWt*Xk>G5Ss{##q4jA)fyY#;H4*a(l5035so1 zQ1k1$CBVf~^e5yJXaAgcgl8i13T(bC=dt6C@s#A6xC#7yQ%ePzjf@)M`7XiTjV)AE zH?njZUw+ZpbA_ikA+4`Wn#^@2tZ-i0>p*oCwtxP0-yf@p52<8Q#JY99^m};qy&R34 znB$#<7b9;(6)N3pQdX6*La!&@zjQv?tp`mLFZIB*ktI7YYGs?2vu?maH2bU%sfwPM zNA5&={LP){ZnVSW0w!3iUw8R2wolRd%T-2)!0{C!eudl}yJSx~f|~Y~(R2lltKBRU z&&0BuoB+Mj$K!F^H~eRYYj1hDwfvsx2Q7KH<(9do;Ws+$q!YG?+juE#q$>#@!);o* z_f(@7JoY8a3$?S1OzttKhPtD$20s{Je^c0&9dSzBCEc&Tpllbuz4GgI>gumBx_hu2 zC<(#Uk2e`-tl<5EqOfZH`TAtU)a?tdOr-#$J&)P8MXc3ErjbF0Mbd)e!S6ub<+mP* z&XBO(Tg-1txocIL=e4@@r)ec|3c`cNJ`yz;FQPW>8|>4&)MG|m+*h1%q@pg6%8 z&w$j>-+luM)=u@FHf>_Hf}SKhh|ZC$h31{v89WruF)tW@Q2*d!(4Q2^y1PoR`8VE` zBFBt!Tj-87LT-W;xcTx_4Y__V?=gt|%02`APOnZ559JA+BFw4E{iP?coizD#7-MT@ zZ96!xbw1Ua8;X65lZr=76-$m4I!!4-#;Cs7oZR$f_9w7xz{jq?@^A#LQlaTHU#=KP zY6uuNW>@XNfY4X;gdRjy?X}VMhqI6#L(Ru|$qD2>)uAUKPN$$LHo6*=xOA>09@R-z zUZUHye~%hBl|{C9{}=#ztphed596aeXqtL#2D(X?VZbeP;&8OmB4m9vt#%+k(jI4% zRpi4Om5_cXE{65w8{I{jTm;fANqSkC^g3B@=aH{db2dRd%6)H+z zM3W3FPLQHIev$}hQ)fX$?}KV52${Q!4_+&ts3-h>)yR?noT!fr1KU{75Bj}2Ssl6V zXHaz$z26Mz#>wA8!o@u5;2BdaTUbs3iOQ7zQ*@?1Zh39s$5a_BzFMHR&7SA+4rI-Q z7KQ0TI(REs5#rk07eJFS`?}c<629!!4Y}`~Swx4}9%~|kKQS;(UQ+(El7WfU z)wzcV!257xe;?J{aG(SGkzT*Ou(dv;b`E7ui&O=>Jf41&yDhs|;4Gbt7PH?ipimsy zA|Lh{40sF_1HH(nwE(Vqd`*}!_REhC<=@HVxqM-j=#+Wn zkN?uj?^t7-5%E=9r62{pNV>TU_j7$VfGAb_oYYEAt5jA(TYgp7Cot@zO~k6HgZF5d zl8gW{&ij{ChzCn}jsd9z z3^Co{^x;Ls8gQcsBEvjYXx5mRZ1mc!2YW*rCfC5~EpdxChn@Oelq=~Ud(E*7_Ow3V2-$8Gj`ykv zoTAxj=Eq-hM{@Jkue7W^ADI#LnuhNM-87X?f1I{HIn9;AXs;Ic;zwLe z;a$V}Ep?M4AofC)6)TPU&a{Z$xXCui-9~rG#9fxT1xPpc!eo5Oh|2brk>Jz3qg(t! z`ZMqh99C+pVdrS?)My#f5-cqZO`S}qOJ4c38$x7j!%smJ!$N_9NUge*7a8Jm+?yPE zW9Nqp9t7f<(#zGNBzqU__pS?bFG(_%FV}NG*jN}J*u=UvGH8^#C3i`k@h#iWWa(#Y z7vxgqTD2lCsBmbYQRq?%X73xc@C2zPRG0#b^0S`i0p7hLtraPiEJPW0C)*Z)?qqwC zAj4E;&KlWY*MA@Ea8nhkb{-wQoQ@YYd*^FlPYr~ zv2=xe9B!LF@4XBJrF{t=La5D)>2#dkGd?#4sP5IZjtMk|hb;myr^#R9A`@MkzGe;0 zd_2b{jMomp60xBxwxN10rB;R>0U8RFU3;`P<$?Om%G3Hf%2~bldh)e3$_DO?4D}84 z4Fxj)G_83YO3F93zQHwhLnG}5fnLGlK|*}bU2u?VKogx`SFkg9kn|%6db4w_1(L<= z4GD`ls}^05eU|>dVyJA{9zFb`j1#L1@Z)yX4++$pTP(4_LMzJw`2Pf)m zTuG+A-_O<3OTNgXk~)Km!CbgX16EFv#>`acnCoSTdr64Y| z=h|U%c#S0feza6h1{R{XdD0JZm(oHD@=Eqil;V<#2?4cU{bI(K19_wY$?eJu#4w$yaDsZ*oJgsT zO9#&O)f1LU;$@WIox-~Fgiyb4tF=x8K#i8JOtMnB3;jOxGd%v|v(#hy3-;c4b6`CK zX2e$1aL<58N2{h>&AvCG6w%ZB0uobwGqE%t92bauAJGl(SBv>3bLUl)Oc*V@Rh92{_{!#e zWdE&i+O`g@yeGa(9oqo{FqUxM4x=`P)q<{SDQD^0dWM z^N;2a_~_y9U)8`MuzE}j=kyZJxDr)oh^&yU%)@Ngr}s#S>8oCSyt|3a6A~ZX#4_EE z?~Z=p4nYV$eHxy(dHz3xu=T#WR=Mc^G?gW!Rg{Hsay~ zPkj-DWh!aKFLUCMn5R)j_e1eBovkXgNMh3oRLxZ699^?jkfFHC(LGdL#N+_KqMAvb zq0dWJ!u^F>#3N4L8xI|1>fx=)#AT+{E(_p*Sy4~H7-apN4UxPso&ro+YwH681LwSv zDY9->5Oab)Y9iuu&Pz5V+b0~;68Bmi4Sx=CI@A; zDoaouCRFrHMwPYZso&`sI6k?4369}@6o5zHN^}G69C9UqOx>1(&!&G?BItoz;Q!{5 zu8~p0vc1+f!Y^{%(vJ^*(4DH|X}JbR79JQ?6}cjOypV`Slm)2nI_QM#r*-*}pe_W0 zFp3^-omL8LObOATp$6$YfAkdkesJb13|G0H?sGsMtG-Eba}F8t+87L2=)(vlh^*c> z(L>khcCn1{V_=L*4x1CFof%_}W-jhU zf^P-e0VSTDr2H8MU9u`Dqqu}CF5)m|l`BetZMeIcnV(#@IbovPPs-#r>Gq4{H-=xF zUhtv5y=|l?RC94VQv}HcGpAO_ePfF@=&Qo89~k$OH0wZyTiJv#xJaTSm^E7Y(tF*v z*o@_%=%g?8*PGAf*v(x9huxjOZQtB(({n3gn#^GAF)<8TD4_~x@=ziGmFiqdxKfup z22v)NfzAQD0NF16u?v)ZtM)x>zt(e<5fgVNMSM|x!Gx?Il_F%^m|NWdsq{Od1Q}Pz zkguRb(bX05_yWVI-lF?R>>@UW3T$Opd;4bd)Lzr0jOREpmBWVdpAtCPradV=n9g3g zb@{7YflAlIe90Qw{z*;{^`>4Sh3H$Iy%h4v+fz=!DmL?KZ;S?oEq%*Np;oy#Vi-Mj zL=lo3X>JL`n)*J&{C>?_PVT#G{>xgrgZf0CHA@iR%9Rk&V%~#w-}|#OJL2sb-3>HK z>g%pOG9}yX0|xKSLnr8|ljwR_f6!wi2<|j{9ahH58{;joe~+vVpV+7E*2|)4Wz91w zHf-3Tc!iD?@-#(P0I?ETTM(?t^-4%EpH`P7De2vb@d5UE*OS_4&4{|BMcs34>-Id*d8fx`QUXu31q z;UB9IAVU)&1z)9GucXM3EzV2l@h;nyL-xx&*KrVPz9vM~&Gull2i&RTK|J%>y8*aF zJ4M)x`iT-4NP+_2&%BM_VTc_{FAiX>Gkq5ebI%uEaE(Pbk|Vq7$%S$g$*apjs3Ju-iP%$0FIoSC>^Gdjw9k#GfR z7JJ(T8TTJ3kU+G3>P-iSx$6gb$X=S<#yzQSSsoCq&1NoY%0>TqXvd$tSP`DKSF%301e z0c|1o6-?yvhC&AiKL~u3v%@>&)|WdJTQph9Y($FALp1Q&VDuAiV9_xPi;eDmgTLh_^AZgtiPB~ z9O@J9JzLe5;i4elRGSWza-c4G+sPoErFDK(zj)IeH+v)hf#IWBBJq1|hV@s)Z_5O@ zqRmqhfhU>xPcsl3&2a(!ArW+h4{lf+u~2a^K?ba%hLiCoU;s_dgOD`t76NQ3vNa;& z>oP_Nap13fqhnJqAAzdaN@K$ewrHW|5AWX$yN0T(suxKogC?Si0B0arVCJWJV30Wjc(cx4Xte9bhBAfDT@C_Ep&qGTd0^NrigT zHOzob>?gL2c{%+t7>xN@rDGDGTA4Bo!Qhf!6u}A(i37`?$kAYKK3-OQ(PN<3 z)!57e$N71yu!|xil{igq%uNn|e31fSdxxJzpN~o4k-`DmLD|X&N3M&@W7R=n`IvEe)Od);|WV=OMNNmz@a+|{Baa0*vG6m<3L;lpXops>EgYZ zKvzF)1@|0uyi_ifPsrI zir{XoYElmp4G~BSVn|5tx=nD=``9ry6YBZouC%UVZS(?AOulb{-y8lV_ZWflk z4{gQ;ox}vpy{4dx28dmmT%>|-whvlfgI{TG2#S`cw9u)!vU?A?FLqq(0pZ6bzJ2dG zg3WJuU6v~(x0K>BX=Z~{+7k(DXRfzJ^m%`+V_8}gs>Lxi@L+muRrPvW!)o3sQ>%DX z_0+>`+AH91Ap8GfO4mZSmy@xSWATDk-&{a!e+}CMY#xF>tk4EJk6Sx!J=Vyh$U-`t zBGa8dU%Rs4xSUpA!1&gZrh{bc z>hJsA73)tIr#VQGa-CFJ?=%#16aP+(pT7m3hZn-s${^7tV^%d1#;$#pehp#31?qVHX_x;_X<9m%__jXKU>|vF`h2zIL12$ytY~m45pMXDsI5;{mm!>2Q=K z<*8x|X*~3gdww8w#(sM22O}>(4+z=O)}AUcp54pclfaO#r@4Jp6NcrqYkifUYi=2s zM+U{Ee4j&c%`mb$QJ`mrH;@0rOHb;HZiYbZk4*;%E;n>&P{a6B3wb$(e>oLM^sxwj#sShX5A1V09h?oX#Ge~@ zVx8LlcGYnhRNpkp3=w`b7QQ4X+dKGt=IkO%P>AARVd^LCL9#@n_53E>-py}SVHy_7N43`$`$Oa_PZT?IX}M6^q?uWeznDFbfx;ljS#_0 zA&$W~DRD`Na8FRA?f6iga$-u&6YOKb( zauzFm@qnu&0J3R%hr&m$p|7bq-Bbh<5mL=|&lE2#vO*G%F*ag{7cq`m zfKpygjoTQm4cU0&k(-j8-!T3As*$Ba4DrHv9s>M+c*tm?^*RH3;=BIC6k=x)`!CbQUMc`LWjT7Hq2L7M5X4 zyA^LN<;OcK8_6YAl{QEW@riQkLx|Jv7+>BhV3@`q;rUj>^V|57=ku_UO79!hFh@*m zCs+TQ;8K_lEWxNguQKpPa0B{hu#t{#;_AZN*c(PaLYlQDE5d~w7J{_X&m2d;B2{*l zm|#(ZzkTHhYfp@!#Jv9xko}8Zq9#{!``C4~0&!*o*0sPZNBkZP-Uy}5T1n%R_TqT6 z8?2mIRVu`m@miiXb)$9(55J+ zN)qoo_`^DY6oqE&Om{5dNDoor1dS=sDJpzUjd<(X`W!jkc0z+oJjp@^J@wTnq=DG> z7N+5vV){`6_%AGO2ye9Az12+VRI@OjFsYhAVNzY4?&DgrL-=a7S7E}T87^X&{MiZ2 z;pY_CTNvavT(i9XvCTCRM0Z--FtFl@3~_wj3iPs{%0fpW$L`2u0gM}rRi77yfncwv zSRC1Vus(p1(Cr31t1mNHSVr*4wv&arNx+WK2Pu@;#Kmotp+zs0S4w~zwkzinXQQz5 z;!fx2^nH2V@EG4viZ6>^yMm>V&7Yno;NnLB2CA|5h6ZWmumj(9I^w~UOQDK{osy=I z3S0)BN+LsOaEV}}7B)Ku5L`_1R>8fp^0mLc|2eL~L3VDkfN@X|(`>NmPC$&G#E zF^|0t*gwB22y0k_bN*v47@hELv%DNmZyypla}GqgQAe#mF@KnuYMxW1ihGIuSHC4%ec zfmYz=PB!l9&Q>Kx(bW|#vPJqj3sn3P?Q%3Xl|rV#Tqj^;w9hng)ckGRULdV+zJDc+ z4c=*7(`T9tHsqEJk-BWhd9?ZVSOWM3M}&_?EHcE`vR+y&8Y4a9%NX#9J0jy?WQ6S0 z=yF#ukPvx=YQ#hO_2d+375M3QZU`~X@%r&hLA(cQg75h)_GipCg1a~Gr*Vjb9b z13Qi)?0d1~Hj_Q4j(XvQUUqZW5&x}Y?L0rZy^7PvV2nW;O-EpC$`uppu0OhD`rU*Q z`4|)847~@4QOa{!o0zDLy8(jlbGEDHg0knrGssA+UTu0QN4VNf=~zW9nj;(_q=N$m_=|(h8U_Jx`WJBCYONZp8r{v zF5(d$Om12>_mY@A@)Ridrf3j~lWS;A{5_+yr3frdb~KT*k z!@Z!Xp=kqB_f}jen07I|##@&&jVTdg+DoBmeH#l}Bqj^m`9sOqHN+6-N3ZP@W8POM z_OG*o(n1kp)H`P-3RVX^wbD9YGSoM`hHb*4z^fWseih0jQb;xDs;T>=ws&fCy#@L90n5_O>*NJFtxyli2euP@* z_)=l^E;4*3RvD&yalDQJHcDxw9-obu&;SzEHY2(lEz7&e_?>(RFQxy<)d-eYM*-%p z-zh1iYSaM&t%Vz7w0CqEVXE!c9K?P4X#}Z5&iy$#4+EqA?#jPNWmNb}JK-N!it}*VKY65x^mtD@ zBI2!&3z{B6VlKU=6Xuze$OK{s&0}kHPuDR?^{Z*q(J;}uTtqRfQD;BEU*6fTc{pY* zaiMNw;q5!pRlMn-+(u=u5v}` z8l-;d@On%Y&udYs_PAs9iD6?1M?k=z%|16o1vRCDJPY-?n?u} zPADG-#QpUu#GW==+imDQVp$UKjCkeKyBjafPB?8- zj0gK=)n*IE9c+X65pB0pjmS(RnAWj-%;1-MRhbm*;-+IWGSHxtu>#sobZCuc0XQ+AtC z?9*0r36HNASlmvn1dK&ivyT8DY7@`2z)c)e#S^}1vhkfULa7@a*Z+I%D;;(tI?n{-rt0GUa9$1C+dZ>t&mh!1Y z&q%{wYCQFhN{Lz1=15a>Ze6_YQd+wPELQmp@ZF)5r2`O`T4&CJY>Wu9&&S(YvE}G4 zu&iBe-YOWjxv6W32L7A+J919^2y(4-s5wy|6+zJ;=@}7haXa0MA35{O5#An@n?Zx< zou8b6KI!ey$0lyLQ%8yv`Xd}LchkAju+$I~9hLuCE|P^S7}52v6}@m;H@AOu{qg4T z2fqd7T$YZntwqiirXEYjK_i2e5jA!98S9tCniJ*6G4A?xH#^#rglY#*j|R}S!@M2j za$<7^(*4y^73{DJLA-@JG5%<36)V2)U8O*1`!i8Uw?8u_aSr>{;^+<&t_pIt0<8To zMoA7&I>gYc+)BvhXYSr>0{)w*hiB)S??@1xrQ*~(Mb^EhVZ+lQL z`HB5mYn&i3^7AYNf03(H2(Bgh2TbgGI#E(ot}3u5NV4qYm#*1a zcD40Pdses7`rnm(d-~}>SyJcXqh|ZZTyF9nrEsgx4X){%8=oa~A$tavF*^8!A9coM z3b0$U4Su|L`NWvgrd4vUB}QvYywD&Z-)qyWoa=w|Xa2;OrS2Up-ivp7Ua;6zyQ;nswFd6fixNf`lT zGNPmO2t6n5zD?HQnbrspSWTVG`n!!Lcm{j^u5iD}FB7U#4u6owr*7g^eY_`AECxEW zYn+YFw0iAKJS*I$TP=s)!FNrHZa!Vx-R*Y=gTtI~>{QYkEEET^1L}a?4Wdn8v}b@M zU{VOgQF~BwsfTRYJv9K9G7_2Jm0!CXVLW(Z=2gp5+pJy1dDU=vptr13#!^y^&f25V4{2i4MM$hTTK?Gei=!)X1g0_` zTeJM~yrM#Z<+4r4hhJ*~hS|m!B`I8J%rToFp+#_=onO<>Me!)^C!~g8Rgy5ntdUy- z;3|Zt0c;aGW1?C4;sgipf{+Oql`md`merLpC*0EOY}*~`0C&=l3yMCy?9=$9bXgsmDHtngy8o#Cgz;IH`5*bl%9<1+ zf4|F_z={j6b?T5{{r!^l4{Hm{nkoEGIn;O>|O zzh6?Lc7DtG;MNXS%Ws!{R@*|6%^w8oY#k&JdW~**=pi!vrn*AFbnv+AvJv@3eRs>Tinge9OEF!;gty^f-Htb@8efqg{mc zgbNw6_c|T8C(V~(Xqhyq^h$I{f5+=oWVo=}bd}SiP|zN;(I2@7*_YyQPkHlpnF0pS zGfefHZ0Q5D%+r{&?DBd(BQYSMNja0Cs@7TZ*wY{WQJU_x_91IqIb~wX5i`PCZuL3n z^Dg&>_;0N5y%>C92FY#Hp+a^la`*vFp4=WGwd~9DV_TkHzGtA6EM8G$O4xVwo#1RF z{KjQ$`L7)G$KnwirJ;F@*&DXiyX(zPN7qasx(YL+>z(6FPjxnqoCgAfjl}GAym7_t zPIUusr;iIiHtIHBgVzCuQYC~PXu$B=b&L%JKA*P%e%T&Uqi8v|uQF+R{KMV$2adCp zhitwS>JK+_f2G*D?ZB~(ZW)&ytrhYRMkxY(G=304vC3$cG(vdIpIGj;tnNw zFZEl5$|37YB6BsztZBL zt5-KZl$G!l6B6nO*fd4szVGpuJWGF0Hm}(oofD5d2{(UTJCg7GPbs&$FDKN-TF2-q z=8v^vtRhjp&;E!-f#0)+Z!R`oQj=a1pYf!NGBQ@v1ugerBomW}_d0~vU2(tiR`qSXpq#+`k^^7VCvE3R6Yzkp43ULC{S z_Zo%sA3+qROS?-tohxNZxh@kWOqG#M_eFS$ z&fS#UWw%ywN?#&q$8Nll?F`ne@P>A`tIN3nxmD^ZaQ{!1ExPNKHgVvLtT0iFpbv19 z31(VLL74%LdU7|2t5ZDJ&*<$MTFyQfWzrRzO~$_{x{R;Dyl&1i4cm~vS!y)*A!X&` zx6Gf1OjuSTFi`mgdzq7C(fPqbO=s9jSn|ZrdL;-R_k0wb@`)kLXCq}7h-KBty32vj zKY!51z}RNNZ7=h==rql)5EK#33p;#Jq$m<3Xvr(=mG~b{jAANRbrPFYPVgCXxWey{E2s^@P?o!u*ZR3k542MFIDN^O`!RFJ;EAc+SKK-FC^?{-2HgHC!m)uQw8J^g`)H^-`@j9Sj{SD45%{Z&!T5fv*lLIz)e~5Op8iU& zJz6oJ?MLefm0Pg8Tzt8&9_CQ^Ovz`^tH{K6Rri6eDsAP-VYnl6z=!yA`zoWmD4bAFed#$loc2dUcd8I~n9K;UjMNYXQ&EYw{8!3RG4qUtHZ zX3z8f`VrkLG4>a{?+?BiTIvcSRD1X$mBU1`bdw!9x|@(ENZVrnmJ%--hd#(IL!}>#nc|)xXsK;W6>`vp{nV_N`SRKD(*vC%d^xR%tVd|!Uel9> z?vB5rLmk{|tE$?F+KUB4TH~YntuX$m`gW$$$Nq8_^vh`jmaK?2?o>LO-H_g& zkdmDqkG_C+$)G-2I8SVuyog zRK`6%Dc(?g$XrK=VWZM^OyH*3qX!KmE14R+L-G4;Y*|Tq-~LlVYV>AKru`?C_x!SW z>9w2cK03>+Y#xos!z*uZmr@`JW@RA_{suh^C<<~yq6Vk!0NseEC&ywJcdYR48!v8T zrQSXfJvsS|h%&!3^{Icf@fF7)NpK5V@7>sXis{LVRtjdQH$Qh<)J-+16|1%`{5pom z=&Ux&i|pTmm14~xC2Q-)+EF&@MJ)DDZ()WDmC9VKt zcl)6RWK)>!ZEThJl08G7gG7JHi+t`w>1$27A!_%uVFy;kYU%DvAcGgq07i4zXR>&C zoVyXzeb7b-uTG*L5KbWh*F~uYFbwT3@xY1mhPb z1El@huGbcsI&BvO5CeR4qCnGFeUBWqESdZU){^#Jgama{zO&wcQZ(SOKH|Upm_6Q5 zLqVWaiBxG+d45|TD=0X|uZ;BZRzUJ_dO9bj=*dJxa5t|TChCnhPurE3+ZZ*{JNa}6 zl3+One4cfhjf5o($@dDpxDXrLtXVCOR$I@Hxt%?sKeT0bR`#e*XW?{hPTXUgz>cZ` z60ofw@tJKbDKSy0zvQl8LF3~qfdt9{kSvQ1IK>=`YQ%_zr|ReFy?5 z`1N!K(H~!5uDqdj(SQd1$U=*1{nQcNzRKz|%owLf;YFXyZ-4rfS_aZdj6=~QmAyOp z876eL@x$j|3e6E(I4mc8cU(;u8v%wC*CbxXN`etxy@%ecHnMJEypAX;;AsV(*^w8A zbh(ZmAwdGrsdd39KS&>_y+vU-zwn>w`PD<;G#GnUJeVnGXvD!^0gxo(LJtEAkTFc;(5jF7uz$`{5M}@VImO4L znUyqJDSyR);oi*gmtcRG{Jm}TNjABqXU-vX_@+V=t-Eyoc+DGXybZg&XmW*_y^MX4 z`Io2Lw!=m4p&}n*rQ_9Tt^9U_3VJ#*ttW+6K90Aa=-7BDi0kj zY7i95+MdH=dhUy1XY7B%UGcAup@F!5Xs3Y|c`mHq0W_CKkx=_;=Yw>}yu8Gu@2p5N1VaEU&^}qU65tT%= zA!8&NvLoLzV9Fom#3*8F)}#S8b#WF5k4=LAz||;cLI^L7w2vEL8M9S)@!06GmtOB? zVYY#3bK{eU5O{$lx78AaW56U^Ph zgB#3Qsl^#gREH9@oxOJ*(*HcLtr4``E%rw{bZ^L2i~oT2-oBoXUMr^@+uEOq8h^O* z>o@xZ@9rOh=Bb}M;FM{Qq#CX8L-#S!;8hflWY3=DlMCU0e$2S%55ID*)};P!)jBKm z*imlJw&?)v{B3XcZ!zicq9xU2Rp|G+I(mktihq7EQJ`%7?jaj1chs|)9EoVzy2q&) z{Q{4jKy&I{EU39`N#m;+rHb68xYTF9La1*#g1xU}UJVOXsE41Uoq2_J#yx3H>2#G> zeu+L=Y3Z6PlM`8UO7Z8vvqx-kPM(f1WFj#H!LMmi0`VSugOi8o+0;1JIA5+zHSRY!BVM0 zYR}%i6~Frgj)CYARF%|+o)uLuX)Bl_GhTmur}5TsV`kmF${}cG$#8mkQoX6+0}by* z2nrzkPyJ=J&%bzK{Y3)NejUHL7$$;`x~^Gf({TQ8EIliX%*fep%fJ}G@}?6#4l*9i zb4pfs1`L=Hp3&E#PF;jigt;2-JIevw=(VF?IrIF9kbEBI7jc9elJ+M3@`Cy)3|>EL z0;z-5i9zZJA(fwaoLT)gBL(~*G4+}i_Yg~~;WH5D2P3e>!|n-E(=ClWSDjCjPh=8Bty~L?Lc?w_ot!Q+e>$c(r#x~`>k++|1i*z zv?&hI86Q_ub&0=Xq%)v2)T@ERrS<#SqxY6=SdQSHWotY%q030Y+1YiK2CY zu4w3a_ZLW&j3GQdq_6odpprt(TotlAg1{1r_PyDq$HbnZNx~-14;*!aF$hO2|`)!LN zvvRhBs&7il6f*+~kBb|2CJbuzxig!d(~WX0-8{?)@Yu#7jq#w-=)Se@8#sPu-1REi zU;(aXpwFSG@4`KCwlDa+qWHzF42mW)d3wn{AA&l+Iw|n#*o}O*dS!_XZ$}B)p7U`E zxE6MKNbO>|&cJz9lZpX3k7f#vny60%Y3rsz0K30pev^an@HEx(*EoOwqjf00+w;QR zi@6IB!UVg3c&pOr@Z9j0LN4z(zCU>F(}&M{@gIP##+&ENkLF?d@%xWMJ+-1fb!e9x zlJ{u-_3r#Beemu&NByzjOyl-|)ORDdxvS~KL%m2#4+!=)L(Oeuy68O@f9*?k^8 zkAQ47`3&Xss|3>H$LIs4`UTuShjUwVTYoEj9)F}iR-!M@!B^Y0p|4M_LV*(E_V1MKZCXL{62D3b}SwCXH#Pe4>f7c3WcW=#z7K@lp`#whVt-uv+~?RrWjq; z|B|?HDZFZ>^1tjK3$B^!rxkBH2FNQX>>W6(P_N3eG^`G!4rMaNX{6f9=sr(kZ{0@OQn@C_ktpnqpOnb^jDXt?Y4g^lL5kK;>jtUc*@D zaFC`yj1F6D8lGVQpW+KJL3=^7I<4;nLll{;`Xg5lSNV~tP&C(nsr8{>>|!@145T`( z``$*#r0+*SNb*P=ZGC=`LA~9&?ZG!Oyf3Y4k=%a|OiF-%+JkV_EnR%#DW>(&ptmlJ zNS?kvP%Twl%;vCG^1Izw8lSPCEC#NTxvtZO4Y zSFrz|0Qm$4`vCs|d45O8bq|x{w