diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d09fbf..15b2d04 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,32 +18,24 @@ jobs: with: node-version: 22 - - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: Install dependencies - run: pnpm install + run: npm ci - name: Build - run: pnpm build + run: npm run build - name: Test - run: pnpm test:all - - - name: Copy root files for extension packaging - run: cp LICENSE CHANGELOG.md THIRD_PARTY_NOTICES.md packages/platforms/vscode/ + run: npm run test:all - name: Package extension - run: pnpm --filter opencodegui run package - working-directory: . + run: npm run package - name: Publish to Marketplace - run: pnpm --filter opencodegui run publish + run: npm run publish env: VSCE_PAT: ${{ secrets.VSCE_PAT }} - name: Upload .vsix to GitHub Release uses: softprops/action-gh-release@v2 with: - files: packages/platforms/vscode/*.vsix + files: "*.vsix" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e4aa8a6..161c90a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,15 +17,11 @@ jobs: with: node-version: 22 - - uses: pnpm/action-setup@v4 - with: - version: 10 - - name: Install dependencies - run: pnpm install + run: npm ci - name: Lint & Format check - run: pnpm check + run: npm run check - name: Test - run: pnpm test:all + run: npm run test:all diff --git a/.gitignore b/.gitignore index 0c42119..d7c9a1d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,11 +14,10 @@ Thumbs.db # VS Code extension package *.vsix -# Root files copied into extension dir for packaging -packages/platforms/vscode/LICENSE -packages/platforms/vscode/CHANGELOG.md -packages/platforms/vscode/THIRD_PARTY_NOTICES.md - # Environment .env -.env.* \ No newline at end of file +.env.* + +# Agents +AGENTS.md +CLAUDE.md \ No newline at end of file diff --git a/.npmrc b/.npmrc deleted file mode 100644 index bf2e764..0000000 --- a/.npmrc +++ /dev/null @@ -1 +0,0 @@ -shamefully-hoist=true diff --git a/.vscode/launch.json b/.vscode/launch.json index 6531f05..ddf6edc 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,8 +5,8 @@ "name": "Run Extension", "type": "extensionHost", "request": "launch", - "args": ["--extensionDevelopmentPath=${workspaceFolder}/packages/platforms/vscode"], - "outFiles": ["${workspaceFolder}/packages/platforms/vscode/dist/**/*.js"], + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/dist/**/*.js"], "preLaunchTask": "npm: build" } ] diff --git a/packages/platforms/vscode/.vscodeignore b/.vscodeignore similarity index 92% rename from packages/platforms/vscode/.vscodeignore rename to .vscodeignore index a5034f0..32a0f0d 100644 --- a/packages/platforms/vscode/.vscodeignore +++ b/.vscodeignore @@ -1,5 +1,4 @@ src/** -webview/** node_modules/** tsconfig.json vite.config.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2cb435d..0462d9e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,8 +22,7 @@ This project itself is developed primarily through AI-assisted coding, and we we #### Prerequisites -- Node.js v22+ -- npm +- Node.js v24+ and npm - [OpenCode](https://github.com/anomalyco/opencode) installed with LLM provider authentication configured #### Setup @@ -105,8 +104,7 @@ By submitting a pull request, you agree that your contributions are licensed und #### 前提条件 -- Node.js v22+ -- npm +- Node.js v24+ と npm - [OpenCode](https://github.com/anomalyco/opencode) がインストール済みで、LLM プロバイダの認証が完了していること #### セットアップ diff --git a/README.md b/README.md index 3e0864d..925190e 100644 --- a/README.md +++ b/README.md @@ -85,27 +85,26 @@ Search for **OpenCodeGUI** in the VS Code Extensions view (`Ctrl+Shift+X` / `Cmd #### Prerequisites -- Node.js v22+ -- [pnpm](https://pnpm.io/) v10+ +- Node.js v24+ and npm #### Setup ```sh -pnpm install -pnpm run build +npm install +npm run build ``` #### Build ```sh -# Full build (all packages) -pnpm run build +# Full build +npm run build -# Extension only (from packages/platforms/vscode) -pnpm --filter opencodegui run build:ext +# Extension only +npm run build:extension -# Webview only (from packages/platforms/vscode) -pnpm --filter opencodegui run build:webview +# Webview only +npm run build:webview ``` #### Watch Mode @@ -114,63 +113,49 @@ Open two terminals and run each: ```sh # Terminal 1: Extension watch -pnpm --filter opencodegui run watch:ext +npm run watch:extension # Terminal 2: Webview watch -pnpm --filter opencodegui run watch:webview +npm run watch:webview ``` #### Lint & Format ```sh -pnpm run check +npm run check ``` #### Debug -1. Run `pnpm run build` +1. Run `npm run build` 2. Press `F5` in VS Code to launch the Extension Development Host 3. Click the OpenCode icon in the sidebar to open the chat panel #### Test ```sh -pnpm test +npm test ``` ### Project Structure -This project is a pnpm monorepo with the following packages: +This project is a single VS Code extension package: ``` -packages/ - core/ # @opencodegui/core — Domain types, interfaces & protocol - src/ - domain.ts # Domain types (messages, sessions, tools, permissions) - agent.interface.ts # IAgent interface - platform.interface.ts # IPlatformServices interface - protocol.ts # Webview ↔ Extension messaging protocol - - agents/ - opencode/ # @opencodegui/agent-opencode — OpenCode SDK adapter - src/ - opencode-agent.ts # IAgent implementation for OpenCode - mappers.ts # SDK ↔ domain type mappers - - platforms/ - vscode/ # opencodegui — VS Code extension - src/ - extension.ts # Extension entry point - chat-view-provider.ts # Webview panel & messaging - vscode-platform-services.ts # IPlatformServices implementation - webview/ # Webview (Browser, React) - App.tsx # State management & SSE event handling - components/ # React components (Atoms / Molecules / Organisms) - hooks/ # Custom React hooks - contexts/ # React Context providers - locales/ # i18n locale files - utils/ # Utility functions - __tests__/ # Tests (unit, scenario) +extension/ + extension.ts # Extension entry point + chat-view-provider.ts # Webview panel & messaging + opencode-client-handle.ts # OpenCode client lifecycle + __tests__/ # Extension host tests +shared/ # Shared types for extension host and webview +webview/ # Webview (React) + App.tsx # State management & SSE event handling + components/ # React components + hooks/ # Custom React hooks + contexts/ # React Context providers + locales/ # i18n locale files + utils/ # Utility functions + __tests__/ # Webview tests ``` ### Contributing @@ -257,27 +242,26 @@ VS Code の拡張機能ビュー(`Ctrl+Shift+X` / `Cmd+Shift+X`)で **OpenCo #### 前提条件 -- Node.js v22+ -- [pnpm](https://pnpm.io/) v10+ +- Node.js v24+ と npm #### セットアップ ```sh -pnpm install -pnpm run build +npm install +npm run build ``` #### ビルド ```sh -# 全体ビルド(全パッケージ) -pnpm run build +# 全体ビルド +npm run build -# Extension のみ(packages/platforms/vscode から) -pnpm --filter opencodegui run build:ext +# Extension のみ +npm run build:extension -# Webview のみ(packages/platforms/vscode から) -pnpm --filter opencodegui run build:webview +# Webview のみ +npm run build:webview ``` #### Watch モード @@ -286,63 +270,49 @@ pnpm --filter opencodegui run build:webview ```sh # Terminal 1: Extension watch -pnpm --filter opencodegui run watch:ext +npm run watch:extension # Terminal 2: Webview watch -pnpm --filter opencodegui run watch:webview +npm run watch:webview ``` #### リント & フォーマット ```sh -pnpm run check +npm run check ``` #### デバッグ実行 -1. `pnpm run build` でビルドする +1. `npm run build` でビルドする 2. VS Code で `F5` を押して Extension Development Host を起動する 3. サイドバーの OpenCode アイコンをクリックしてチャットパネルを開く #### テスト ```sh -pnpm test +npm test ``` ### プロジェクト構造 -本プロジェクトは pnpm モノレポ構成です。 +本プロジェクトは単一の VS Code 拡張パッケージです。 ``` -packages/ - core/ # @opencodegui/core — ドメイン型・インターフェース・プロトコル - src/ - domain.ts # ドメイン型(メッセージ、セッション、ツール、パーミッション) - agent.interface.ts # IAgent インターフェース - platform.interface.ts # IPlatformServices インターフェース - protocol.ts # Webview ↔ Extension メッセージングプロトコル - - agents/ - opencode/ # @opencodegui/agent-opencode — OpenCode SDK アダプター - src/ - opencode-agent.ts # OpenCode 用 IAgent 実装 - mappers.ts # SDK ↔ ドメイン型マッパー - - platforms/ - vscode/ # opencodegui — VS Code 拡張機能 - src/ - extension.ts # 拡張機能エントリーポイント - chat-view-provider.ts # Webview パネル & メッセージング - vscode-platform-services.ts # IPlatformServices 実装 - webview/ # Webview (Browser, React) - App.tsx # 状態管理 & SSE イベントハンドリング - components/ # React コンポーネント(Atoms / Molecules / Organisms) - hooks/ # カスタム React フック - contexts/ # React Context プロバイダー - locales/ # i18n ロケールファイル - utils/ # ユーティリティ関数 - __tests__/ # テスト(単体、シナリオ) +extension/ + extension.ts # 拡張機能エントリーポイント + chat-view-provider.ts # Webview パネル & メッセージング + opencode-client-handle.ts # OpenCode client lifecycle + __tests__/ # Extension Host テスト +shared/ # Extension Host と Webview の共有型 +webview/ # Webview (React) + App.tsx # 状態管理 & SSE イベントハンドリング + components/ # React コンポーネント + hooks/ # カスタム React フック + contexts/ # React Context プロバイダー + locales/ # i18n locale files + utils/ # ユーティリティ関数 + __tests__/ # Webview テスト ``` ### コントリビュート diff --git a/packages/platforms/vscode/config.json b/config.json similarity index 100% rename from packages/platforms/vscode/config.json rename to config.json diff --git a/docs/architecture.md b/docs/architecture.md index 9899b85..fa68ebe 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,322 +1,49 @@ -# OpenCodeGUI アーキテクチャ - -## 概要 - -OpenCodeGUI は、AI コーディングエージェントと対話するための VS Code 拡張機能を提供するマルチパッケージモノレポです。アーキテクチャは **Core**(共有型定義)、**Agents**(バックエンドアダプター)、**Platforms**(UI + プラットフォーム固有サービス)の3層に関心を分離しています。 - -``` -opencodegui-monorepo/ -├── packages/ -│ ├── core/ @opencodegui/core -│ ├── agents/ -│ │ └── opencode/ @opencodegui/agent-opencode -│ └── platforms/ -│ └── vscode/ @opencodegui/vscode -├── package.json ワークスペースルート -├── pnpm-workspace.yaml pnpm ワークスペース設定 -└── biome.json 共有リンター設定 -``` - -## 依存関係グラフ - -``` -@opencodegui/vscode - ├── @opencodegui/core (ドメイン型、インターフェース、プロトコル) - └── @opencodegui/agent-opencode - └── @opencodegui/core - @opencode-ai/sdk (OpenCode サーバー SDK) -``` - -重要な制約: **vscode パッケージは `@opencode-ai/sdk` を直接インポートしません**。SDK とのやり取りはすべてエージェントパッケージに隠蔽されています。 - ---- - -## パッケージ詳細 - -### `@opencodegui/core` - -依存ゼロの共有コントラクトパッケージ。ランタイムコードなし、型定義のみ。 - -| モジュール | 説明 | -|-----------|------| -| `domain.ts` | ドメイン型: `ChatSession`, `ChatMessage`, `ChatMessageWithParts`, `MessagePart`, `FileDiff`, `ProviderInfo`, `AgentInfo`, `TodoItem` 等 | -| `agent.interface.ts` | `IAgent` インターフェース + `AgentCapabilities` フラグ | -| `platform.interface.ts` | `IBridge`(UI-ホスト間通信)、`IPlatformServices`(プラットフォーム操作) | -| `protocol.ts` | `UIToHostMessage` / `HostToUIMessage` 判別共用体型 | - -### `@opencodegui/agent-opencode` - -`@opencode-ai/sdk` をラップし、`IAgent` を実装するアダプター。 - -| モジュール | 説明 | -|-----------|------| -| `opencode-agent.ts` | `IAgent` を実装する `OpenCodeAgent` クラス — ライフサイクル管理、イベント転送、全エージェント操作 | -| `mappers.ts` | SDK 型 → core ドメイン型への変換関数群 (`mapSession`, `mapMessage`, `mapParts` 等) | - -### `@opencodegui/vscode` - -Extension Host プロセスと React Webview の両方を含む VS Code 拡張機能。 - -| モジュール | レイヤー | 説明 | -|-----------|---------|------| -| `src/extension.ts` | Extension Host | エントリーポイント — `OpenCodeAgent`、`VscodePlatformServices` を作成し `ChatViewProvider` を登録 | -| `src/chat-view-provider.ts` | Extension Host | Webview とエージェント/プラットフォームサービス間のメッセージルーター(28以上のハンドラー) | -| `src/vscode-platform-services.ts` | Extension Host | VS Code API を使用した `IPlatformServices` 実装 | -| `webview/bridges/VscodeBridge.ts` | Webview | `acquireVsCodeApi()` をラップする `IBridge` 実装 | -| `webview/App.tsx` | Webview | ルート React コンポーネント | -| `webview/contexts/` | Webview | React コンテキストプロバイダー | -| `webview/hooks/` | Webview | カスタム React フック | -| `webview/components/` | Webview | UI コンポーネント (atoms / molecules / organisms) | - ---- - -## 主要インターフェース - -### IAgent - -AI コーディングエージェントバックエンドの中心的な抽象化。ケイパビリティ駆動設計により、エージェントがサポートする機能に応じて UI が適応します。 - -```typescript -interface IAgent { - getCapabilities(): AgentCapabilities; - - // ライフサイクル - connect(): Promise; - disconnect(): void; - onEvent(handler: (event: AgentEvent) => void): Disposable; - - // セッション - listSessions(): Promise; - createSession(title?: string): Promise; - getSession(id: string): Promise; - deleteSession(id: string): Promise; - forkSession(sessionId: string, messageId?: string): Promise; - // ... revert, unrevert, summarize, share, unshare - - // メッセージ - getMessages(sessionId: string): Promise; - sendMessage(sessionId: string, text: string, options?: SendMessageOptions): Promise; - abortSession(sessionId: string): Promise; - - // プロバイダーとモデル - getProviders(): Promise<{ providers: ProviderInfo[]; default: Record }>; - - // ツール、設定、MCP 等 - getToolIds(): Promise; - setModel?(model: string): Promise; -} -``` - -### AgentCapabilities - -各エージェント実装が宣言する機能フラグ。UI はこれを読み取って機能の表示/非表示を切り替えます。 - -```typescript -type AgentCapabilities = { - sessionDelete: boolean; // セッション削除 - sessionFork: boolean; // セッション分岐(任意のメッセージからブランチ) - sessionRevert: boolean; // セッション巻き戻し / 巻き戻し解除(Undo / Redo) - sessionShare: boolean; // セッション共有(URL 生成) - sessionSummarize: boolean; // セッション要約 / コンテキスト圧縮 - sessionDiff: boolean; // セッション単位のファイル差分 - todo: boolean; // Todo 管理 - multiProvider: boolean; // マルチプロバイダーモデル選択 - permission: boolean; // パーミッション管理(ツール実行承認フロー) - mcp: boolean; // MCP (Model Context Protocol) サポート - subAgent: boolean; // サブエージェント(子セッション) - shell: boolean; // シェルコマンド実行 - config: boolean; // 設定管理 API -}; -``` - -### IBridge - -Webview(React)とホストプロセス間の通信チャネル。 - -```typescript -interface IBridge { - postMessage(message: UIToHostMessage): void; - onMessage(handler: (message: HostToUIMessage) => void): Disposable; - getPersistedState(): UIPersistedState | null; - setPersistedState(state: UIPersistedState): void; -} -``` - -### IPlatformServices - -Extension Host から抽出されたプラットフォーム固有の操作。 - -```typescript -interface IPlatformServices { - openDiffEditor(filePath: string, before: string, after: string): Promise; - copyToClipboard(text: string): Promise; - openTerminal(serverUrl: string, sessionId?: string): Promise; - openConfigFile(filePath: string): Promise; - searchWorkspaceFiles(query: string): Promise; - getOpenEditors(): Promise; -} -``` - ---- - -## メッセージプロトコル - -Webview と Extension Host 間の通信は型付き判別共用体を使用します。 - -### UI -> Host (`UIToHostMessage`) - -| タイプ | 説明 | -|-------|------| -| `ready` | Webview の初期化完了 | -| `createSession` | 新規チャットセッション作成 | -| `selectSession` | アクティブセッションの切り替え | -| `deleteSession` | セッション削除 | -| `sendMessage` | エージェントへのユーザーメッセージ送信 | -| `abortSession` | 進行中の生成をキャンセル | -| `setModel` | AI モデルの変更 | -| `compressSession` | コンテキストの要約/圧縮 | -| `undoSession` / `redoSession` | セッション状態の Undo/Redo | -| `forkSession` | メッセージからの分岐 | -| `shareSession` / `unshareSession` | セッションの共有/共有解除 | -| `replyPermission` | ツール実行パーミッションへの応答 | -| `openDiff` | Diff ビューアを開く | -| `copyToClipboard` | テキストをクリップボードにコピー | -| `openTerminal` | エージェント用ターミナルを開く | -| `searchFiles` | ワークスペースファイル検索 | -| `getOpenEditors` | 開いているエディタファイルの取得 | -| `openConfig` | 設定ファイルを開く | -| `revertToMessage` | 特定メッセージへの巻き戻し(レガシー) | - -### Host -> UI (`HostToUIMessage`) - -| タイプ | 説明 | -|-------|------| -| `init` | 初期状態(ケイパビリティ、ロケール、パス、ツール) | -| `sessions` | セッション一覧 | -| `session` | 単一セッションの更新 | -| `messages` | セッションのメッセージ群 | -| `event` | リアルタイムエージェントイベント(ストリーミングトークン、ツール呼び出し等) | -| `providers` | 利用可能なモデルプロバイダー | -| `allProviders` | 全プロバイダーデータ | -| `agents` | 利用可能なサブエージェント | -| `childSessions` | 親セッションの子セッション | -| `diff` | セッションのファイル差分 | -| `todos` | セッションの Todo アイテム | -| `mcpStatus` | MCP 接続状態 | -| `toolIds` | 利用可能なツール識別子 | -| `searchResults` | ファイル検索結果 | -| `openEditors` | 現在開いているエディタファイル | -| `activeEditor` | フォーカス中のエディタ変更通知 | - ---- - -## データフロー - -``` -[Webview (React)] - | - | UIToHostMessage (IBridge.postMessage 経由) - v -[ChatViewProvider] -- メッセージルーター (message.type で switch) - | | - | エージェント操作 | プラットフォーム操作 - v v -[IAgent] [IPlatformServices] - | | - v v -[OpenCodeAgent] [VscodePlatformServices] - | | - v v -[@opencode-ai/sdk] [VS Code API] -``` - -### イベントフロー (エージェント -> UI) - -``` -[@opencode-ai/sdk] -- SSE イベント - | - v -[OpenCodeAgent.onEvent()] -- SDK イベントを AgentEvent にマッピング - | - v -[ChatViewProvider] -- 登録済みハンドラー - | - | HostToUIMessage (webview.postMessage 経由) - v -[Webview (React)] -- AppContext がフックにディスパッチ -``` - ---- - -## 拡張機能のライフサイクル - -1. VS Code が拡張機能をアクティベート (`extension.ts:activate`) -2. `OpenCodeAgent` を作成(モジュールスコープのシングルトン) -3. `VscodePlatformServices` を作成 -4. `ChatViewProvider` をエージェントとプラットフォームサービスの両方で登録 -5. Webview パネルが開いた時: - - React アプリがマウントされ、`ready` メッセージを送信 - - `ChatViewProvider` が `ready` を処理: `agent.connect()` を呼び出し、セッションを読み込み、`init` メッセージを送信 - - エージェントが OpenCode サーバー (localhost HTTP) に接続 - - エージェントイベントが `HostToUIMessage` 経由で Webview に転送される - ---- - -## ビルドシステム - -| コンポーネント | ツール | 設定 | -|-------------|-------|------| -| Core 型定義 | TypeScript (tsc) | `packages/core/tsconfig.json` (composite, declaration) | -| Agent-OpenCode | TypeScript (tsc) | `packages/agents/opencode/tsconfig.json` (composite, declaration) | -| Extension Host | esbuild | `packages/platforms/vscode/esbuild.mjs` | -| Webview (React) | Vite | `packages/platforms/vscode/vite.config.ts` | -| リンティング | Biome | `biome.json` (ルート) | - -### ビルド順序 - -``` -pnpm -r build - 1. @opencodegui/core (tsc) - 2. @opencodegui/agent-opencode (tsc、core に依存) - 3. @opencodegui/vscode (esbuild + vite、core + agent に依存) -``` - ---- - -## テスト構造 - -| スイート | ランナー | 設定 | テスト数 | -|---------|---------|------|---------| -| Agent-OpenCode | Vitest | `packages/agents/opencode/vitest.config.ts` | 85 | -| Webview | Vitest + jsdom | `packages/platforms/vscode/vitest.config.ts` | 1475 | -| Extension Host | Vitest | `packages/platforms/vscode/vitest.config.ext.ts` | 54 | -| **合計** | | `pnpm test:all` | **1614** | - -### Extension Host テストの注意点 - -- `vscode` モジュールは `vi.mock("vscode")` で完全にモック化(`src/__tests__/mocks/vscode.ts` 参照) -- モジュールスコープのシングルトン(例: `extension.ts` の `OpenCodeAgent`)はテスト分離のため `vi.resetModules()` + `vi.doMock()` + 動的 `import()` パターンが必要 -- 設定ファイルの読み書きテストでは `node:fs/promises` をモック化 - ---- - -## 新しいエージェントの追加方法 - -新しい AI コーディングエージェント(例: Claude Code, Codex)を追加する場合: - -1. `packages/agents//` を作成 -2. 適切な `AgentCapabilities` で `IAgent` インターフェースを実装 -3. エージェントの SDK 型から core ドメイン型へのマッパー関数を作成 -4. vscode パッケージの依存に `@opencodegui/agent-: workspace:*` を追加 -5. `extension.ts` を更新して新しいエージェントを作成(またはエージェント選択ロジックを追加) -6. UI は `AgentCapabilities` フラグにより自動的に適応 - -## 新しいプラットフォームの追加方法 - -新しいプラットフォーム(例: Electron, Web)を追加する場合: - -1. `packages/platforms//` を作成 -2. プラットフォームの UI-ホスト間通信用に `IBridge` を実装 -3. プラットフォーム固有の操作用に `IPlatformServices` を実装 -4. メッセージルーター(`ChatViewProvider` 相当)で `IAgent` と `IPlatformServices` を接続 -5. Webview の React コードは core プロトコル型を通じて共有可能 +# Architecture + +OpenCodeGUI is a single VS Code extension package. The extension host starts an +OpenCode server through `@opencode-ai/sdk`, forwards SDK events to the webview, +and handles VS Code-specific operations such as opening files, terminals, and +diff editors. + +## Structure + +``` +extension/ + extension.ts VS Code activation entry point + chat-view-provider.ts Webview message router + opencode-client-handle.ts OpenCode client lifecycle + vscode-platform-services.ts + VS Code API helpers + __tests__/ Extension host tests +shared/ + domain.ts Shared session/message/tool/config types + protocol.ts Webview <-> extension host messages +webview/ + App.tsx React state and event handling + components/ UI components + hooks/ React hooks + contexts/ React contexts + locales/ Localization dictionaries + utils/ UI utilities + __tests__/ Webview tests +``` + +## Data Flow + +1. `extension.ts` creates `OpenCodeClientHandle` and calls `connect()`. +2. `OpenCodeClientHandle` starts the OpenCode server, creates the SDK client, and + subscribes to SDK events. +3. `ChatViewProvider` receives messages from the webview and calls + the OpenCode SDK client or `VscodePlatformServices` directly. +4. SDK events are forwarded to the webview as `HostToUIMessage`. +5. The webview updates React state from host messages and sends user actions + back as `UIToHostMessage`. + +## Build And Test + +- Extension host bundle: `npm run build:extension` +- Webview bundle: `npm run build:webview` +- Full build: `npm run build` +- Webview tests: `npm test` +- Extension host tests: `npm run test:extension` +- All tests: `npm run test:all` diff --git a/packages/platforms/vscode/esbuild.mjs b/esbuild.mjs similarity index 86% rename from packages/platforms/vscode/esbuild.mjs rename to esbuild.mjs index 47d2c8f..cf8ab7b 100644 --- a/packages/platforms/vscode/esbuild.mjs +++ b/esbuild.mjs @@ -4,10 +4,13 @@ const watch = process.argv.includes("--watch"); /** @type {esbuild.BuildOptions} */ const buildOptions = { - entryPoints: ["src/extension.ts"], + entryPoints: ["extension/extension.ts"], bundle: true, outfile: "dist/extension.js", external: ["vscode"], + alias: { + "@shared": "./shared/index.ts", + }, format: "cjs", platform: "node", target: "node22", diff --git a/packages/platforms/vscode/src/__tests__/chat-view-provider.test.ts b/extension/__tests__/chat-panel.test.ts similarity index 73% rename from packages/platforms/vscode/src/__tests__/chat-view-provider.test.ts rename to extension/__tests__/chat-panel.test.ts index de2bd9a..516c2da 100644 --- a/packages/platforms/vscode/src/__tests__/chat-view-provider.test.ts +++ b/extension/__tests__/chat-panel.test.ts @@ -1,6 +1,6 @@ /** - * ChatViewProvider のユニットテスト。 - * IAgent をモックし、webview メッセージハンドラの振る舞いを検証する。 + * ChatPanel のユニットテスト。 + * OpenCodeClientHandle をモックし、webview メッセージハンドラの振る舞いを検証する。 */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -12,35 +12,26 @@ vi.mock("node:fs/promises", () => ({ })); import * as fs from "node:fs/promises"; -import type { IAgent, IPlatformServices } from "@opencodegui/core"; import * as vscode from "vscode"; -import { ChatViewProvider } from "../chat-view-provider"; -import type { DiffReviewManager } from "../diff-review-manager"; +import { ChatPanel } from "../chat-panel"; +import type { DifitHandle } from "../difit-handle"; +import type { OpenCodeClientHandle } from "../opencode-client-handle"; -// --- Helper: IAgent のモック --- +// --- Helper: OpenCodeClientHandle のモック --- -function createMockAgent(): { - [K in keyof IAgent]: IAgent[K] extends (...args: never[]) => unknown ? ReturnType : IAgent[K]; -} { - return { - getCapabilities: vi.fn().mockReturnValue({ - sessionDelete: true, - sessionFork: true, - sessionRevert: true, - sessionShare: true, - sessionSummarize: true, - sessionDiff: true, - todo: true, - multiProvider: true, - permission: true, - mcp: true, - subAgent: true, - shell: true, - config: true, - }), +type MockedMethods = { + [K in keyof T]: T[K] extends (...args: never[]) => unknown ? ReturnType : T[K]; +}; + +type MockOpenCodeClientHandle = MockedMethods & Record>; + +function createMockAgent(): MockOpenCodeClientHandle { + const api = { connect: vi.fn().mockResolvedValue(undefined), disconnect: vi.fn(), onEvent: vi.fn().mockReturnValue({ dispose: vi.fn() }), + resubscribeEvents: vi.fn().mockResolvedValue(undefined), + getClient: vi.fn(), listSessions: vi.fn().mockResolvedValue([]), createSession: vi.fn().mockResolvedValue({ id: "new-sess", title: "New" }), getSession: vi.fn().mockResolvedValue({ id: "sess-1" }), @@ -61,6 +52,8 @@ function createMockAgent(): { getSkills: vi.fn().mockResolvedValue([]), getChildSessions: vi.fn().mockResolvedValue([]), replyPermission: vi.fn().mockResolvedValue(undefined), + replyQuestion: vi.fn().mockResolvedValue(undefined), + rejectQuestion: vi.fn().mockResolvedValue(undefined), getSessionDiff: vi.fn().mockResolvedValue([]), getSessionTodos: vi.fn().mockResolvedValue([]), getConfig: vi.fn().mockResolvedValue({}), @@ -72,31 +65,122 @@ function createMockAgent(): { getToolIds: vi.fn().mockResolvedValue([]), getServerUrl: vi.fn().mockReturnValue("http://localhost:12345"), setModel: vi.fn().mockResolvedValue(undefined), - } as never; -} - -// --- Helper: IPlatformServices のモック --- + } as any; + + api.getClient.mockReturnValue({ + session: { + list: vi.fn(async () => ({ data: await api.listSessions() })), + create: vi.fn(async ({ title }: { title?: string }) => ({ data: await api.createSession(title) })), + get: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.getSession(sessionID) })), + delete: vi.fn(async ({ sessionID }: { sessionID: string }) => api.deleteSession(sessionID)), + fork: vi.fn(async ({ sessionID, messageID }: { sessionID: string; messageID?: string }) => ({ + data: await api.forkSession(sessionID, messageID), + })), + revert: vi.fn(async ({ sessionID, messageID }: { sessionID: string; messageID: string }) => ({ + data: await api.revertSession(sessionID, messageID), + })), + unrevert: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ + data: await api.unrevertSession(sessionID), + })), + summarize: vi.fn( + async ({ + sessionID, + providerID, + modelID, + }: { + sessionID: string; + providerID?: string; + modelID?: string; + }) => api.summarizeSession(sessionID, providerID && modelID ? { providerID, modelID } : undefined), + ), + share: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.shareSession(sessionID) })), + unshare: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.unshareSession(sessionID) })), + messages: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.getMessages(sessionID) })), + promptAsync: vi.fn( + async ({ + sessionID, + parts, + model, + agent: primaryAgent, + }: { + sessionID: string; + parts: Array<{ type: string; text?: string; synthetic?: boolean; url?: string; filename?: string; name?: string }>; + model?: unknown; + agent?: string; + }) => { + const textPart = parts.find((part) => part.type === "text" && !part.synthetic); + const skillPart = parts.find((part) => part.type === "text" && part.synthetic); + const fileParts = parts.filter((part) => part.type === "file"); + const agentPart = parts.find((part) => part.type === "agent"); + const options: Record = {}; + if (model !== undefined) options.model = model; + if (fileParts.length > 0) { + options.files = fileParts.map((part) => ({ + filePath: part.url?.replace("file:///workspace/", "") ?? "", + fileName: part.filename ?? "", + })); + } + if (agentPart?.name) options.agent = agentPart.name; + if (primaryAgent) options.primaryAgent = primaryAgent; + if (skillPart?.text) options.skill = skillPart.text.replace(/^\//, ""); + return api.sendMessage(sessionID, textPart?.text ?? "", options as never); + }, + ), + abort: vi.fn(async ({ sessionID }: { sessionID: string }) => api.abortSession(sessionID)), + shell: vi.fn(async ({ sessionID, command, model }: { sessionID: string; command: string; model?: unknown }) => + api.executeShell(sessionID, command, model as never), + ), + children: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.getChildSessions(sessionID) })), + todo: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.getSessionTodos(sessionID) })), + diff: vi.fn(async ({ sessionID }: { sessionID: string }) => ({ data: await api.getSessionDiff(sessionID) })), + }, + config: { + providers: vi.fn(async () => ({ data: await api.getProviders() })), + get: vi.fn(async () => ({ data: await api.getConfig() })), + update: vi.fn(async ({ config }: { config: unknown }) => api.updateConfig(config as never)), + }, + provider: { + list: vi.fn(async () => ({ data: await api.listAllProviders() })), + }, + permission: { + reply: vi.fn(async ({ requestID, reply }: { requestID: string; reply: never }) => + api.replyPermission("", requestID, reply), + ), + }, + question: { + reply: vi.fn(async ({ requestID, answers }: { requestID: string; answers: string[] }) => + api.replyQuestion(requestID, answers), + ), + reject: vi.fn(async ({ requestID }: { requestID: string }) => api.rejectQuestion(requestID)), + }, + app: { + agents: vi.fn(async () => ({ data: await api.getAgents() })), + skills: vi.fn(async () => ({ data: await api.getSkills() })), + }, + path: { + get: vi.fn(async () => ({ data: await api.getPath() })), + }, + mcp: { + status: vi.fn(async () => ({ data: await api.getMcpStatus() })), + connect: vi.fn(async ({ name }: { name: string }) => api.connectMcp(name)), + disconnect: vi.fn(async ({ name }: { name: string }) => api.disconnectMcp(name)), + }, + tool: { + ids: vi.fn(async () => ({ data: (await api.getToolIds()).map((tool: { id: string }) => tool.id) })), + }, + }); -function createMockPlatformServices(): { - [K in keyof IPlatformServices]: ReturnType; -} { - return { - openDiffEditor: vi.fn().mockResolvedValue(undefined), - copyToClipboard: vi.fn().mockResolvedValue(undefined), - openTerminal: vi.fn().mockResolvedValue(undefined), - openConfigFile: vi.fn().mockResolvedValue(undefined), - openFile: vi.fn().mockResolvedValue(undefined), - searchWorkspaceFiles: vi.fn().mockResolvedValue([]), - getOpenEditors: vi.fn().mockResolvedValue([]), - }; + return api as MockOpenCodeClientHandle; } -// --- Helper: DiffReviewManager のモック --- +// --- Helper: DifitHandle のモック --- -function createMockDiffReviewManager(): { - [K in keyof DiffReviewManager]: ReturnType; +function createMockDifitHandle(difitAvailable = false): { + [K in keyof DifitHandle]: ReturnType; } { return { + init: vi.fn().mockResolvedValue(undefined), + isAvailable: vi.fn().mockReturnValue(difitAvailable), start: vi.fn().mockResolvedValue(undefined), stop: vi.fn(), dispose: vi.fn(), @@ -149,30 +233,22 @@ function createMockWebviewView() { function setupProvider( mockAgent: ReturnType, - mockPlatformServices?: ReturnType, - mockDiffReviewManager?: ReturnType, + mockDifitHandle?: ReturnType, difitAvailable = false, ) { - const extensionUri = { fsPath: "/ext" }; - const ps = mockPlatformServices ?? createMockPlatformServices(); - const drm = mockDiffReviewManager ?? createMockDiffReviewManager(); - const provider = new ChatViewProvider( - extensionUri as never, - mockAgent as never, - ps as never, - drm as never, - difitAvailable, - ); + const extensionUri = { fsPath: "/extension" }; + const dh = mockDifitHandle ?? createMockDifitHandle(difitAvailable); + const provider = new ChatPanel(extensionUri as never, mockAgent as never, "/workspace", dh as never); const mock = createMockWebviewView(); provider.resolveWebviewView( mock.webviewView as never, {} as never, { isCancellationRequested: false, onCancellationRequested: vi.fn() } as never, ); - return { provider, platformServices: ps, diffReviewManager: drm, ...mock }; + return { provider, difitHandle: dh, ...mock }; } -describe("ChatViewProvider", () => { +describe("ChatPanel", () => { let mockAgent: ReturnType; beforeEach(() => { @@ -322,21 +398,6 @@ describe("ChatViewProvider", () => { type: "init", locale: "en", paths: { config: "/home/.config/opencode", data: "/home/.data" }, - capabilities: expect.objectContaining({ - sessionDelete: true, - sessionFork: true, - sessionRevert: true, - sessionShare: true, - sessionSummarize: true, - sessionDiff: true, - todo: true, - multiProvider: true, - permission: true, - mcp: true, - subAgent: true, - shell: true, - config: true, - }), }), ); @@ -490,7 +551,7 @@ describe("ChatViewProvider", () => { // ============================================================ describe("sendMessage", () => { - it("should call agent.sendMessage with correct args (IAgent signature)", async () => { + it("should call agent.sendMessage with correct args", async () => { const { sendMessage } = setupProvider(mockAgent); await sendMessage({ @@ -537,8 +598,9 @@ describe("ChatViewProvider", () => { // ============================================================ describe("replyPermission", () => { - it("should call agent.replyPermission with 3 args", async () => { + it("should call SDK permission.reply", async () => { const { sendMessage } = setupProvider(mockAgent); + const client = (mockAgent as any).getClient(); await sendMessage({ type: "replyPermission", @@ -547,7 +609,7 @@ describe("ChatViewProvider", () => { response: "always", }); - expect(mockAgent.replyPermission).toHaveBeenCalledWith("sess-1", "perm-1", "always"); + expect(client.permission.reply).toHaveBeenCalledWith({ requestID: "perm-1", reply: "always" }); }); }); @@ -615,17 +677,16 @@ describe("ChatViewProvider", () => { // ============================================================ describe("getOpenEditors", () => { - it("should delegate to platformServices.getOpenEditors and send result", async () => { - const mockPS = createMockPlatformServices(); - mockPS.getOpenEditors.mockResolvedValue([ - { filePath: "src/index.ts", fileName: "index.ts" }, - { filePath: "src/app.ts", fileName: "app.ts" }, - ]); + it("タブ一覧から FileAttachment[] を組み立てて postMessage する", async () => { + // workspaceFolders を設定。/workspace 以下の相対パスを取りたい。 + vi.mocked(vscode.workspace).workspaceFolders = [{ uri: { fsPath: "/workspace" } }] as never; + const tabA = { input: new vscode.TabInputText({ fsPath: "/workspace/src/index.ts", scheme: "file" } as never) }; + const tabB = { input: new vscode.TabInputText({ fsPath: "/workspace/src/app.ts", scheme: "file" } as never) }; + vi.mocked(vscode.window).tabGroups = { all: [{ tabs: [tabA, tabB] }] } as never; - const { postMessage, sendMessage } = setupProvider(mockAgent, mockPS); + const { postMessage, sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "getOpenEditors" }); - expect(mockPS.getOpenEditors).toHaveBeenCalled(); expect(postMessage).toHaveBeenCalledWith({ type: "openEditors", files: [ @@ -641,14 +702,16 @@ describe("ChatViewProvider", () => { // ============================================================ describe("searchWorkspaceFiles", () => { - it("should delegate to platformServices.searchWorkspaceFiles and send result", async () => { - const mockPS = createMockPlatformServices(); - mockPS.searchWorkspaceFiles.mockResolvedValue([{ filePath: "src/index.ts", fileName: "index.ts" }]); + it("findFiles の結果を FileAttachment[] に変換して postMessage する", async () => { + vi.mocked(vscode.workspace).workspaceFolders = [{ uri: { fsPath: "/workspace" } }] as never; + vi.mocked(vscode.workspace.findFiles).mockResolvedValueOnce([ + { fsPath: "/workspace/src/index.ts" } as never, + ]); - const { postMessage, sendMessage } = setupProvider(mockAgent, mockPS); + const { postMessage, sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "searchWorkspaceFiles", query: "index" }); - expect(mockPS.searchWorkspaceFiles).toHaveBeenCalledWith("index"); + expect(vscode.workspace.findFiles).toHaveBeenCalledWith("**/*index*", "**/node_modules/**", 20); expect(postMessage).toHaveBeenCalledWith({ type: "workspaceFiles", files: [{ filePath: "src/index.ts", fileName: "index.ts" }], @@ -724,7 +787,7 @@ describe("ChatViewProvider", () => { sessionId: "sess-1", messages: [], }); - // 3. send new message (IAgent signature with options) + // 3. send new message with options expect(mockAgent.sendMessage).toHaveBeenCalledWith("sess-1", "Updated text", { model: { providerID: "openai", modelID: "gpt-4" }, files: [{ filePath: "a.ts", fileName: "a.ts" }], @@ -752,12 +815,27 @@ describe("ChatViewProvider", () => { // ============================================================ describe("openConfigFile", () => { - it("should delegate to platformServices.openConfigFile", async () => { - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + it("既存のファイルを開く(stat 成功時は新規作成しない)", async () => { + vi.mocked(vscode.workspace.fs.stat).mockResolvedValueOnce(undefined as never); + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "openConfigFile", filePath: "/home/.config/opencode/opencode.json" }); - expect(mockPS.openConfigFile).toHaveBeenCalledWith("/home/.config/opencode/opencode.json"); + expect(vscode.workspace.fs.stat).toHaveBeenCalled(); + expect(vscode.workspace.fs.createDirectory).not.toHaveBeenCalled(); + expect(vscode.workspace.fs.writeFile).not.toHaveBeenCalled(); + expect(vscode.workspace.openTextDocument).toHaveBeenCalled(); + expect(vscode.window.showTextDocument).toHaveBeenCalled(); + }); + + it("ファイル未存在時はディレクトリ作成 + 初期内容の書き込みを行ってから開く", async () => { + vi.mocked(vscode.workspace.fs.stat).mockRejectedValueOnce(new Error("not found")); + const { sendMessage } = setupProvider(mockAgent); + await sendMessage({ type: "openConfigFile", filePath: "/home/.config/opencode/opencode.json" }); + + expect(vscode.workspace.fs.createDirectory).toHaveBeenCalled(); + expect(vscode.workspace.fs.writeFile).toHaveBeenCalled(); + expect(vscode.workspace.openTextDocument).toHaveBeenCalled(); + expect(vscode.window.showTextDocument).toHaveBeenCalled(); }); }); @@ -766,36 +844,36 @@ describe("ChatViewProvider", () => { // ============================================================ describe("openTerminal", () => { - it("should do nothing when serverUrl is undefined", async () => { + it("serverUrl が未取得なら何もしない", async () => { mockAgent.getServerUrl.mockReturnValue(undefined); - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "openTerminal" }); - expect(mockPS.openTerminal).not.toHaveBeenCalled(); + expect(vscode.window.createTerminal).not.toHaveBeenCalled(); }); - it("should delegate to platformServices.openTerminal with serverUrl", async () => { - const mockPS = createMockPlatformServices(); + it("serverUrl が取得できれば opencode attach コマンドを送る", async () => { + const sendText = vi.fn(); + vi.mocked(vscode.window.createTerminal).mockReturnValueOnce({ show: vi.fn(), sendText } as never); - const { sendMessage } = setupProvider(mockAgent, mockPS); + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "openTerminal" }); - expect(mockPS.openTerminal).toHaveBeenCalledWith("http://localhost:12345", undefined); + expect(vscode.window.createTerminal).toHaveBeenCalledWith({ name: "OpenCode", cwd: "/workspace" }); + expect(sendText).toHaveBeenCalledWith('opencode "attach" "http://localhost:12345"'); }); - it("should include sessionId when activeSession exists", async () => { - const mockPS = createMockPlatformServices(); + it("activeSession がある場合は --session も渡す", async () => { + const sendText = vi.fn(); + vi.mocked(vscode.window.createTerminal).mockReturnValueOnce({ show: vi.fn(), sendText } as never); mockAgent.createSession.mockResolvedValue({ id: "sess-1" }); - const { sendMessage } = setupProvider(mockAgent, mockPS); - // まずアクティブセッションを設定 + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "createSession" }); - await sendMessage({ type: "openTerminal" }); - expect(mockPS.openTerminal).toHaveBeenCalledWith("http://localhost:12345", "sess-1"); + expect(sendText).toHaveBeenCalledWith('opencode "attach" "http://localhost:12345" "--session" "sess-1"'); }); }); @@ -804,11 +882,16 @@ describe("ChatViewProvider", () => { // ============================================================ describe("setModel", () => { - it("should delegate to agent.setModel and send modelUpdated", async () => { + it("should update opencode config file and send modelUpdated", async () => { + vi.mocked(fs.readFile).mockResolvedValue('{"theme":"dark"}'); const { postMessage, sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "setModel", model: "anthropic/claude-4" }); - expect(mockAgent.setModel).toHaveBeenCalledWith("anthropic/claude-4"); + const writeCall = vi.mocked(fs.writeFile).mock.calls[0]; + expect(JSON.parse((writeCall[1] as string).trim())).toEqual({ + theme: "dark", + model: "anthropic/claude-4", + }); expect(postMessage).toHaveBeenCalledWith({ type: "modelUpdated", model: "anthropic/claude-4", @@ -929,27 +1012,25 @@ describe("ChatViewProvider", () => { // ============================================================ describe("shareSession", () => { - it("should update activeSession and copy share URL via platformServices", async () => { + it("activeSession を更新し share URL をクリップボードにコピーする", async () => { const session = { id: "sess-1", share: { url: "https://share.example.com/abc" } }; mockAgent.shareSession.mockResolvedValue(session); - const mockPS = createMockPlatformServices(); - const { postMessage, sendMessage } = setupProvider(mockAgent, mockPS); + const { postMessage, sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "shareSession", sessionId: "sess-1" }); expect(postMessage).toHaveBeenCalledWith({ type: "activeSession", session }); - expect(mockPS.copyToClipboard).toHaveBeenCalledWith("https://share.example.com/abc"); + expect(vscode.env.clipboard.writeText).toHaveBeenCalledWith("https://share.example.com/abc"); }); - it("should not copy to clipboard when share.url is absent", async () => { + it("share.url が無ければクリップボードにコピーしない", async () => { const session = { id: "sess-1" }; mockAgent.shareSession.mockResolvedValue(session); - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "shareSession", sessionId: "sess-1" }); - expect(mockPS.copyToClipboard).not.toHaveBeenCalled(); + expect(vscode.env.clipboard.writeText).not.toHaveBeenCalled(); }); }); @@ -1022,9 +1103,8 @@ describe("ChatViewProvider", () => { // ============================================================ describe("openDiffEditor", () => { - it("should delegate to platformServices.openDiffEditor", async () => { - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + it("vscode.diff コマンドを実行する", async () => { + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "openDiffEditor", @@ -1033,7 +1113,12 @@ describe("ChatViewProvider", () => { after: "const a = 2;", }); - expect(mockPS.openDiffEditor).toHaveBeenCalledWith("src/index.ts", "const a = 1;", "const a = 2;"); + expect(vscode.commands.executeCommand).toHaveBeenCalledWith( + "vscode.diff", + expect.objectContaining({ scheme: "opencode-diff-before" }), + expect.objectContaining({ scheme: "opencode-diff-after" }), + "index.ts (Changes)", + ); }); }); @@ -1042,29 +1127,41 @@ describe("ChatViewProvider", () => { // ============================================================ describe("openFile", () => { - it("should delegate to platformServices.openFile", async () => { - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + it("line 指定時はテキストエディタの選択範囲を更新し中央へリビールする", async () => { + const editor = { + selection: undefined as unknown, + revealRange: vi.fn(), + }; + vi.mocked(vscode.window.showTextDocument).mockResolvedValueOnce(editor as never); + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "openFile", filePath: "/home/user/project/src/main.ts", line: 42, }); - expect(mockPS.openFile).toHaveBeenCalledWith("/home/user/project/src/main.ts", 42); + expect(vscode.workspace.openTextDocument).toHaveBeenCalled(); + expect(vscode.window.showTextDocument).toHaveBeenCalled(); + expect(editor.selection).toBeInstanceOf(vscode.Selection); + expect(editor.revealRange).toHaveBeenCalled(); }); - it("should delegate to platformServices.openFile without line", async () => { - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + it("line 未指定時は選択範囲やリビールを行わない", async () => { + const editor = { + selection: undefined as unknown, + revealRange: vi.fn(), + }; + vi.mocked(vscode.window.showTextDocument).mockResolvedValueOnce(editor as never); + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "openFile", filePath: "/home/user/project/src/main.ts", }); - expect(mockPS.openFile).toHaveBeenCalledWith("/home/user/project/src/main.ts", undefined); + expect(vscode.window.showTextDocument).toHaveBeenCalled(); + expect(editor.revealRange).not.toHaveBeenCalled(); }); }); @@ -1073,13 +1170,12 @@ describe("ChatViewProvider", () => { // ============================================================ describe("copyToClipboard", () => { - it("should delegate to platformServices.copyToClipboard", async () => { - const mockPS = createMockPlatformServices(); - const { sendMessage } = setupProvider(mockAgent, mockPS); + it("クリップボードにテキストを書き込む", async () => { + const { sendMessage } = setupProvider(mockAgent); await sendMessage({ type: "copyToClipboard", text: "Hello World" }); - expect(mockPS.copyToClipboard).toHaveBeenCalledWith("Hello World"); + expect(vscode.env.clipboard.writeText).toHaveBeenCalledWith("Hello World"); }); }); @@ -1115,8 +1211,8 @@ describe("ChatViewProvider", () => { it("agent.getSessionDiff と diffReviewManager.start を呼ぶこと", async () => { const diffs = [{ file: "a.ts", before: "old", after: "new", additions: 1, deletions: 1 }]; mockAgent.getSessionDiff.mockResolvedValue(diffs); - const drm = createMockDiffReviewManager(); - const { sendMessage, postMessage } = setupProvider(mockAgent, undefined, drm); + const dh = createMockDifitHandle(); + const { sendMessage, postMessage } = setupProvider(mockAgent, dh); // activeSession を設定 const session = { id: "s1", title: "S1" }; @@ -1127,7 +1223,7 @@ describe("ChatViewProvider", () => { await sendMessage({ type: "openDiffReview" }); expect(mockAgent.getSessionDiff).toHaveBeenCalledWith("s1"); - expect(drm.start).toHaveBeenCalledWith(diffs, undefined); + expect(dh.start).toHaveBeenCalledWith(diffs, undefined); expect(postMessage).toHaveBeenCalledWith({ type: "diffReviewStarted" }); }); @@ -1135,8 +1231,8 @@ describe("ChatViewProvider", () => { it("focusFile を diffReviewManager.start に渡すこと", async () => { const diffs = [{ file: "a.ts", before: "old", after: "new", additions: 1, deletions: 1 }]; mockAgent.getSessionDiff.mockResolvedValue(diffs); - const drm = createMockDiffReviewManager(); - const { sendMessage } = setupProvider(mockAgent, undefined, drm); + const dh = createMockDifitHandle(); + const { sendMessage } = setupProvider(mockAgent, dh); const session = { id: "s1", title: "S1" }; mockAgent.createSession.mockResolvedValue(session); @@ -1145,30 +1241,30 @@ describe("ChatViewProvider", () => { await sendMessage({ type: "openDiffReview", focusFile: "a.ts" }); - expect(drm.start).toHaveBeenCalledWith(diffs, "a.ts"); + expect(dh.start).toHaveBeenCalledWith(diffs, "a.ts"); }); // should not call start when no activeSession it("activeSession がない場合は start を呼ばないこと", async () => { - const drm = createMockDiffReviewManager(); - const { sendMessage } = setupProvider(mockAgent, undefined, drm); + const dh = createMockDifitHandle(); + const { sendMessage } = setupProvider(mockAgent, dh); await sendMessage({ type: "openDiffReview" }); expect(mockAgent.getSessionDiff).not.toHaveBeenCalled(); - expect(drm.start).not.toHaveBeenCalled(); + expect(dh.start).not.toHaveBeenCalled(); }); }); describe("stopDiffReview", () => { // should call diffReviewManager.stop it("diffReviewManager.stop を呼ぶこと", async () => { - const drm = createMockDiffReviewManager(); - const { sendMessage, postMessage } = setupProvider(mockAgent, undefined, drm); + const dh = createMockDifitHandle(); + const { sendMessage, postMessage } = setupProvider(mockAgent, dh); await sendMessage({ type: "stopDiffReview" }); - expect(drm.stop).toHaveBeenCalled(); + expect(dh.stop).toHaveBeenCalled(); expect(postMessage).toHaveBeenCalledWith({ type: "diffReviewStopped" }); }); }); @@ -1180,7 +1276,7 @@ describe("ChatViewProvider", () => { describe("difitAvailable", () => { // should send difitAvailable on ready it("ready 時に difitAvailable メッセージを送信すること", async () => { - const { postMessage, sendMessage } = setupProvider(mockAgent, undefined, undefined, true); + const { postMessage, sendMessage } = setupProvider(mockAgent, undefined, true); await sendMessage({ type: "ready" }); @@ -1189,7 +1285,7 @@ describe("ChatViewProvider", () => { // should send false when difit is not available it("difit 未インストール時は available=false を送信すること", async () => { - const { postMessage, sendMessage } = setupProvider(mockAgent, undefined, undefined, false); + const { postMessage, sendMessage } = setupProvider(mockAgent, undefined, false); await sendMessage({ type: "ready" }); @@ -1204,13 +1300,12 @@ describe("ChatViewProvider", () => { describe("postMessage null safety", () => { it("should not crash when view is not set", () => { // resolveWebviewView を呼ばずに provider を作成 - const extensionUri = { fsPath: "/ext" }; - const provider = new ChatViewProvider( + const extensionUri = { fsPath: "/extension" }; + const provider = new ChatPanel( extensionUri as never, mockAgent as never, - createMockPlatformServices() as never, - createMockDiffReviewManager() as never, - false, + "/workspace", + createMockDifitHandle() as never, ); // view が undefined のまま postMessage を呼ぶ(内部的に) diff --git a/packages/platforms/vscode/src/__tests__/diff-review-manager.test.ts b/extension/__tests__/difit-handle.test.ts similarity index 65% rename from packages/platforms/vscode/src/__tests__/diff-review-manager.test.ts rename to extension/__tests__/difit-handle.test.ts index e31bae2..0f39ce1 100644 --- a/packages/platforms/vscode/src/__tests__/diff-review-manager.test.ts +++ b/extension/__tests__/difit-handle.test.ts @@ -1,6 +1,7 @@ /** - * DiffReviewManager のユニットテスト。 - * child_process.spawn をモックし、difit プロセスの起動・URL 検出・停止を検証する。 + * DifitHandle のユニットテスト。 + * child_process.spawn / execFile をモックし、 + * difit の存在確認 (init/isAvailable) と difit プロセスの起動・URL 検出・停止を検証する。 */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -9,10 +10,11 @@ vi.mock("node:child_process", () => ({ execFile: vi.fn(), })); -import { spawn } from "node:child_process"; +import { execFile, spawn } from "node:child_process"; import { EventEmitter, Readable, Writable } from "node:stream"; import * as vscode from "vscode"; -import { DiffReviewManager, fileDiffsToUnifiedDiff } from "../diff-review-manager"; +import { DifitHandle, fileDiffsToUnifiedDiff } from "../difit-handle"; +import { DifitBinaryNotFoundError, DifitError } from "../errors"; /** stdin / stdout / stderr を持つ擬似 ChildProcess を生成する */ function createMockProcess() { @@ -35,16 +37,46 @@ function createMockProcess() { return proc; } -describe("DiffReviewManager", () => { - let manager: DiffReviewManager; +describe("DifitHandle", () => { + let handle: DifitHandle; beforeEach(() => { - manager = new DiffReviewManager(); + handle = new DifitHandle(); vi.clearAllMocks(); }); afterEach(() => { - manager.dispose(); + handle.dispose(); + }); + + // ============================================================ + // init() / isAvailable() + // ============================================================ + + describe("init() / isAvailable()", () => { + it("which difit が成功すれば isAvailable は true", async () => { + vi.mocked(execFile).mockImplementationOnce(((_cmd: string, _args: string[], cb: (e: unknown) => void) => { + cb(null); + }) as never); + + await handle.init(); + + expect(handle.isAvailable()).toBe(true); + }); + + it("which difit が失敗すれば isAvailable は false", async () => { + vi.mocked(execFile).mockImplementationOnce(((_cmd: string, _args: string[], cb: (e: unknown) => void) => { + cb(new Error("not found")); + }) as never); + + await handle.init(); + + expect(handle.isAvailable()).toBe(false); + }); + + it("init() を呼ばずに isAvailable を呼んでも false(フェイルセーフ)", () => { + expect(handle.isAvailable()).toBe(false); + }); }); // ============================================================ @@ -57,7 +89,7 @@ describe("DiffReviewManager", () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([ + const startPromise = handle.start([ { file: "src/index.ts", before: "old", after: "new", additions: 1, deletions: 1 }, ]); @@ -75,7 +107,7 @@ describe("DiffReviewManager", () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start( + const startPromise = handle.start( [{ file: "src/index.ts", before: "old", after: "new", additions: 1, deletions: 1 }], "src/index.ts", ); @@ -92,7 +124,7 @@ describe("DiffReviewManager", () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([ + const startPromise = handle.start([ { file: "src/index.ts", before: "old", after: "new", additions: 1, deletions: 1 }, ]); @@ -108,7 +140,7 @@ describe("DiffReviewManager", () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([ + const startPromise = handle.start([ { file: "src/index.ts", before: "old", after: "new", additions: 1, deletions: 1 }, ]); @@ -127,39 +159,55 @@ describe("DiffReviewManager", () => { .mockReturnValueOnce(proc1 as never) .mockReturnValueOnce(proc2 as never); - const start1 = manager.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); + const start1 = handle.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); proc1.stdout.push("http://127.0.0.1:4966\n"); await start1; - const start2 = manager.start([{ file: "b.ts", before: "", after: "y", additions: 1, deletions: 0 }]); + const start2 = handle.start([{ file: "b.ts", before: "", after: "y", additions: 1, deletions: 0 }]); proc2.stdout.push("http://127.0.0.1:4967\n"); await start2; expect(proc1.kill).toHaveBeenCalled(); }); - // should reject when difit exits before emitting URL - it("URL 出力前に difit が終了した場合 reject すること", async () => { + it("URL 出力前に difit が終了した場合 DifitError で reject する(cause に元エラー)", async () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); + const startPromise = handle.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); mockProc.emit("close", 1); - await expect(startPromise).rejects.toThrow("difit exited with code 1 before emitting URL"); + const rejection = await startPromise.catch((e: unknown) => e); + expect(rejection).toBeInstanceOf(DifitError); + expect(rejection).not.toBeInstanceOf(DifitBinaryNotFoundError); + expect((rejection as DifitError).cause).toBeInstanceOf(Error); + }); + + it("spawn が ENOENT エラーを emit した場合 DifitBinaryNotFoundError で reject する", async () => { + const mockProc = createMockProcess(); + vi.mocked(spawn).mockReturnValue(mockProc as never); + + const startPromise = handle.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); + + mockProc.emit("error", Object.assign(new Error("spawn ENOENT"), { code: "ENOENT" })); + + await expect(startPromise).rejects.toBeInstanceOf(DifitBinaryNotFoundError); }); - // should reject on spawn error - it("spawn エラー時に reject すること", async () => { + it("spawn が ENOENT 以外のエラーを emit した場合 DifitError で reject する", async () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); + const startPromise = handle.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); - mockProc.emit("error", new Error("ENOENT")); + const original = new Error("EACCES"); + mockProc.emit("error", original); - await expect(startPromise).rejects.toThrow("ENOENT"); + const rejection = await startPromise.catch((e: unknown) => e); + expect(rejection).toBeInstanceOf(DifitError); + expect(rejection).not.toBeInstanceOf(DifitBinaryNotFoundError); + expect((rejection as DifitError).cause).toBe(original); }); }); @@ -173,18 +221,18 @@ describe("DiffReviewManager", () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); + const startPromise = handle.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); mockProc.stdout.push("http://127.0.0.1:4966\n"); await startPromise; - manager.stop(); + handle.stop(); expect(mockProc.kill).toHaveBeenCalled(); }); // should not throw when no process is running it("プロセスが起動していない場合でもエラーにならないこと", () => { - expect(() => manager.stop()).not.toThrow(); + expect(() => handle.stop()).not.toThrow(); }); }); @@ -198,11 +246,11 @@ describe("DiffReviewManager", () => { const mockProc = createMockProcess(); vi.mocked(spawn).mockReturnValue(mockProc as never); - const startPromise = manager.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); + const startPromise = handle.start([{ file: "a.ts", before: "", after: "x", additions: 1, deletions: 0 }]); mockProc.stdout.push("http://127.0.0.1:4966\n"); await startPromise; - manager.dispose(); + handle.dispose(); expect(mockProc.kill).toHaveBeenCalled(); }); diff --git a/packages/platforms/vscode/src/__tests__/extension.test.ts b/extension/__tests__/extension.test.ts similarity index 52% rename from packages/platforms/vscode/src/__tests__/extension.test.ts rename to extension/__tests__/extension.test.ts index d11c32a..938f1c3 100644 --- a/packages/platforms/vscode/src/__tests__/extension.test.ts +++ b/extension/__tests__/extension.test.ts @@ -1,27 +1,37 @@ /** * extension.ts (activate / deactivate) のユニットテスト。 - * ChatViewProvider と OpenCodeAgent をモックし、起動・停止の振る舞いを検証する。 + * ChatPanel と OpenCodeClientHandle をモックし、起動・停止の振る舞いを検証する。 */ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; // --- モックの準備 --- +// difit の存在確認 (`which difit`) をモックで制御する。 +// 既定では「見つかった」相当(callback に error なしで応答)にしておき、 +// 必要なテストで `mockExecFile.mockImplementationOnce(...)` で個別に上書きする。 +const mockExecFile = vi.fn((_cmd: string, _args: string[], cb: (error: unknown) => void) => { + cb(null); +}); +vi.mock("node:child_process", () => ({ + execFile: (cmd: string, args: string[], cb: (error: unknown) => void) => mockExecFile(cmd, args, cb), +})); + const mockConnect = vi.fn().mockResolvedValue(undefined); const mockDisconnect = vi.fn(); -// モジュールスコープで `new OpenCodeAgent()` が呼ばれるため、 +// モジュールスコープで `new OpenCodeClientHandle()` が呼ばれるため、 // コンストラクタとして機能するクラスを返す必要がある。 function createMockAgentClass() { - return class MockOpenCodeAgent { + return class MockOpenCodeClientHandle { connect = mockConnect; disconnect = mockDisconnect; workspaceFolder: string | undefined = undefined; }; } -// ChatViewProvider のモック — コンストラクタとして使われる -function createMockChatViewProviderClass() { - return Object.assign(class MockChatViewProvider {}, { viewType: "opencode.chatView" }); +// ChatPanel のモック — コンストラクタとして使われる +function createMockChatPanelClass() { + return Object.assign(class MockChatPanel {}, { viewType: "opencode.chatView" }); } import * as vscode from "vscode"; @@ -48,17 +58,17 @@ describe("extension", () => { }); /** - * extension.ts はモジュールスコープで `new OpenCodeAgent()` を実行する。 + * extension.ts はモジュールスコープで `new OpenCodeClientHandle()` を実行する。 * テストごとに新しいモジュールインスタンスが必要なので、毎回 resetModules して再 import する。 */ async function importExtension() { vi.resetModules(); - vi.doMock("@opencodegui/agent-opencode", () => ({ - OpenCodeAgent: createMockAgentClass(), + vi.doMock("../opencode-client-handle", () => ({ + OpenCodeClientHandle: createMockAgentClass(), })); - vi.doMock("../chat-view-provider", () => ({ - ChatViewProvider: createMockChatViewProviderClass(), + vi.doMock("../chat-panel", () => ({ + ChatPanel: createMockChatPanelClass(), })); return import("../extension"); @@ -70,14 +80,14 @@ describe("extension", () => { describe("activate() - normal", () => { it("should connect, register webview provider and diff providers", async () => { - const ext = await importExtension(); + const extensionModule = await importExtension(); const subscriptions: { dispose: () => void }[] = []; const context = { - extensionUri: { fsPath: "/ext" }, + extensionUri: { fsPath: "/extension" }, subscriptions, }; - await ext.activate(context as never); + await extensionModule.activate(context as never); // connect が呼ばれた expect(mockConnect).toHaveBeenCalled(); @@ -101,10 +111,10 @@ describe("extension", () => { }); it("should change cwd to workspace folder and restore it", async () => { - const ext = await importExtension(); - const context = { extensionUri: { fsPath: "/ext" }, subscriptions: [] }; + const extensionModule = await importExtension(); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; - await ext.activate(context as never); + await extensionModule.activate(context as never); // chdir が workspaceFolder で呼ばれ、その後元に戻されること const chdirCalls = chdirSpy.mock.calls.map((c: string[]) => c[0]); @@ -121,10 +131,10 @@ describe("extension", () => { describe("activate() - no workspace", () => { it("should show warning and return early", async () => { vi.mocked(vscode.workspace).workspaceFolders = undefined as never; - const ext = await importExtension(); - const context = { extensionUri: { fsPath: "/ext" }, subscriptions: [] }; + const extensionModule = await importExtension(); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; - await ext.activate(context as never); + await extensionModule.activate(context as never); expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(expect.stringContaining("workspace")); expect(mockConnect).not.toHaveBeenCalled(); @@ -132,35 +142,72 @@ describe("extension", () => { }); // ============================================================ - // activate - ENOENT エラー(opencode コマンドが見つからない) + // activate - opencode バイナリ未検出 // ============================================================ - describe("activate() - ENOENT error", () => { - it("should show warning for ENOENT code", async () => { - const error = new Error("spawn opencode ENOENT") as NodeJS.ErrnoException; - error.code = "ENOENT"; - mockConnect.mockRejectedValueOnce(error); + describe("activate() - OpenCodeBinaryNotFoundError", () => { + it("OpenCodeBinaryNotFoundError を受けたら警告を表示し webview を登録しない", async () => { + // importExtension() 内で vi.resetModules() が走るため、 + // 同一クラス識別子になるよう importExtension() の後で errors を読み込む。 + const extensionModule = await importExtension(); + const { OpenCodeBinaryNotFoundError } = await import("../errors"); + mockConnect.mockRejectedValueOnce(new OpenCodeBinaryNotFoundError(new Error("spawn opencode ENOENT"))); - const ext = await importExtension(); - const context = { extensionUri: { fsPath: "/ext" }, subscriptions: [] }; + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; - await ext.activate(context as never); + await extensionModule.activate(context as never); expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(expect.stringContaining("opencode")); - // webview provider が登録されない expect(vscode.window.registerWebviewViewProvider).not.toHaveBeenCalled(); }); - it("should show warning for ENOENT in message", async () => { - const error = new Error("ENOENT: command not found"); - mockConnect.mockRejectedValueOnce(error); + it("汎用 OpenCodeError を受けたらエラー通知 + ログ出力し webview を登録しない", async () => { + const extensionModule = await importExtension(); + const { OpenCodeError } = await import("../errors"); + const original = new Error("port already in use"); + mockConnect.mockRejectedValueOnce(new OpenCodeError(original)); - const ext = await importExtension(); - const context = { extensionUri: { fsPath: "/ext" }, subscriptions: [] }; + const consoleErrorSpy = vi.spyOn(console, "error").mockImplementation(() => {}); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; - await ext.activate(context as never); + await extensionModule.activate(context as never); - expect(vscode.window.showWarningMessage).toHaveBeenCalledWith(expect.stringContaining("opencode")); + expect(vscode.window.showErrorMessage).toHaveBeenCalled(); + // OpenCodeError をそのまま console.error に渡す(cause は error 自身に含まれる)。 + expect(consoleErrorSpy).toHaveBeenCalledWith(expect.any(Error)); + expect(consoleErrorSpy.mock.calls[0]?.[0]).toMatchObject({ cause: original }); + expect(vscode.window.registerWebviewViewProvider).not.toHaveBeenCalled(); + + consoleErrorSpy.mockRestore(); + }); + }); + + // ============================================================ + // activate - difit の有無による分岐 + // ============================================================ + + describe("activate() - difit availability", () => { + it("difit が見つからない場合は info メッセージを表示する", async () => { + // `which difit` が失敗(exit code 非 0)した状況を模す。 + mockExecFile.mockImplementationOnce((_cmd, _args, cb) => cb(new Error("not found"))); + + const extensionModule = await importExtension(); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; + + await extensionModule.activate(context as never); + + expect(vscode.window.showInformationMessage).toHaveBeenCalledWith(expect.stringContaining("difit")); + }); + + it("difit が見つかった場合は info メッセージを表示しない", async () => { + mockExecFile.mockImplementationOnce((_cmd, _args, cb) => cb(null)); + + const extensionModule = await importExtension(); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; + + await extensionModule.activate(context as never); + + expect(vscode.window.showInformationMessage).not.toHaveBeenCalled(); }); }); @@ -173,10 +220,10 @@ describe("extension", () => { const error = new Error("Connection refused"); mockConnect.mockRejectedValueOnce(error); - const ext = await importExtension(); - const context = { extensionUri: { fsPath: "/ext" }, subscriptions: [] }; + const extensionModule = await importExtension(); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; - await expect(ext.activate(context as never)).rejects.toThrow("Connection refused"); + await expect(extensionModule.activate(context as never)).rejects.toThrow("Connection refused"); }); }); @@ -186,9 +233,9 @@ describe("extension", () => { describe("deactivate()", () => { it("should call agent.disconnect()", async () => { - const ext = await importExtension(); + const extensionModule = await importExtension(); - ext.deactivate(); + extensionModule.deactivate(); expect(mockDisconnect).toHaveBeenCalled(); }); @@ -200,9 +247,9 @@ describe("extension", () => { describe("diff content provider", () => { it("should decode URI query to provide document content", async () => { - const ext = await importExtension(); - const context = { extensionUri: { fsPath: "/ext" }, subscriptions: [] }; - await ext.activate(context as never); + const extensionModule = await importExtension(); + const context = { extensionUri: { fsPath: "/extension" }, subscriptions: [] }; + await extensionModule.activate(context as never); // registerTextDocumentContentProvider に渡されたプロバイダーを取得 const registerCalls = vi.mocked(vscode.workspace.registerTextDocumentContentProvider).mock.calls; diff --git a/extension/__tests__/i18n.test.ts b/extension/__tests__/i18n.test.ts new file mode 100644 index 0000000..b319111 --- /dev/null +++ b/extension/__tests__/i18n.test.ts @@ -0,0 +1,38 @@ +/** + * i18n モジュールのユニットテスト。 + * `t()` が source.ts の英文を引いて vscode.l10n.t に渡し、 + * バンドルヒット時は翻訳、未ヒット時は英文へフォールバックすることを検証する。 + */ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import * as vscode from "vscode"; +import { I18nKeyNotFoundError, type MessageKey, t } from "../i18n"; +import { messages } from "../i18n/source"; + +describe("t", () => { + beforeEach(() => { + // 既定のモック: 入力をそのまま返す(= バンドル未ヒット相当)。 + // l10n.t は複数のオーバーロードを持つため as never 経由で差し替える。 + vi.mocked(vscode.l10n.t).mockImplementation(((s: string) => s) as never); + }); + + it("source.ts に定義された英文を vscode.l10n.t に渡す", () => { + const result = t("warnings.noWorkspace"); + expect(vscode.l10n.t).toHaveBeenCalledWith(messages.warnings.noWorkspace); + expect(result).toBe(messages.warnings.noWorkspace); + }); + + it("vscode.l10n.t が翻訳を返した場合はその翻訳を返す(バンドルヒット)", () => { + vi.mocked(vscode.l10n.t).mockReturnValueOnce("ワークスペースを開いてください。"); + expect(t("warnings.noWorkspace")).toBe("ワークスペースを開いてください。"); + }); + + it("vscode.l10n.t が引数をそのまま返した場合は英文フォールバックになる", () => { + expect(t("warnings.opencodeNotFound")).toBe(messages.warnings.opencodeNotFound); + }); + + it("source.ts に存在しないキーが渡された場合は I18nKeyNotFoundError を投げる", () => { + // 通常は MessageKey 型で弾かれる経路。型キャストでバイパスして検証する。 + expect(() => t("warnings.unknown" as MessageKey)).toThrow(I18nKeyNotFoundError); + expect(() => t("nonexistent.key" as MessageKey)).toThrow(/i18n のソースにキーが存在しません/); + }); +}); diff --git a/packages/platforms/vscode/src/__tests__/mocks/vscode.ts b/extension/__tests__/mocks/vscode.ts similarity index 84% rename from packages/platforms/vscode/src/__tests__/mocks/vscode.ts rename to extension/__tests__/mocks/vscode.ts index 9402ebd..2ba90dc 100644 --- a/packages/platforms/vscode/src/__tests__/mocks/vscode.ts +++ b/extension/__tests__/mocks/vscode.ts @@ -22,6 +22,8 @@ export const workspace = { export const window = { registerWebviewViewProvider: vi.fn(() => ({ dispose: vi.fn() })), showWarningMessage: vi.fn(), + showErrorMessage: vi.fn(), + showInformationMessage: vi.fn(), showTextDocument: vi.fn().mockResolvedValue(undefined), activeTextEditor: undefined as unknown, onDidChangeActiveTextEditor: vi.fn(() => ({ dispose: vi.fn() })), @@ -104,3 +106,32 @@ export const ViewColumn = { Two: 2, Three: 3, }; + +// --- Position / Selection / Range / TextEditorRevealType --- +export class Position { + constructor( + public line: number, + public character: number, + ) {} +} + +export class Selection { + constructor( + public anchor: Position, + public active: Position, + ) {} +} + +export class Range { + constructor( + public start: Position, + public end: Position, + ) {} +} + +export const TextEditorRevealType = { + Default: 0, + InCenter: 1, + InCenterIfOutsideViewport: 2, + AtTop: 3, +}; diff --git a/extension/__tests__/opencode-client-handle.test.ts b/extension/__tests__/opencode-client-handle.test.ts new file mode 100644 index 0000000..a7f1ebd --- /dev/null +++ b/extension/__tests__/opencode-client-handle.test.ts @@ -0,0 +1,206 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +function createMockSdkClient() { + return { + event: { + subscribe: vi.fn().mockResolvedValue({ + stream: (async function* () { + // default empty stream + })(), + }), + }, + }; +} + +let mockClient: ReturnType; +const mockServerClose = vi.fn(); + +vi.mock("@opencode-ai/sdk/v2", () => ({ + createOpencodeServer: vi.fn().mockImplementation(() => + Promise.resolve({ + url: "http://localhost:12345", + close: mockServerClose, + }), + ), + createOpencodeClient: vi.fn().mockImplementation(() => mockClient), +})); + +import { createOpencodeClient, createOpencodeServer } from "@opencode-ai/sdk/v2"; +import { OpenCodeBinaryNotFoundError, OpenCodeClientNotConnectedError, OpenCodeError } from "../errors"; +import { OpenCodeClientHandle } from "../opencode-client-handle"; + +describe("OpenCodeClientHandle", () => { + let handle: OpenCodeClientHandle; + + beforeEach(() => { + mockClient = createMockSdkClient(); + vi.mocked(createOpencodeClient).mockReturnValue(mockClient as never); + handle = new OpenCodeClientHandle(); + }); + + afterEach(() => { + handle.disconnect(); + vi.clearAllMocks(); + }); + + describe("connect()", () => { + it("creates an OpenCode server on a free port and creates an SDK client", async () => { + await handle.connect(); + + expect(createOpencodeServer).toHaveBeenCalledWith({ port: 0 }); + expect(createOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://localhost:12345" }); + expect(handle.getClient()).toBe(mockClient); + expect(handle.getServerUrl()).toBe("http://localhost:12345"); + }); + + it("subscribes to SDK events after connecting", async () => { + await handle.connect(); + + expect(mockClient.event.subscribe).toHaveBeenCalled(); + }); + + it("createOpencodeServer が ENOENT を投げた場合は OpenCodeBinaryNotFoundError に変換する", async () => { + const enoent = Object.assign(new Error("spawn opencode ENOENT"), { code: "ENOENT" }); + vi.mocked(createOpencodeServer).mockRejectedValueOnce(enoent); + + await expect(handle.connect()).rejects.toBeInstanceOf(OpenCodeBinaryNotFoundError); + }); + + it("code が落ちていても message に ENOENT を含めば OpenCodeBinaryNotFoundError に変換する", async () => { + // SDK 側でラップされて code フィールドが失われるケースを再現する。 + vi.mocked(createOpencodeServer).mockRejectedValueOnce(new Error("Failed to spawn: ENOENT")); + + await expect(handle.connect()).rejects.toBeInstanceOf(OpenCodeBinaryNotFoundError); + }); + + it("ENOENT 以外のエラーは OpenCodeError でラップされ、cause に元エラーを保持する", async () => { + const original = new Error("port already in use"); + vi.mocked(createOpencodeServer).mockRejectedValueOnce(original); + + const rejection = await handle.connect().catch((e: unknown) => e); + + expect(rejection).toBeInstanceOf(OpenCodeError); + // ラップ後はサブクラスではなく基底の OpenCodeError として投げられる。 + expect(rejection).not.toBeInstanceOf(OpenCodeBinaryNotFoundError); + expect((rejection as OpenCodeError).cause).toBe(original); + }); + + it("OpenCodeBinaryNotFoundError も OpenCodeError として識別できる(基底クラスでまとめて catch 可能)", async () => { + const enoent = Object.assign(new Error("spawn opencode ENOENT"), { code: "ENOENT" }); + vi.mocked(createOpencodeServer).mockRejectedValueOnce(enoent); + + await expect(handle.connect()).rejects.toBeInstanceOf(OpenCodeError); + }); + }); + + describe("disconnect()", () => { + it("closes the server and clears client state", async () => { + await handle.connect(); + + handle.disconnect(); + + expect(mockServerClose).toHaveBeenCalled(); + expect(handle.getServerUrl()).toBeUndefined(); + expect(() => handle.getClient()).toThrow(OpenCodeClientNotConnectedError); + expect(() => handle.getClient()).toThrow( + "OpenCode クライアントが接続されていません。先に connect() を呼び出してください。", + ); + }); + + it("is idempotent", () => { + expect(() => handle.disconnect()).not.toThrow(); + }); + }); + + describe("events", () => { + it("delivers SSE events to listeners", async () => { + const events = [ + { type: "session.updated", properties: { id: "sess-1" } }, + { type: "message.created", properties: { id: "msg-1" } }, + ]; + let resolveStream!: () => void; + const streamDone = new Promise((resolve) => { + resolveStream = resolve; + }); + + mockClient.event.subscribe.mockResolvedValue({ + stream: (async function* () { + for (const event of events) { + yield event; + } + resolveStream(); + })(), + }); + + const listener = vi.fn(); + handle.onEvent(listener); + await handle.connect(); + await streamDone; + await new Promise((resolve) => setTimeout(resolve, 0)); + + expect(listener).toHaveBeenCalledTimes(2); + expect(listener).toHaveBeenCalledWith(events[0]); + expect(listener).toHaveBeenCalledWith(events[1]); + }); + + it("removes listeners when their disposable is disposed", async () => { + let emitEvent: ((event: unknown) => void) | undefined; + let endStream: (() => void) | undefined; + + mockClient.event.subscribe.mockResolvedValue({ + stream: (async function* () { + const queue: unknown[] = []; + let resolve: (() => void) | undefined; + let done = false; + + emitEvent = (event: unknown) => { + queue.push(event); + resolve?.(); + }; + endStream = () => { + done = true; + resolve?.(); + }; + + while (!done) { + if (queue.length > 0) { + const next = queue.shift(); + if (next !== undefined) { + yield next; + } + } else { + await new Promise((r) => { + resolve = r; + }); + } + } + })(), + }); + + await handle.connect(); + const listener = vi.fn(); + const disposable = handle.onEvent(listener); + + emitEvent?.({ type: "test-event-1" }); + await new Promise((resolve) => setTimeout(resolve, 10)); + expect(listener).toHaveBeenCalledTimes(1); + + disposable.dispose(); + emitEvent?.({ type: "test-event-2" }); + await new Promise((resolve) => setTimeout(resolve, 10)); + expect(listener).toHaveBeenCalledTimes(1); + + endStream?.(); + }); + + it("resubscribes by aborting the previous stream and creating a new subscription", async () => { + await handle.connect(); + + expect(mockClient.event.subscribe).toHaveBeenCalledTimes(1); + + await handle.resubscribeEvents(); + + expect(mockClient.event.subscribe).toHaveBeenCalledTimes(2); + }); + }); +}); diff --git a/packages/platforms/vscode/src/__tests__/setup.ts b/extension/__tests__/setup.ts similarity index 100% rename from packages/platforms/vscode/src/__tests__/setup.ts rename to extension/__tests__/setup.ts diff --git a/extension/chat-handlers/context.ts b/extension/chat-handlers/context.ts new file mode 100644 index 0000000..40a385a --- /dev/null +++ b/extension/chat-handlers/context.ts @@ -0,0 +1,27 @@ +import type { OpencodeClient } from "@opencode-ai/sdk/v2"; +import type { ChatSession, HostToUIMessage, UIToHostMessage } from "@shared"; +import type { DifitHandle } from "../difit-handle"; +import type { OpenCodeClientHandle } from "../opencode-client-handle"; + +/** + * 個別のメッセージハンドラーが共通で使うコンテキスト。 + * `ChatPanel.handleWebviewMessageInner` がリクエストごとに組み立てて渡す。 + */ +export interface ChatHandlerContext { + /** 接続済みの OpenCode SDK クライアント。 */ + readonly client: OpencodeClient; + /** OpenCode サーバーの URL 取得など、クライアント以外の用途用。 */ + readonly openCodeClientHandle: OpenCodeClientHandle; + readonly difitHandle: DifitHandle; + /** path 解決などで使うワークスペースフォルダの絶対パス。 */ + readonly workspaceFolder: string; + /** Webview にメッセージを送信する。 */ + postMessage(message: HostToUIMessage): void; + /** UI 側で持つ「現在アクティブなセッション」状態の取得。 */ + getActiveSession(): ChatSession | null; + /** UI 側で持つ「現在アクティブなセッション」状態の更新。 */ + setActiveSession(session: ChatSession | null): void; +} + +/** `UIToHostMessage` の中から特定 `type` のメッセージだけを取り出すユーティリティ型。 */ +export type Msg = Extract; diff --git a/extension/chat-handlers/init.ts b/extension/chat-handlers/init.ts new file mode 100644 index 0000000..bf91278 --- /dev/null +++ b/extension/chat-handlers/init.ts @@ -0,0 +1,50 @@ +import * as fs from "node:fs/promises"; +import * as path from "node:path"; +import type { AllProvidersData, AppPaths, ChatSession, ProviderInfo } from "@shared"; +import * as vscode from "vscode"; +import type { ChatHandlerContext } from "./context"; +import { getActiveEditorFile } from "./utils"; + +/** + * Webview の初期化完了通知に応じて、UI が起動時に必要とする情報を一括送信する。 + */ +export async function ready(ctx: ChatHandlerContext): Promise { + const { client, postMessage } = ctx; + + const paths = (await client.path.get()).data! as unknown as AppPaths; + postMessage({ + type: "init", + locale: vscode.env.language, + paths, + }); + + const sessions = (await client.session.list()).data! as unknown as ChatSession[]; + postMessage({ type: "sessions", sessions }); + postMessage({ type: "activeSession", session: ctx.getActiveSession() }); + + const [providersResponse, allProvidersResponse] = await Promise.all([ + client.config.providers(), + client.provider.list(), + ]); + const providersData = providersResponse.data!; + const allProviders = allProvidersResponse.data! as unknown as AllProvidersData; + + // config ファイルから model を直接読み取る(config.get API は model を正しく返さない) + let configModel: string | undefined; + try { + const raw = await fs.readFile(path.join(paths.config, "opencode.json"), "utf-8"); + configModel = JSON.parse(raw).model; + } catch { + // ファイルが存在しない場合は undefined のまま + } + postMessage({ + type: "providers", + providers: providersData.providers as unknown as ProviderInfo[], + allProviders, + default: providersData.default, + configModel, + }); + + postMessage({ type: "activeEditor", file: getActiveEditorFile(vscode.window.activeTextEditor) }); + postMessage({ type: "difitAvailable", available: ctx.difitHandle.isAvailable() }); +} diff --git a/extension/chat-handlers/messaging.ts b/extension/chat-handlers/messaging.ts new file mode 100644 index 0000000..adae67f --- /dev/null +++ b/extension/chat-handlers/messaging.ts @@ -0,0 +1,96 @@ +import * as path from "node:path"; +import type { ChatMessageWithParts, ChatSession, SendMessageOptions } from "@shared"; +import type { ChatHandlerContext, Msg } from "./context"; + +type PromptPart = + | { type: "text"; text: string; synthetic?: boolean } + | { type: "file"; mime: string; url: string; filename: string } + | { type: "agent"; name: string }; + +/** prompt 送信用のパーツ配列を組み立てる。 */ +function toPromptParts(text: string, workspaceFolder: string, options?: SendMessageOptions): PromptPart[] { + const parts: PromptPart[] = []; + + if (options?.skill) { + parts.push({ type: "text", text: `/${options.skill}`, synthetic: true }); + } + + parts.push({ type: "text", text }); + + if (options?.files) { + for (const file of options.files) { + const absPath = path.isAbsolute(file.filePath) ? file.filePath : path.resolve(workspaceFolder, file.filePath); + parts.push({ + type: "file", + mime: "text/plain", + url: `file://${absPath}`, + filename: file.fileName, + }); + } + } + + if (options?.agent) { + parts.push({ type: "agent", name: options.agent }); + } + + return parts; +} + +export async function sendMessage(ctx: ChatHandlerContext, msg: Msg<"sendMessage">): Promise { + await ctx.client.session.promptAsync({ + sessionID: msg.sessionId, + parts: toPromptParts(msg.text, ctx.workspaceFolder, { + model: msg.model, + files: msg.files, + agent: msg.agent, + primaryAgent: msg.primaryAgent, + skill: msg.skill, + }), + model: msg.model, + agent: msg.primaryAgent, + }); +} + +export async function editAndResend(ctx: ChatHandlerContext, msg: Msg<"editAndResend">): Promise { + // 1. 指定メッセージまで巻き戻す(そのメッセージ以降を削除) + const session = (await ctx.client.session.revert({ sessionID: msg.sessionId, messageID: msg.messageId })) + .data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + const messages = (await ctx.client.session.messages({ sessionID: msg.sessionId })) + .data! as unknown as ChatMessageWithParts[]; + ctx.postMessage({ type: "messages", sessionId: msg.sessionId, messages }); + // 2. 編集後のテキストを送信 + await ctx.client.session.promptAsync({ + sessionID: msg.sessionId, + parts: toPromptParts(msg.text, ctx.workspaceFolder, { model: msg.model, files: msg.files }), + model: msg.model, + agent: undefined, + }); +} + +export async function executeShell(ctx: ChatHandlerContext, msg: Msg<"executeShell">): Promise { + await ctx.client.session.shell({ + sessionID: msg.sessionId, + agent: "default", + command: msg.command, + model: msg.model, + }); +} + +export async function abort(ctx: ChatHandlerContext, msg: Msg<"abort">): Promise { + await ctx.client.session.abort({ sessionID: msg.sessionId }); +} + +export async function replyPermission(ctx: ChatHandlerContext, msg: Msg<"replyPermission">): Promise { + await ctx.client.permission.reply({ requestID: msg.permissionId, reply: msg.response }); +} + +export async function replyQuestion(ctx: ChatHandlerContext, msg: Msg<"replyQuestion">): Promise { + await ctx.client.question.reply({ requestID: msg.requestId, answers: msg.answers }); +} + +export async function rejectQuestion(ctx: ChatHandlerContext, msg: Msg<"rejectQuestion">): Promise { + await ctx.client.question.reject({ requestID: msg.requestId }); +} + diff --git a/extension/chat-handlers/meta.ts b/extension/chat-handlers/meta.ts new file mode 100644 index 0000000..b1f1704 --- /dev/null +++ b/extension/chat-handlers/meta.ts @@ -0,0 +1,76 @@ +import * as fs from "node:fs/promises"; +import * as path from "node:path"; +import type { OpencodeClient } from "@opencode-ai/sdk/v2"; +import type { AgentInfo, AllProvidersData, AppPaths, ProviderInfo, SkillInfo } from "@shared"; +import * as vscode from "vscode"; +import type { ChatHandlerContext, Msg } from "./context"; + +/** opencode.json に model を書き込む。ファイルが無ければ新規作成する。 */ +async function setConfiguredModel(client: OpencodeClient, model: string): Promise { + const paths = (await client.path.get()).data! as unknown as AppPaths; + const configFilePath = path.join(paths.config, "opencode.json"); + let configJson: Record = {}; + try { + const raw = await fs.readFile(configFilePath, "utf-8"); + configJson = JSON.parse(raw); + } catch { + // File may not exist yet. + } + configJson.model = model; + await fs.mkdir(path.dirname(configFilePath), { recursive: true }); + await fs.writeFile(configFilePath, `${JSON.stringify(configJson, null, 2)}\n`); +} + +export async function getProviders(ctx: ChatHandlerContext): Promise { + const [providersResponse, allProvidersResponse, pathsResponse] = await Promise.all([ + ctx.client.config.providers(), + ctx.client.provider.list(), + ctx.client.path.get(), + ]); + const providersData = providersResponse.data!; + const allProviders = allProvidersResponse.data! as unknown as AllProvidersData; + const paths = pathsResponse.data! as unknown as AppPaths; + let configModel: string | undefined; + try { + const raw = await fs.readFile(path.join(paths.config, "opencode.json"), "utf-8"); + configModel = JSON.parse(raw).model; + } catch { + // ignore + } + ctx.postMessage({ + type: "providers", + providers: providersData.providers as unknown as ProviderInfo[], + allProviders, + default: providersData.default, + configModel, + }); +} + +export async function getAgents(ctx: ChatHandlerContext): Promise { + const agents = (await ctx.client.app.agents()).data! as unknown as AgentInfo[]; + ctx.postMessage({ type: "agents", agents }); +} + +export async function getSkills(ctx: ChatHandlerContext): Promise { + const skills = (await ctx.client.app.skills()).data! as unknown as SkillInfo[]; + ctx.postMessage({ type: "skills", skills }); +} + +export async function setModel(ctx: ChatHandlerContext, msg: Msg<"setModel">): Promise { + await setConfiguredModel(ctx.client, msg.model); + ctx.postMessage({ type: "modelUpdated", model: msg.model, default: {} }); +} + +/** 設定ファイルを開く。存在しない場合は初期内容で新規作成する。 */ +export async function openConfigFile(_ctx: ChatHandlerContext, msg: Msg<"openConfigFile">): Promise { + const uri = vscode.Uri.file(msg.filePath); + try { + await vscode.workspace.fs.stat(uri); + } catch { + const dir = vscode.Uri.file(msg.filePath.substring(0, msg.filePath.lastIndexOf("/"))); + await vscode.workspace.fs.createDirectory(dir); + await vscode.workspace.fs.writeFile(uri, Buffer.from('{\n "$schema": "https://opencode.ai/config.json"\n}\n')); + } + const doc = await vscode.workspace.openTextDocument(uri); + await vscode.window.showTextDocument(doc); +} diff --git a/extension/chat-handlers/session.ts b/extension/chat-handlers/session.ts new file mode 100644 index 0000000..8a48fa8 --- /dev/null +++ b/extension/chat-handlers/session.ts @@ -0,0 +1,119 @@ +import type { ChatMessageWithParts, ChatSession, FileDiff, TodoItem } from "@shared"; +import * as vscode from "vscode"; +import type { ChatHandlerContext, Msg } from "./context"; + +export async function createSession(ctx: ChatHandlerContext, msg: Msg<"createSession">): Promise { + const session = (await ctx.client.session.create({ title: msg.title })).data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + const sessions = (await ctx.client.session.list()).data! as unknown as ChatSession[]; + ctx.postMessage({ type: "sessions", sessions }); +} + +export async function listSessions(ctx: ChatHandlerContext): Promise { + const sessions = (await ctx.client.session.list()).data! as unknown as ChatSession[]; + ctx.postMessage({ type: "sessions", sessions }); +} + +export async function selectSession(ctx: ChatHandlerContext, msg: Msg<"selectSession">): Promise { + const session = (await ctx.client.session.get({ sessionID: msg.sessionId })).data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + const messages = (await ctx.client.session.messages({ sessionID: msg.sessionId })) + .data! as unknown as ChatMessageWithParts[]; + ctx.postMessage({ type: "messages", sessionId: msg.sessionId, messages }); +} + +export async function deleteSession(ctx: ChatHandlerContext, msg: Msg<"deleteSession">): Promise { + await ctx.client.session.delete({ sessionID: msg.sessionId }); + if (ctx.getActiveSession()?.id === msg.sessionId) { + ctx.setActiveSession(null); + ctx.postMessage({ type: "activeSession", session: null }); + } + const sessions = (await ctx.client.session.list()).data! as unknown as ChatSession[]; + ctx.postMessage({ type: "sessions", sessions }); +} + +export async function getMessages(ctx: ChatHandlerContext, msg: Msg<"getMessages">): Promise { + const messages = (await ctx.client.session.messages({ sessionID: msg.sessionId })) + .data! as unknown as ChatMessageWithParts[]; + ctx.postMessage({ type: "messages", sessionId: msg.sessionId, messages }); +} + +export async function compressSession(ctx: ChatHandlerContext, msg: Msg<"compressSession">): Promise { + await ctx.client.session.summarize({ + sessionID: msg.sessionId, + providerID: msg.model?.providerID, + modelID: msg.model?.modelID, + }); +} + +export async function revertToMessage(ctx: ChatHandlerContext, msg: Msg<"revertToMessage">): Promise { + const session = (await ctx.client.session.revert({ sessionID: msg.sessionId, messageID: msg.messageId })) + .data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + const messages = (await ctx.client.session.messages({ sessionID: msg.sessionId })) + .data! as unknown as ChatMessageWithParts[]; + ctx.postMessage({ type: "messages", sessionId: msg.sessionId, messages }); +} + +export async function forkSession(ctx: ChatHandlerContext, msg: Msg<"forkSession">): Promise { + const forked = (await ctx.client.session.fork({ sessionID: msg.sessionId, messageID: msg.messageId })) + .data! as unknown as ChatSession; + ctx.setActiveSession(forked); + ctx.postMessage({ type: "activeSession", session: forked }); + const sessions = (await ctx.client.session.list()).data! as unknown as ChatSession[]; + ctx.postMessage({ type: "sessions", sessions }); +} + +export async function getSessionDiff(ctx: ChatHandlerContext, msg: Msg<"getSessionDiff">): Promise { + const diffs = (await ctx.client.session.diff({ sessionID: msg.sessionId })).data! as unknown as FileDiff[]; + ctx.postMessage({ type: "sessionDiff", sessionId: msg.sessionId, diffs }); +} + +export async function getSessionTodos(ctx: ChatHandlerContext, msg: Msg<"getSessionTodos">): Promise { + const todos = (await ctx.client.session.todo({ sessionID: msg.sessionId })).data! as unknown as TodoItem[]; + ctx.postMessage({ type: "sessionTodos", sessionId: msg.sessionId, todos }); +} + +export async function getChildSessions(ctx: ChatHandlerContext, msg: Msg<"getChildSessions">): Promise { + const children = (await ctx.client.session.children({ sessionID: msg.sessionId })) + .data! as unknown as ChatSession[]; + ctx.postMessage({ type: "childSessions", sessionId: msg.sessionId, children }); +} + +export async function shareSession(ctx: ChatHandlerContext, msg: Msg<"shareSession">): Promise { + const session = (await ctx.client.session.share({ sessionID: msg.sessionId })).data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + // 共有 URL をクリップボードにコピーする + if (session.share?.url) { + await vscode.env.clipboard.writeText(session.share.url); + } +} + +export async function unshareSession(ctx: ChatHandlerContext, msg: Msg<"unshareSession">): Promise { + const session = (await ctx.client.session.unshare({ sessionID: msg.sessionId })).data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); +} + +export async function undoSession(ctx: ChatHandlerContext, msg: Msg<"undoSession">): Promise { + const session = (await ctx.client.session.revert({ sessionID: msg.sessionId, messageID: msg.messageId })) + .data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + const messages = (await ctx.client.session.messages({ sessionID: msg.sessionId })) + .data! as unknown as ChatMessageWithParts[]; + ctx.postMessage({ type: "messages", sessionId: msg.sessionId, messages }); +} + +export async function redoSession(ctx: ChatHandlerContext, msg: Msg<"redoSession">): Promise { + const session = (await ctx.client.session.unrevert({ sessionID: msg.sessionId })).data! as unknown as ChatSession; + ctx.setActiveSession(session); + ctx.postMessage({ type: "activeSession", session }); + const messages = (await ctx.client.session.messages({ sessionID: msg.sessionId })) + .data! as unknown as ChatMessageWithParts[]; + ctx.postMessage({ type: "messages", sessionId: msg.sessionId, messages }); +} diff --git a/extension/chat-handlers/utils.ts b/extension/chat-handlers/utils.ts new file mode 100644 index 0000000..00622dd --- /dev/null +++ b/extension/chat-handlers/utils.ts @@ -0,0 +1,18 @@ +import * as path from "node:path"; +import type { FileAttachment } from "@shared"; +import * as vscode from "vscode"; + +/** + * アクティブなテキストエディタから FileAttachment を生成する。 + * エディタが無い、または file スキーム以外(出力パネル等)の場合は null を返す。 + */ +export function getActiveEditorFile(editor: vscode.TextEditor | undefined): FileAttachment | null { + if (!editor) return null; + const uri = editor.document.uri; + if (uri.scheme !== "file") return null; + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri; + const relativePath = workspaceFolder + ? path.relative(workspaceFolder.fsPath, uri.fsPath) + : path.basename(uri.fsPath); + return { filePath: relativePath, fileName: path.basename(uri.fsPath) }; +} diff --git a/extension/chat-handlers/vscode-actions.ts b/extension/chat-handlers/vscode-actions.ts new file mode 100644 index 0000000..eea0422 --- /dev/null +++ b/extension/chat-handlers/vscode-actions.ts @@ -0,0 +1,94 @@ +import * as path from "node:path"; +import type { FileAttachment, FileDiff } from "@shared"; +import * as vscode from "vscode"; +import type { ChatHandlerContext, Msg } from "./context"; + +/** 現在開かれているテキストエディタの一覧を取得する(重複除去あり)。 */ +export async function getOpenEditors(ctx: ChatHandlerContext): Promise { + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri; + const files = vscode.window.tabGroups.all + .flatMap((group) => group.tabs) + .filter((tab) => tab.input instanceof vscode.TabInputText) + .map((tab): FileAttachment => { + const uri = (tab.input as vscode.TabInputText).uri; + const relativePath = workspaceFolder + ? path.relative(workspaceFolder.fsPath, uri.fsPath) + : path.basename(uri.fsPath); + return { filePath: relativePath, fileName: path.basename(uri.fsPath) }; + }) + .filter((f, i, arr) => arr.findIndex((a) => a.filePath === f.filePath) === i); + ctx.postMessage({ type: "openEditors", files }); +} + +/** ワークスペース内のファイルを部分一致で検索する。 */ +export async function searchWorkspaceFiles(ctx: ChatHandlerContext, msg: Msg<"searchWorkspaceFiles">): Promise { + const pattern = msg.query ? `**/*${msg.query}*` : "**/*"; + const uris = await vscode.workspace.findFiles(pattern, "**/node_modules/**", 20); + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri; + const files = uris.map((uri): FileAttachment => { + const relativePath = workspaceFolder + ? path.relative(workspaceFolder.fsPath, uri.fsPath) + : path.basename(uri.fsPath); + return { filePath: relativePath, fileName: path.basename(uri.fsPath) }; + }); + ctx.postMessage({ type: "workspaceFiles", files }); +} + +/** OpenCode サーバーへ attach するためのターミナルを開く。 */ +export async function openTerminal(ctx: ChatHandlerContext): Promise { + const serverUrl = ctx.openCodeClientHandle.getServerUrl(); + if (!serverUrl) return; + const args = ["attach", serverUrl]; + const sessionId = ctx.getActiveSession()?.id; + if (sessionId) { + args.push("--session", sessionId); + } + const wsFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; + const terminal = vscode.window.createTerminal({ name: "OpenCode", cwd: wsFolder }); + terminal.show(); + terminal.sendText(`opencode ${args.map((a) => JSON.stringify(a)).join(" ")}`); +} + +/** 仮想ドキュメントを使って VS Code のネイティブ diff エディタを開く。 */ +export async function openDiffEditor(_ctx: ChatHandlerContext, msg: Msg<"openDiffEditor">): Promise { + const beforeUri = vscode.Uri.parse(`opencode-diff-before:${msg.filePath}?${encodeURIComponent(msg.before)}`); + const afterUri = vscode.Uri.parse(`opencode-diff-after:${msg.filePath}?${encodeURIComponent(msg.after)}`); + const fileName = path.basename(msg.filePath); + await vscode.commands.executeCommand("vscode.diff", beforeUri, afterUri, `${fileName} (Changes)`); +} + +/** ファイルを開く。`line` 指定時は該当行へジャンプする。 */ +export async function openFile(_ctx: ChatHandlerContext, msg: Msg<"openFile">): Promise { + const uri = vscode.Uri.file(msg.filePath); + const doc = await vscode.workspace.openTextDocument(uri); + const editor = await vscode.window.showTextDocument(doc); + if (msg.line !== undefined && msg.line >= 1) { + const position = new vscode.Position(msg.line - 1, 0); + editor.selection = new vscode.Selection(position, position); + editor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.InCenter); + } +} + +export async function copyToClipboard(_ctx: ChatHandlerContext, msg: Msg<"copyToClipboard">): Promise { + await vscode.env.clipboard.writeText(msg.text); +} + +export async function openDiffReview(ctx: ChatHandlerContext, msg: Msg<"openDiffReview">): Promise { + const session = ctx.getActiveSession(); + if (!session) return; + try { + const diffs = (await ctx.client.session.diff({ sessionID: session.id })).data! as unknown as FileDiff[]; + if (diffs.length === 0) return; + await ctx.difitHandle.start(diffs, msg.focusFile); + ctx.postMessage({ type: "diffReviewStarted" }); + } catch (e) { + const errorMsg = e instanceof Error ? e.message : String(e); + console.error("[openDiffReview]", errorMsg); + ctx.postMessage({ type: "diffReviewError", error: errorMsg }); + } +} + +export async function stopDiffReview(ctx: ChatHandlerContext): Promise { + ctx.difitHandle.stop(); + ctx.postMessage({ type: "diffReviewStopped" }); +} diff --git a/extension/chat-panel.ts b/extension/chat-panel.ts new file mode 100644 index 0000000..cbfaee8 --- /dev/null +++ b/extension/chat-panel.ts @@ -0,0 +1,201 @@ +import type { ChatSession, HostToUIMessage, UIToHostMessage } from "@shared"; +import * as vscode from "vscode"; +import type { ChatHandlerContext } from "./chat-handlers/context"; +import * as init from "./chat-handlers/init"; +import * as messaging from "./chat-handlers/messaging"; +import * as meta from "./chat-handlers/meta"; +import * as session from "./chat-handlers/session"; +import { getActiveEditorFile } from "./chat-handlers/utils"; +import * as vscodeActions from "./chat-handlers/vscode-actions"; +import type { DifitHandle } from "./difit-handle"; +import type { OpenCodeClientHandle } from "./opencode-client-handle"; + +/** + * OpenCode のチャット UI を表示するサイドバーパネル。 + * Webview のライフサイクル管理と、UI から受信したメッセージを各ハンドラーへ振り分ける役割を持つ。 + * 個々の処理は `chat-handlers/` 配下のモジュールに分離されている。 + */ +export class ChatPanel implements vscode.WebviewViewProvider { + public static readonly viewType = "opencode.chatView"; + + private view: vscode.WebviewView | undefined; + // OpenCode サーバーには「現在アクティブなセッション」を保持する API がないため、 + // UI クライアント側で管理する(TUI も同様の設計)。 + private activeSession: ChatSession | null = null; + + constructor( + private readonly extensionUri: vscode.Uri, + private readonly openCodeClientHandle: OpenCodeClientHandle, + private readonly workspaceFolder: string, + private readonly difitHandle: DifitHandle, + ) {} + + resolveWebviewView( + webviewView: vscode.WebviewView, + _context: vscode.WebviewViewResolveContext, + _token: vscode.CancellationToken, + ): void { + this.view = webviewView; + + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, "dist", "webview")], + }; + + webviewView.webview.html = this.getHtmlForWebview(webviewView.webview); + + webviewView.webview.onDidReceiveMessage((message: UIToHostMessage) => this.handleWebviewMessage(message)); + + // SSE イベントを Webview に転送する + this.openCodeClientHandle.onEvent((event) => { + this.postMessage({ type: "event", event }); + }); + + // アクティブエディタが変わるたびに Webview に通知する + // (プッシュ型通知はメッセージルーターの責務として残す) + vscode.window.onDidChangeActiveTextEditor((editor) => { + this.postMessage({ type: "activeEditor", file: getActiveEditorFile(editor) }); + }); + } + + private async handleWebviewMessage(message: UIToHostMessage): Promise { + try { + await this.dispatch(message); + } catch (err) { + console.error(`[OpenCode] Error handling message '${message.type}':`, err); + } + } + + private async dispatch(message: UIToHostMessage): Promise { + const ctx: ChatHandlerContext = { + client: this.openCodeClientHandle.getClient(), + openCodeClientHandle: this.openCodeClientHandle, + difitHandle: this.difitHandle, + workspaceFolder: this.workspaceFolder, + postMessage: (msg) => this.postMessage(msg), + getActiveSession: () => this.activeSession, + setActiveSession: (s) => { + this.activeSession = s; + }, + }; + + switch (message.type) { + // --- 初期化 --- + case "ready": + return init.ready(ctx); + + // --- session 操作 --- + case "createSession": + return session.createSession(ctx, message); + case "listSessions": + return session.listSessions(ctx); + case "selectSession": + return session.selectSession(ctx, message); + case "deleteSession": + return session.deleteSession(ctx, message); + case "getMessages": + return session.getMessages(ctx, message); + case "compressSession": + return session.compressSession(ctx, message); + case "revertToMessage": + return session.revertToMessage(ctx, message); + case "forkSession": + return session.forkSession(ctx, message); + case "getSessionDiff": + return session.getSessionDiff(ctx, message); + case "getSessionTodos": + return session.getSessionTodos(ctx, message); + case "getChildSessions": + return session.getChildSessions(ctx, message); + case "shareSession": + return session.shareSession(ctx, message); + case "unshareSession": + return session.unshareSession(ctx, message); + case "undoSession": + return session.undoSession(ctx, message); + case "redoSession": + return session.redoSession(ctx, message); + + // --- メッセージ送信・割り込み --- + case "sendMessage": + return messaging.sendMessage(ctx, message); + case "editAndResend": + return messaging.editAndResend(ctx, message); + case "executeShell": + return messaging.executeShell(ctx, message); + case "abort": + return messaging.abort(ctx, message); + case "replyPermission": + return messaging.replyPermission(ctx, message); + case "replyQuestion": + return messaging.replyQuestion(ctx, message); + case "rejectQuestion": + return messaging.rejectQuestion(ctx, message); + + // --- 設定・メタ情報 --- + case "getProviders": + return meta.getProviders(ctx); + case "getAgents": + return meta.getAgents(ctx); + case "getSkills": + return meta.getSkills(ctx); + case "setModel": + return meta.setModel(ctx, message); + case "openConfigFile": + return meta.openConfigFile(ctx, message); + + // --- VS Code 操作 --- + case "getOpenEditors": + return vscodeActions.getOpenEditors(ctx); + case "searchWorkspaceFiles": + return vscodeActions.searchWorkspaceFiles(ctx, message); + case "openTerminal": + return vscodeActions.openTerminal(ctx); + case "openDiffEditor": + return vscodeActions.openDiffEditor(ctx, message); + case "openFile": + return vscodeActions.openFile(ctx, message); + case "copyToClipboard": + return vscodeActions.copyToClipboard(ctx, message); + case "openDiffReview": + return vscodeActions.openDiffReview(ctx, message); + case "stopDiffReview": + return vscodeActions.stopDiffReview(ctx); + } + } + + private postMessage(message: HostToUIMessage): void { + this.view?.webview.postMessage(message); + } + + private getHtmlForWebview(webview: vscode.Webview): string { + const distUri = vscode.Uri.joinPath(this.extensionUri, "dist", "webview"); + + // Vite がビルドした JS/CSS アセットを参照する + const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(distUri, "assets", "index.js")); + const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(distUri, "assets", "index.css")); + + const nonce = getNonce(); + + return /* html */ ` + + + + + + + + +
+ + +`; + } +} + +function getNonce(): string { + const array = new Uint8Array(16); + crypto.getRandomValues(array); + return Array.from(array, (b) => b.toString(16).padStart(2, "0")).join(""); +} diff --git a/packages/platforms/vscode/src/diff-review-manager.ts b/extension/difit-handle.ts similarity index 56% rename from packages/platforms/vscode/src/diff-review-manager.ts rename to extension/difit-handle.ts index b816e3d..6011570 100644 --- a/packages/platforms/vscode/src/diff-review-manager.ts +++ b/extension/difit-handle.ts @@ -1,17 +1,47 @@ import type { ChildProcess } from "node:child_process"; -import { spawn } from "node:child_process"; -import type { FileDiff } from "@opencodegui/core"; +import { execFile, spawn } from "node:child_process"; +import type { FileDiff } from "@shared"; import { createTwoFilesPatch } from "diff"; import * as vscode from "vscode"; +import { DifitBinaryNotFoundError, DifitError } from "./errors"; + +/** spawn 失敗が ENOENT(実行ファイル未検出)を示しているか判定する。 */ +function isBinaryNotFoundError(error: unknown): boolean { + if (!(error instanceof Error)) return false; + const code = (error as NodeJS.ErrnoException).code; + return code === "ENOENT" || error.message.includes("ENOENT"); +} /** - * difit プロセスのライフサイクル管理を担当する。 - * ワークスペースごとに 1 つの difit プロセスを保持し、 - * システムブラウザで差分レビュー画面を開く。 + * difit という外部プロセスとのやり取りを集約するハンドル。 + * `OpenCodeClientHandle` と同じく「外部プロセスの存在確認 + ライフサイクル管理」を 1 クラスに閉じる。 + * + * 使い方: + * 1. `init()` で PATH 上の存在を確認する(結果はキャッシュされる) + * 2. `isAvailable()` で利用可否を取得する + * 3. `start()` でレビュー画面を起動、`stop()` / `dispose()` で停止 */ -export class DiffReviewManager implements vscode.Disposable { +export class DifitHandle implements vscode.Disposable { private process: ChildProcess | null = null; private serverUrl: string | null = null; + private available: boolean | undefined; + + /** PATH 上に difit コマンドが存在するか確認する。結果は内部にキャッシュされる。 */ + async init(): Promise { + this.available = await new Promise((resolve) => { + execFile("which", ["difit"], (error) => { + resolve(!error); + }); + }); + } + + /** + * `init()` で確認した利用可否を返す。 + * `init()` 未実行の場合は `false` を返す(フェイルセーフ)。 + */ + isAvailable(): boolean { + return this.available === true; + } /** * difit プロセスを起動しシステムブラウザでレビュー画面を開く。 @@ -45,6 +75,9 @@ export class DiffReviewManager implements vscode.Disposable { /** * difit を子プロセスとして起動し、stdin に unified diff を書き込む。 * stdout から http://... の URL を検出して返す。 + * + * @throws {@link DifitBinaryNotFoundError} `difit` バイナリが PATH 上に存在しない場合。 + * @throws {@link DifitError} それ以外の理由で difit の起動に失敗した場合。 */ private spawnDifit(unifiedDiff: string): Promise { return new Promise((resolve, reject) => { @@ -53,7 +86,7 @@ export class DiffReviewManager implements vscode.Disposable { const { stdout, stderr, stdin } = child; if (!stdout || !stderr || !stdin) { - reject(new Error("Failed to create stdio streams")); + reject(new DifitError(new Error("Failed to create stdio streams"))); return; } @@ -74,13 +107,17 @@ export class DiffReviewManager implements vscode.Disposable { child.on("error", (err) => { this.process = null; - reject(err); + if (isBinaryNotFoundError(err)) { + reject(new DifitBinaryNotFoundError(err)); + } else { + reject(new DifitError(err)); + } }); child.on("close", (code) => { this.process = null; if (!this.serverUrl) { - reject(new Error(`difit exited with code ${code} before emitting URL`)); + reject(new DifitError(new Error(`difit exited with code ${code} before emitting URL`))); } }); @@ -97,6 +134,9 @@ export class DiffReviewManager implements vscode.Disposable { export function fileDiffsToUnifiedDiff(diffs: FileDiff[]): string { return diffs .map((d) => { + if ("patch" in d) { + return d.patch; + } const patch = createTwoFilesPatch(`a/${d.file}`, `b/${d.file}`, d.before, d.after); // jsdiff は "===...===" ヘッダーを出力するが difit は "diff --git" を期待する return patch.replace(/^={10,}\n/, `diff --git a/${d.file} b/${d.file}\n`); diff --git a/extension/errors.ts b/extension/errors.ts new file mode 100644 index 0000000..dc6d198 --- /dev/null +++ b/extension/errors.ts @@ -0,0 +1,63 @@ +/** + * 拡張機能内で利用するドメイン例外クラスの集約。 + * 複数モジュールから参照されるため、本ファイルに集めてモジュール間の依存を一方向に保つ。 + */ + +/** + * OpenCode 関連エラーの汎用クラス兼基底クラス。 + * 特定の失敗モードに分類されない OpenCode 由来の失敗を表すと同時に、 + * `OpenCodeBinaryNotFoundError` などのサブクラスの基底としても機能する。 + * 呼び出し側は `instanceof OpenCodeError` で OpenCode 由来の失敗をまとめて受けられる。 + */ +export class OpenCodeError extends Error { + constructor(public readonly cause?: unknown) { + super("OpenCode で予期しないエラーが発生しました。"); + this.name = "OpenCodeError"; + } +} + +/** OpenCode クライアントが未接続の状態で要求された場合のエラー。 */ +export class OpenCodeClientNotConnectedError extends OpenCodeError { + constructor() { + super(); + this.message = "OpenCode クライアントが接続されていません。先に connect() を呼び出してください。"; + this.name = "OpenCodeClientNotConnectedError"; + } +} + +/** + * `opencode` バイナリが PATH 上に見つからず、サーバーを起動できなかった場合のエラー。 + * 子プロセス spawn 時の ENOENT を本クラスに変換することで、 + * 呼び出し側は `instanceof` で「未インストール」を識別できる。 + */ +export class OpenCodeBinaryNotFoundError extends OpenCodeError { + constructor(cause: unknown) { + super(cause); + this.message = '"opencode" コマンドが PATH 上に見つかりませんでした。OpenCode をインストールしてください。'; + this.name = "OpenCodeBinaryNotFoundError"; + } +} + +/** + * difit 関連エラーの汎用クラス兼基底クラス。 + * 特定の失敗モードに分類されない difit 由来の失敗を表すと同時に、サブクラスの基底としても機能する。 + * 呼び出し側は `instanceof DifitError` で difit 由来の失敗をまとめて受けられる。 + */ +export class DifitError extends Error { + constructor(public readonly cause?: unknown) { + super("difit で予期しないエラーが発生しました。"); + this.name = "DifitError"; + } +} + +/** + * `difit` バイナリが PATH 上に見つからず、起動できなかった場合のエラー。 + * 子プロセス spawn 時の ENOENT を本クラスに変換する。 + */ +export class DifitBinaryNotFoundError extends DifitError { + constructor(cause: unknown) { + super(cause); + this.message = '"difit" コマンドが PATH 上に見つかりませんでした。difit をインストールしてください。'; + this.name = "DifitBinaryNotFoundError"; + } +} diff --git a/extension/extension.ts b/extension/extension.ts new file mode 100644 index 0000000..2962b45 --- /dev/null +++ b/extension/extension.ts @@ -0,0 +1,92 @@ +import * as vscode from "vscode"; +import { ChatPanel } from "./chat-panel"; +import { DifitHandle } from "./difit-handle"; +import { OpenCodeBinaryNotFoundError, OpenCodeError } from "./errors"; +import { t } from "./i18n"; +import { OpenCodeClientHandle } from "./opencode-client-handle"; + +const openCodeClientHandle = new OpenCodeClientHandle(); + +// Extension Host プロセスが強制終了された場合でもサーバーを停止する +process.on("exit", () => openCodeClientHandle.disconnect()); + +/** + * VS Code から呼ばれる拡張機能のエントリポイント。 + * 呼び出し契機は `package.json` の `activationEvents` および `contributes` 宣言で定義されている。 + */ +export async function activate(context: vscode.ExtensionContext) { + const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; + if (!workspaceFolder) { + vscode.window.showWarningMessage(t("warnings.noWorkspace")); + return; + } + + if (!(await connectOpenCode(workspaceFolder))) { + return; + } + + const difitHandle = new DifitHandle(); + await difitHandle.init(); + if (!difitHandle.isAvailable()) { + vscode.window.showInformationMessage(t("info.difitNotAvailable")); + } + + const chatPanel = new ChatPanel(context.extensionUri, openCodeClientHandle, workspaceFolder, difitHandle); + context.subscriptions.push(vscode.window.registerWebviewViewProvider(ChatPanel.viewType, chatPanel)); + context.subscriptions.push(difitHandle); + + // diff エディタ用の仮想ドキュメントプロバイダー。 + // URI のクエリ部分にエンコードされたコンテンツを返す。 + const diffContentProvider: vscode.TextDocumentContentProvider = { + provideTextDocumentContent(uri: vscode.Uri): string { + return decodeURIComponent(uri.query); + }, + }; + context.subscriptions.push( + vscode.workspace.registerTextDocumentContentProvider("opencode-diff-before", diffContentProvider), + vscode.workspace.registerTextDocumentContentProvider("opencode-diff-after", diffContentProvider), + ); + + context.subscriptions.push(new vscode.Disposable(() => openCodeClientHandle.disconnect())); +} + +/** + * VS Code から呼ばれる拡張機能の終了フック。 + * ウィンドウを閉じる・拡張を無効化する・リロードするタイミングで呼ばれる。 + * `context.subscriptions` 管理外のリソースはここで解放する必要がある。 + */ +export function deactivate() { + openCodeClientHandle.disconnect(); +} + +/** + * 指定したワークスペースフォルダで OpenCode サーバーへ接続する。 + * 失敗種別に応じてユーザー通知を出し、`activate` を続行すべきかを真偽値で返す。 + * + * @returns 接続成功時 true。通知済みで activate を中止すべき場合 false。 + * @throws OpenCode に由来しない想定外のエラー。 + */ +async function connectOpenCode(workspaceFolder: string): Promise { + // SDK の createOpencodeServer は cwd オプションを持たないため、 + // プロセスのカレントディレクトリを変更してからサーバーを起動する。 + const originalCwd = process.cwd(); + process.chdir(workspaceFolder); + try { + await openCodeClientHandle.connect(); + return true; + } catch (error) { + if (error instanceof OpenCodeBinaryNotFoundError) { + vscode.window.showWarningMessage(t("warnings.opencodeNotFound")); + return false; + } + if (error instanceof OpenCodeError) { + console.error(error); + vscode.window.showErrorMessage(t("errors.unexpected")); + return false; + } + throw error; + } finally { + process.chdir(originalCwd); + } +} + diff --git a/extension/i18n/index.ts b/extension/i18n/index.ts new file mode 100644 index 0000000..18710bb --- /dev/null +++ b/extension/i18n/index.ts @@ -0,0 +1,45 @@ +import * as vscode from "vscode"; +import { messages } from "./source"; + +/** + * `messages` の構造から `"warnings.noWorkspace"` のようなドット区切りキー集合を導出する型。 + */ +type Leaves = { + [K in keyof T & string]: T[K] extends string ? `${P}${K}` : Leaves; +}[keyof T & string]; + +export type MessageKey = Leaves; + +/** + * `t()` に渡されたキーが `source.ts` の構造に存在しなかった場合に投げられる例外。 + * 通常は `MessageKey` 型でコンパイル時に弾かれるため、これが投げられた場合は + * 型キャストの誤用などで型の保護が外れたバグとみなせる。 + */ +export class I18nKeyNotFoundError extends Error { + constructor(public readonly key: string) { + super(`i18n のソースにキーが存在しません: ${key}`); + this.name = "I18nKeyNotFoundError"; + } +} + +/** + * Rails I18n 風のキーベース翻訳取得。 + * `source.ts` から英文を引き、それをバンドルキーとして `vscode.l10n.t` に渡す。 + * バンドル未ヒット時は英文がそのまま返るため、フォールバックは自動で機能する。 + */ +export function t(key: MessageKey): string { + return vscode.l10n.t(resolveSource(key)); +} + +function resolveSource(key: string): string { + const value = key.split(".").reduce((current, segment) => { + if (current && typeof current === "object" && segment in current) { + return (current as Record)[segment]; + } + return undefined; + }, messages); + if (typeof value !== "string") { + throw new I18nKeyNotFoundError(key); + } + return value; +} diff --git a/extension/i18n/source.ts b/extension/i18n/source.ts new file mode 100644 index 0000000..39d3840 --- /dev/null +++ b/extension/i18n/source.ts @@ -0,0 +1,20 @@ +/** + * メッセージの英語ソース。すべての翻訳キーの正本。 + * `bundle.l10n..json` は本ファイルのキー(ドット区切り表記)を JSON のキーとして持つ。 + * 各言語バンドルにキーが無い場合、`t()` はここに定義された英文へフォールバックする。 + */ +export const messages = { + warnings: { + noWorkspace: "OpenCodeGUI requires an open workspace folder.", + opencodeNotFound: + 'OpenCodeGUI: "opencode" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode', + }, + errors: { + unexpected: + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.", + }, + info: { + difitNotAvailable: + 'OpenCodeGUI: "difit" command not found. The diff review feature will be disabled. Install difit to enable it.', + }, +} as const; diff --git a/extension/opencode-client-handle.ts b/extension/opencode-client-handle.ts new file mode 100644 index 0000000..1f8c162 --- /dev/null +++ b/extension/opencode-client-handle.ts @@ -0,0 +1,119 @@ +import { createOpencodeClient, createOpencodeServer, type OpencodeClient } from "@opencode-ai/sdk/v2"; +import type { AgentEvent, Disposable } from "@shared"; +import { OpenCodeBinaryNotFoundError, OpenCodeClientNotConnectedError, OpenCodeError } from "./errors"; + +/** OpenCode から受信したエージェントイベントを処理するコールバック。 */ +type EventHandler = (event: AgentEvent) => void; + +/** spawn 失敗が ENOENT(実行ファイル未検出)を示しているか判定する。 */ +function isBinaryNotFoundError(error: unknown): boolean { + if (!(error instanceof Error)) return false; + // Node 標準の NodeJS.ErrnoException は code フィールドを持つ。 + // SDK 側でラップされて code が落ちているケースに備えて message も見る。 + const code = (error as NodeJS.ErrnoException).code; + return code === "ENOENT" || error.message.includes("ENOENT"); +} + +/** + * OpenCode サーバーと SDK クライアントのライフサイクルを管理する。 + * VS Code 拡張側からクライアント取得と SSE イベント購読を提供する。 + */ +export class OpenCodeClientHandle { + private client: OpencodeClient | undefined; + private server: { url: string; close(): void } | undefined; + private sseAbortController: AbortController | undefined; + private listeners: Set = new Set(); + + /** + * OpenCode サーバーを起動し、SDK クライアントとイベント購読を初期化する。 + * + * @throws {@link OpenCodeBinaryNotFoundError} `opencode` バイナリが PATH 上に存在しない場合。 + * @throws {@link OpenCodeError} それ以外の理由でサーバー起動に失敗した場合。 + */ + async connect(): Promise { + let server: { url: string; close(): void }; + try { + server = await createOpencodeServer({ port: 0 }); + } catch (error) { + if (isBinaryNotFoundError(error)) { + throw new OpenCodeBinaryNotFoundError(error); + } + throw new OpenCodeError(error); + } + this.server = server; + this.client = createOpencodeClient({ baseUrl: server.url }); + this.subscribeToEvents(); + } + + /** イベント購読を停止し、サーバーとクライアントを破棄する。 */ + disconnect(): void { + this.sseAbortController?.abort(); + this.sseAbortController = undefined; + this.server?.close(); + this.server = undefined; + this.client = undefined; + this.listeners.clear(); + } + + /** + * 接続済みの OpenCode SDK クライアントを返す。 + * + * @throws {@link OpenCodeClientNotConnectedError} OpenCode クライアントが未接続の場合。 + */ + getClient(): OpencodeClient { + if (!this.client) { + throw new OpenCodeClientNotConnectedError(); + } + return this.client; + } + + /** 起動中の OpenCode サーバー URL を返す。未接続の場合は undefined を返す。 */ + getServerUrl(): string | undefined { + return this.server?.url; + } + + /** + * OpenCode のエージェントイベントを購読する。 + * + * @param handler 受信イベントを処理するコールバック。 + * @returns 購読解除に使う Disposable。 + */ + onEvent(handler: EventHandler): Disposable { + this.listeners.add(handler); + return { + dispose: () => { + this.listeners.delete(handler); + }, + }; + } + + /** 現在の SSE 購読を張り直す。 */ + async resubscribeEvents(): Promise { + await this.subscribeToEvents(); + } + + /** 既存の SSE 購読を停止してから、新しいイベントストリームを購読する。 */ + private async subscribeToEvents(): Promise { + const client = this.getClient(); + this.sseAbortController?.abort(); + this.sseAbortController = new AbortController(); + const result = await client.event.subscribe(undefined, { + signal: this.sseAbortController.signal, + }); + + (async () => { + try { + for await (const event of result.stream) { + for (const listener of this.listeners) { + listener(event as unknown as AgentEvent); + } + } + } catch (error) { + if (error instanceof DOMException && error.name === "AbortError") { + return; + } + throw error; + } + })(); + } +} diff --git a/l10n/bundle.l10n.es.json b/l10n/bundle.l10n.es.json new file mode 100644 index 0000000..0550e9f --- /dev/null +++ b/l10n/bundle.l10n.es.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "OpenCodeGUI requiere una carpeta de espacio de trabajo abierta.", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI: no se encontró el comando \"opencode\". Instale OpenCode primero: https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI: ocurrió un error inesperado al iniciar OpenCode. Consulte el registro del desarrollador para más detalles.", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI: no se encontró el comando \"difit\". La función de revisión de diff se deshabilitará. Instale difit para habilitarla." +} diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json new file mode 100644 index 0000000..dc5a611 --- /dev/null +++ b/l10n/bundle.l10n.ja.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "OpenCodeGUI を使用するにはワークスペースフォルダーを開いてください。", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI: \"opencode\" コマンドが見つかりません。先に OpenCode をインストールしてください: https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI: OpenCode の起動中に予期しないエラーが発生しました。詳細は開発者ログを参照してください。", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI: \"difit\" コマンドが見つかりません。diff レビュー機能は無効化されます。difit をインストールすると利用できます。" +} diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json new file mode 100644 index 0000000..a2810ca --- /dev/null +++ b/l10n/bundle.l10n.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "OpenCodeGUI requires an open workspace folder.", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it." +} diff --git a/l10n/bundle.l10n.ko.json b/l10n/bundle.l10n.ko.json new file mode 100644 index 0000000..b32d514 --- /dev/null +++ b/l10n/bundle.l10n.ko.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "OpenCodeGUI를 사용하려면 작업 영역 폴더를 여세요.", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI: \"opencode\" 명령을 찾을 수 없습니다. 먼저 OpenCode를 설치하세요: https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI: OpenCode 시작 중에 예기치 않은 오류가 발생했습니다. 자세한 내용은 개발자 로그를 참조하세요.", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI: \"difit\" 명령을 찾을 수 없습니다. diff 리뷰 기능이 비활성화됩니다. difit를 설치하면 사용할 수 있습니다." +} diff --git a/l10n/bundle.l10n.pt-br.json b/l10n/bundle.l10n.pt-br.json new file mode 100644 index 0000000..1ef6ff3 --- /dev/null +++ b/l10n/bundle.l10n.pt-br.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "O OpenCodeGUI requer uma pasta de espaço de trabalho aberta.", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI: comando \"opencode\" não encontrado. Instale o OpenCode primeiro: https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI: ocorreu um erro inesperado ao iniciar o OpenCode. Consulte o log do desenvolvedor para obter detalhes.", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI: comando \"difit\" não encontrado. O recurso de revisão de diff será desabilitado. Instale o difit para habilitá-lo." +} diff --git a/l10n/bundle.l10n.ru.json b/l10n/bundle.l10n.ru.json new file mode 100644 index 0000000..3018609 --- /dev/null +++ b/l10n/bundle.l10n.ru.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "Для работы OpenCodeGUI требуется открытая папка рабочей области.", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI: команда \"opencode\" не найдена. Сначала установите OpenCode: https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI: при запуске OpenCode произошла непредвиденная ошибка. Подробности см. в журнале разработчика.", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI: команда \"difit\" не найдена. Функция просмотра diff будет отключена. Установите difit, чтобы включить её." +} diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json new file mode 100644 index 0000000..b0b5719 --- /dev/null +++ b/l10n/bundle.l10n.zh-cn.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "OpenCodeGUI 需要打开工作区文件夹。", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI:未找到 \"opencode\" 命令。请先安装 OpenCode:https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI:启动 OpenCode 时发生意外错误。详情请查看开发者日志。", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI:未找到 \"difit\" 命令。diff 审阅功能将被禁用。安装 difit 后即可使用。" +} diff --git a/l10n/bundle.l10n.zh-tw.json b/l10n/bundle.l10n.zh-tw.json new file mode 100644 index 0000000..0347e5f --- /dev/null +++ b/l10n/bundle.l10n.zh-tw.json @@ -0,0 +1,6 @@ +{ + "OpenCodeGUI requires an open workspace folder.": "OpenCodeGUI 需要開啟工作區資料夾。", + "OpenCodeGUI: \"opencode\" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode": "OpenCodeGUI:找不到 \"opencode\" 命令。請先安裝 OpenCode:https://github.com/anomalyco/opencode", + "OpenCodeGUI: An unexpected error occurred while starting OpenCode. See the developer log for details.": "OpenCodeGUI:啟動 OpenCode 時發生未預期的錯誤。詳情請查看開發者記錄。", + "OpenCodeGUI: \"difit\" command not found. The diff review feature will be disabled. Install difit to enable it.": "OpenCodeGUI:找不到 \"difit\" 命令。diff 檢閱功能將被停用。安裝 difit 後即可使用。" +} diff --git a/packages/platforms/vscode/media/demo.gif b/media/demo.gif similarity index 100% rename from packages/platforms/vscode/media/demo.gif rename to media/demo.gif diff --git a/packages/platforms/vscode/media/icon.png b/media/icon.png similarity index 100% rename from packages/platforms/vscode/media/icon.png rename to media/icon.png diff --git a/packages/platforms/vscode/media/icon_full.png b/media/icon_full.png similarity index 100% rename from packages/platforms/vscode/media/icon_full.png rename to media/icon_full.png diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..6ea5a7e --- /dev/null +++ b/mise.toml @@ -0,0 +1,2 @@ +[tools] +node = "24" diff --git a/package-lock.json b/package-lock.json index caf150d..70aff4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,336 @@ { - "name": "opencodegui-monorepo", - "version": "0.3.0", + "name": "opencodegui", + "version": "0.5.3", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "opencodegui-monorepo", - "version": "0.3.0", + "name": "opencodegui", + "version": "0.5.3", "license": "MIT", + "dependencies": { + "@opencode-ai/sdk": "^1.2.10", + "diff": "^8.0.0", + "dompurify": "^3.3.1", + "highlight.js": "^11.11.1", + "react-icons": "^5.5.0" + }, "devDependencies": { - "@biomejs/biome": "2.4.4" + "@biomejs/biome": "2.4.4", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/dompurify": "^3.0.5", + "@types/node": "^22.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@types/vscode": "^1.100.0", + "@vitejs/plugin-react": "^6.0.1", + "@vscode/vsce": "^3.7.1", + "esbuild": "^0.28.0", + "jsdom": "^28.1.0", + "marked": "^17.0.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "typescript": "^6.0.3", + "vite": "^8.0.11", + "vitest": "^4.0.18" + }, + "engines": { + "node": ">=24", + "vscode": "^1.100.0" + } + }, + "node_modules/@acemir/cssom": { + "version": "0.9.31", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", + "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", + "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.6" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "@azu/format-text": "^1.0.1" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", + "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", + "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.23.0.tgz", + "integrity": "sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", + "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.1.tgz", + "integrity": "sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^5.1.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", + "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.10.0.tgz", + "integrity": "sha512-2Y4TlG5mCfxviHutfW50i8Xd8xhGKTgieL02vMYOE5ZbZrVM+drKSGD//tweRAmlmqqp+F9vrKoHWri/buzxWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.6.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.6.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.6.0.tgz", + "integrity": "sha512-FemGljX0csPlBMUE5GUan7BfRn1emeMRUhHSARhqzLN6LA9nt+MgzmAQ1xVqdLm+6plVoxsq9mS5eoyKtpPSgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.2.0.tgz", + "integrity": "sha512-b/ak8XAqpnGk1N1nsyTVV0Remp48BP3QrGQZ1uCMcvg2S8X1eSXzhHQZEae2oX276Q4KFAqCUswanDtcvIKLrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.6.0", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, "node_modules/@biomejs/biome": { @@ -174,6 +495,6429 @@ "engines": { "node": ">=14.21.3" } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.0.tgz", + "integrity": "sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.0.tgz", + "integrity": "sha512-U0KhLYmy2GVj6q4T3WaAe6NPuFYCPQoE3b0dRGxejWDgcPp8TP7S5rVdM5ZrFaqu4N67X8YaPBw14dQSYx3IyQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.3.tgz", + "integrity": "sha512-SH60bMfrRCJF3morcdk57WklujF4Jr/EsQUzqkarfHXEFcAR1gg7fS/chAE922Sehgzc1/+Tz5H3Ypa1HiEKrg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", + "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.0.tgz", + "integrity": "sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opencode-ai/sdk": { + "version": "1.14.41", + "resolved": "https://registry.npmjs.org/@opencode-ai/sdk/-/sdk-1.14.41.tgz", + "integrity": "sha512-RYb2dCUv0TWIvBNnnO6ANbAPYri6rKuWizSoVFw/Pw+SCDj9ASHM5gAZ+jkskp8gYMfLLHe/Fpkun/9mr8m0IQ==", + "license": "MIT", + "dependencies": { + "cross-spawn": "7.0.6" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.128.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.128.0.tgz", + "integrity": "sha512-huv1Y/LzBJkBVHt3OlC7u0zHBW9qXf1FdD7sGmc1rXc2P1mTwHssYv7jyGx5KAACSCH+9B3Bhn6Z9luHRvf7pQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-lIDyUAfD7U3+BWKzdxMbJcsYHuqXqmGz40aeRqvuAm3y5TkJSYTBW2RDrn65DJFPQqVjUAUqq5uz8urzQ8aBdQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-apJq2ktnGp27nSInMR5Vcj8kY6xJzDAvfdIFlpDcAK/w4cDO58qVoi1YQsES/SKiFNge/6e4CUzgjfHduYqWpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.18.tgz", + "integrity": "sha512-5Ofot8xbs+pxRHJqm9/9N/4sTQOvdrwEsmPE9pdLEEoAbdZtG6F2LMDfO1sp6ZAtXJuJV/21ew2srq3W8NXB5g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.18.tgz", + "integrity": "sha512-7h8eeOTT1eyqJyx64BFCnWZpNm486hGWt2sqeLLgDxA0xI1oGZ9H7gK1S85uNGmBhkdPwa/6reTxfFFKvIsebw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.18.tgz", + "integrity": "sha512-eRcm/HVt9U/JFu5RKAEKwGQYtDCKWLiaH6wOnsSEp6NMBb/3Os8LgHZlNyzMpFVNmiiMFlfb2zEnebfzJrHFmg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-SOrT/cT4ukTmgnrEz/Hg3m7LBnuCLW9psDeMKrimRWY4I8DmnO7Lco8W2vtqPmMkbVu8iJ+g4GFLVLLOVjJ9DQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.18.tgz", + "integrity": "sha512-QWjdxN1HJCpBTAcZ5N5F7wju3gVPzRzSpmGzx7na0c/1qpN9CFil+xt+l9lV/1M6/gqHSNXCiqPfwhVJPeLnug==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-ugCOyj7a4d9h3q9B+wXmf6g3a68UsjGh6dob5DHevHGMwDUbhsYNbSPxJsENcIttJZ9jv7qGM2UesLw5jqIhdg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-kKWRhbsotpXkGbcd5dllUWg5gEXcDAa8u5YnP9AV5DYNbvJHGzzuwv7dpmhc8NqKMJldl0a+x76IHbspEpEmdA==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.18.tgz", + "integrity": "sha512-uCo8ElcCIAMyYAZyuIZ81oFkhTSIllNvUCHCAlbhlN4ji3uC28h7IIdlXyIvGO7HsuqnV9p3rD/bpH7XhIyhRw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.18.tgz", + "integrity": "sha512-XNOQZtuE6yUIvx4rwGemwh8kpL1xvU41FXy/s9K7T/3JVcqGzo3NfKM2HrbrGgfPYGFW42f07Wk++aOC6B9NWA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.18.tgz", + "integrity": "sha512-tSn/kzrfa7tNOXr7sEacDBN4YsIqTyLqh45IO0nHDwtpKIDNDJr+VFojt+4klSpChxB29JLyduSsE0MKEwa65A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.18.tgz", + "integrity": "sha512-+J9YGmc+czgqlhYmwun3S3O0FIZhsH8ep2456xwjAdIOmuJxM7xz4P4PtrxU+Bz17a/5bqPA8o3HAAoX0teUdg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.18.tgz", + "integrity": "sha512-zsu47DgU0FQzSwi6sU9dZoEdUv7pc1AptSEz/Z8HBg54sV0Pbs3N0+CrIbTsgiu6EyoaNN9CHboqbLaz9lhOyQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.18.tgz", + "integrity": "sha512-7H+3yqGgmnlDTRRhw/xpYY9J1kf4GC681nVc4GqKhExZTDrVVrV2tsOR9kso0fvgBdcTCcQShx4SLLoHgaLwhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.7", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.7.tgz", + "integrity": "sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.9.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", + "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "picocolors": "^1.1.1", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@textlint/ast-node-types": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.6.0.tgz", + "integrity": "sha512-CxZHFbYAU7J0A4izz31wV2ZZfySR6aVj2OSR6/3tppZm7VV6hM7nA7sutsLwIiBL/v4lsB1RM79l4Dc/VrH4qw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.6.0.tgz", + "integrity": "sha512-IwHRhjwxs0a5t1eNAoKAdV224CDca38LyopPofXpwO/d0J75wBvzf/cBHXNl4TMsLKhYGtR83UprcLEKj/gZsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.6.0", + "@textlint/resolver": "15.6.0", + "@textlint/types": "15.6.0", + "chalk": "^4.1.2", + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "lodash": "^4.18.1", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/module-interop": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.6.0.tgz", + "integrity": "sha512-MHY6pJx9i5kOlrvUSK51887tYZjHAV2qnr6unBm7LtBLGDFo93utdYqHyWep8r9QLsilQdeijWtufJI46z4v4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.6.0.tgz", + "integrity": "sha512-T1l2Gd3455pwtm0cTewhX/LLy3bL9z6/Fu/am+jj+jjGfXVoknYkjfkZEKrjHlA7xzay0EfUKnu//teYemLeZw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.6.0.tgz", + "integrity": "sha512-CvgYb1PiqF4BGyoZebGWzAJCZ4ChJAZ9gtWjpQIMKE4Xe2KlSwDA8m8MsiZIV321f5Ibx38BMjC1Z/2ZYP2GQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.6.0" + } + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/trusted-types": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.18.tgz", + "integrity": "sha512-9v00a+dn2yWVsYDEunWC4g/TcRKVq3r8N5FuZp7u0SGrPvdN9c2yXI9bBuf5Fl0hNCb+QTIePTn5pJs2pwBOQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", + "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/vscode": { + "version": "1.118.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.118.0.tgz", + "integrity": "sha512-Ah6eTlqDcwIMELEVwQMO++rJAFBRz/oLluLD/vWdYrH1KuI9kfpaM+7pg0OvvascgcJy+ghLCERAYouM4QbzGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.5.tgz", + "integrity": "sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", + "integrity": "sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.7" + }, + "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.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.5", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.5", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.5", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vscode/vsce": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.9.1.tgz", + "integrity": "sha512-MPn5p+DoudI+3GfJSpAZZraE1lgLv0LcwbH3+xy7RgEhty3UIkmUMUA+5jPTDaxXae00AnX5u77FxGM8FhfKKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", + "cheerio": "^1.0.0-rc.9", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^11.0.0", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^14.1.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "secretlint": "^10.1.2", + "semver": "^7.5.2", + "tmp": "^0.2.3", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^3.2.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce-sign": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.9.tgz", + "integrity": "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==", + "dev": true, + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/azure-devops-node-api": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, + "license": "MIT", + "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.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssstyle": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", + "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.0.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.28", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.6" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/data-urls/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/dompurify": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.2.tgz", + "integrity": "sha512-lHeS9SA/IKeIFFyYciHBr2n0v1VMPlSj843HdLOwjb2OxNwdq9Xykxqhk+FE42MzAdHvInbAolSE4mhahPpjXA==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.3.tgz", + "integrity": "sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/highlight.js": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz", + "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", + "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.31", + "@asamuzakjp/dom-selector": "^6.8.1", + "@bramus/specificity": "^2.4.2", + "@exodus/bytes": "^1.11.0", + "cssstyle": "^6.0.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "undici": "^7.21.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/marked": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.6.tgz", + "integrity": "sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-abi": { + "version": "3.92.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz", + "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.6.tgz", + "integrity": "sha512-Gf/KoL3C/MlI7Bt0PGI9I+TeTC/I6r/csU58N4BSNc4lppLBeKsOdFYkK+dX0ABDUMJNfCHTyPpzwwO21Awd3A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss": { + "version": "8.5.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", + "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.4.tgz", + "integrity": "sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "json5": "^2.2.3", + "require-from-string": "^2.0.2" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "node_modules/react-icons": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.6.0.tgz", + "integrity": "sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rolldown": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.18.tgz", + "integrity": "sha512-phmyKBpuBdRYDf4hgyynGAYn/rDDe+iZXKVJ7WX5b1zQzpLkP5oJRPGsfJuHdzPMlyyEO/4sPW6yfSx2gf7lVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.128.0", + "@rolldown/pluginutils": "1.0.0-rc.18" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.0.0-rc.18", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.18", + "@rolldown/binding-darwin-x64": "1.0.0-rc.18", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.18", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.18", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.18", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.18", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.18", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.18", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.18", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.18", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.18" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.18", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.18.tgz", + "integrity": "sha512-CUY5Mnhe64xQBGZEEXQ5WyZwsc1JU3vAZLIxtrsBt3LO6UOb+C8GunVKqe9sT8NeWb4lqSaoJtp2xo6GxT1MNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "bin": { + "secretlint": "bin/secretlint.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.30.tgz", + "integrity": "sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.0.30" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.0.30", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.30.tgz", + "integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/vite": { + "version": "8.0.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.11.tgz", + "integrity": "sha512-Jz1mxtUBR5xTT65VOdJZUUeoyLtqljmFkiUXhPTLZka3RDc9vpi/xXkyrnsdRcm2lIi3l3GPMnAidTsEGIj3Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.32.0", + "picomatch": "^4.0.4", + "postcss": "^8.5.14", + "rolldown": "1.0.0-rc.18", + "tinyglobby": "^0.2.16" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.1.18", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yauzl": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.3.0.tgz", + "integrity": "sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } } } } diff --git a/package.json b/package.json index 2a369e7..95a2315 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,109 @@ { - "name": "opencodegui-monorepo", - "private": true, + "name": "opencodegui", + "displayName": "%displayName%", + "description": "%description%", "version": "0.5.3", + "publisher": "ktmage", "license": "MIT", "repository": { "type": "git", "url": "https://github.com/ktmage/opencode-gui" }, + "homepage": "https://github.com/ktmage/opencode-gui#readme", + "bugs": { + "url": "https://github.com/ktmage/opencode-gui/issues" + }, + "keywords": [ + "opencode", + "ai", + "chat", + "llm", + "coding-assistant" + ], + "icon": "media/icon.png", + "preview": true, + "qna": false, + "galleryBanner": { + "color": "#1e1e1e", + "theme": "dark" + }, + "engines": { + "vscode": "^1.100.0", + "node": ">=24" + }, + "categories": [ + "AI", + "Chat" + ], + "activationEvents": [], + "main": "./dist/extension.js", + "l10n": "./l10n", + "contributes": { + "viewsContainers": { + "activitybar": [ + { + "id": "opencode", + "title": "OpenCode", + "icon": "$(comment-discussion)" + } + ] + }, + "views": { + "opencode": [ + { + "type": "webview", + "id": "opencode.chatView", + "name": "Chat" + } + ] + } + }, "scripts": { - "build": "pnpm -r build", + "build": "node esbuild.mjs && vite build", + "build:extension": "node esbuild.mjs", + "build:webview": "vite build", + "typecheck": "npm run typecheck:extension && npm run typecheck:webview", + "typecheck:extension": "tsc -p tsconfig.json", + "typecheck:webview": "tsc -p webview/tsconfig.json", "check": "biome check .", "check:fix": "biome check --fix .", "format": "biome format --write .", - "test": "pnpm -r test", - "test:all": "pnpm -r run test:all" + "watch:extension": "node esbuild.mjs --watch", + "watch:webview": "vite build --watch", + "test": "vitest run --config vitest.config.ts", + "test:extension": "vitest run --config vitest.config.extension.ts", + "test:extension:watch": "vitest --config vitest.config.extension.ts", + "test:all": "vitest run --config vitest.config.ts && vitest run --config vitest.config.extension.ts", + "test:watch": "vitest --config vitest.config.ts", + "package": "vsce package --no-dependencies", + "publish": "vsce publish --no-dependencies" }, "devDependencies": { - "@biomejs/biome": "2.4.4" + "@biomejs/biome": "2.4.4", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", + "@types/dompurify": "^3.0.5", + "@types/node": "^22.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "@types/vscode": "^1.100.0", + "@vitejs/plugin-react": "^6.0.1", + "@vscode/vsce": "^3.7.1", + "esbuild": "^0.28.0", + "jsdom": "^28.1.0", + "marked": "^17.0.3", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "typescript": "^6.0.3", + "vite": "^8.0.11", + "vitest": "^4.0.18" + }, + "dependencies": { + "@opencode-ai/sdk": "^1.2.10", + "diff": "^8.0.0", + "dompurify": "^3.3.1", + "highlight.js": "^11.11.1", + "react-icons": "^5.5.0" } } diff --git a/packages/platforms/vscode/package.nls.es.json b/package.nls.es.json similarity index 100% rename from packages/platforms/vscode/package.nls.es.json rename to package.nls.es.json diff --git a/packages/platforms/vscode/package.nls.ja.json b/package.nls.ja.json similarity index 100% rename from packages/platforms/vscode/package.nls.ja.json rename to package.nls.ja.json diff --git a/packages/platforms/vscode/package.nls.json b/package.nls.json similarity index 100% rename from packages/platforms/vscode/package.nls.json rename to package.nls.json diff --git a/packages/platforms/vscode/package.nls.ko.json b/package.nls.ko.json similarity index 100% rename from packages/platforms/vscode/package.nls.ko.json rename to package.nls.ko.json diff --git a/packages/platforms/vscode/package.nls.pt-br.json b/package.nls.pt-br.json similarity index 100% rename from packages/platforms/vscode/package.nls.pt-br.json rename to package.nls.pt-br.json diff --git a/packages/platforms/vscode/package.nls.ru.json b/package.nls.ru.json similarity index 100% rename from packages/platforms/vscode/package.nls.ru.json rename to package.nls.ru.json diff --git a/packages/platforms/vscode/package.nls.zh-cn.json b/package.nls.zh-cn.json similarity index 100% rename from packages/platforms/vscode/package.nls.zh-cn.json rename to package.nls.zh-cn.json diff --git a/packages/platforms/vscode/package.nls.zh-tw.json b/package.nls.zh-tw.json similarity index 100% rename from packages/platforms/vscode/package.nls.zh-tw.json rename to package.nls.zh-tw.json diff --git a/packages/agents/opencode/package.json b/packages/agents/opencode/package.json deleted file mode 100644 index bab04aa..0000000 --- a/packages/agents/opencode/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "@opencodegui/agent-opencode", - "version": "0.0.1", - "private": true, - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "dist" - ], - "scripts": { - "build": "tsc -p tsconfig.json", - "test": "vitest run", - "test:all": "vitest run" - }, - "dependencies": { - "@opencode-ai/sdk": "^1.2.10", - "@opencodegui/core": "workspace:*" - }, - "devDependencies": { - "typescript": "^5.7.0", - "vitest": "^4.0.18" - } -} diff --git a/packages/agents/opencode/src/__tests__/mappers.test.ts b/packages/agents/opencode/src/__tests__/mappers.test.ts deleted file mode 100644 index c05085f..0000000 --- a/packages/agents/opencode/src/__tests__/mappers.test.ts +++ /dev/null @@ -1,332 +0,0 @@ -/** - * mappers.ts のユニットテスト。 - * 各 mapper 関数が SDK 型からドメイン型に正しく変換することを検証する。 - */ -import { describe, expect, it } from "vitest"; -import { - mapAgent, - mapAgents, - mapAllProvidersData, - mapConfig, - mapEvent, - mapFileDiff, - mapFileDiffs, - mapMcpStatus, - mapMessage, - mapMessagesWithParts, - mapMessageWithParts, - mapPart, - mapPath, - mapProvider, - mapProviders, - mapSession, - mapSessions, - mapTodo, - mapTodos, - mapToolIds, -} from "../mappers"; - -// ============================================================ -// Session mappers -// ============================================================ - -describe("mapSession", () => { - it("should pass through session data as ChatSession", () => { - const sdkSession = { - id: "sess-1", - title: "Test Session", - createdAt: 1700000000, - updatedAt: 1700001000, - }; - const result = mapSession(sdkSession as never); - expect(result).toEqual(sdkSession); - }); -}); - -describe("mapSessions", () => { - it("should map an array of sessions", () => { - const sessions = [ - { id: "s1", title: "Session 1" }, - { id: "s2", title: "Session 2" }, - ]; - const result = mapSessions(sessions as never); - expect(result).toHaveLength(2); - expect(result[0]).toEqual(sessions[0]); - expect(result[1]).toEqual(sessions[1]); - }); - - it("should return empty array for empty input", () => { - expect(mapSessions([])).toEqual([]); - }); -}); - -// ============================================================ -// Message + Parts mappers -// ============================================================ - -describe("mapMessage", () => { - it("should pass through message data as ChatMessage", () => { - const sdkMessage = { - id: "msg-1", - role: "assistant", - content: "Hello", - createdAt: 1700000000, - }; - const result = mapMessage(sdkMessage as never); - expect(result).toEqual(sdkMessage); - }); -}); - -describe("mapPart", () => { - it("should pass through text part", () => { - const part = { type: "text", content: "Hello world" }; - const result = mapPart(part as never); - expect(result).toEqual(part); - }); - - it("should pass through tool-use part", () => { - const part = { type: "tool-use", toolName: "search", input: { query: "foo" } }; - const result = mapPart(part as never); - expect(result).toEqual(part); - }); -}); - -describe("mapMessageWithParts", () => { - it("should map info and parts together", () => { - const data = { - info: { id: "msg-1", role: "assistant" }, - parts: [ - { type: "text", content: "Hello" }, - { type: "tool-use", toolName: "search" }, - ], - }; - const result = mapMessageWithParts(data as never); - expect(result.info).toEqual(data.info); - expect(result.parts).toHaveLength(2); - expect(result.parts[0]).toEqual(data.parts[0]); - expect(result.parts[1]).toEqual(data.parts[1]); - }); -}); - -describe("mapMessagesWithParts", () => { - it("should map an array of messages with parts", () => { - const data = [ - { info: { id: "msg-1" }, parts: [{ type: "text" }] }, - { info: { id: "msg-2" }, parts: [] }, - ]; - const result = mapMessagesWithParts(data as never); - expect(result).toHaveLength(2); - expect(result[0].info).toEqual(data[0].info); - expect(result[1].parts).toEqual([]); - }); -}); - -// ============================================================ -// Event mapper -// ============================================================ - -describe("mapEvent", () => { - it("should pass through session.updated event", () => { - const event = { type: "session.updated", properties: { id: "sess-1" } }; - const result = mapEvent(event as never); - expect(result).toEqual(event); - }); - - it("should pass through message.created event", () => { - const event = { type: "message.created", properties: { sessionID: "sess-1", id: "msg-1" } }; - const result = mapEvent(event as never); - expect(result).toEqual(event); - }); -}); - -// ============================================================ -// Provider mapper -// ============================================================ - -describe("mapProvider", () => { - it("should pass through provider data as ProviderInfo", () => { - const provider = { id: "anthropic", name: "Anthropic", models: [] }; - const result = mapProvider(provider as never); - expect(result).toEqual(provider); - }); -}); - -describe("mapProviders", () => { - it("should map an array of providers", () => { - const providers = [ - { id: "p1", name: "Provider 1" }, - { id: "p2", name: "Provider 2" }, - ]; - const result = mapProviders(providers as never); - expect(result).toHaveLength(2); - }); -}); - -// ============================================================ -// FileDiff mapper -// ============================================================ - -describe("mapFileDiff", () => { - it("should pass through file diff data", () => { - const diff = { path: "src/index.ts", before: "old", after: "new" }; - const result = mapFileDiff(diff as never); - expect(result).toEqual(diff); - }); -}); - -describe("mapFileDiffs", () => { - it("should map an array of file diffs", () => { - const diffs = [ - { path: "a.ts", before: "", after: "new" }, - { path: "b.ts", before: "old", after: "" }, - ]; - const result = mapFileDiffs(diffs as never); - expect(result).toHaveLength(2); - }); - - it("should return empty array for empty input", () => { - expect(mapFileDiffs([])).toEqual([]); - }); -}); - -// ============================================================ -// Todo mapper -// ============================================================ - -describe("mapTodo", () => { - it("should pass through todo data as TodoItem", () => { - const todo = { id: "t1", text: "Fix bug", done: false }; - const result = mapTodo(todo as never); - expect(result).toEqual(todo); - }); -}); - -describe("mapTodos", () => { - it("should map an array of todos", () => { - const todos = [ - { id: "t1", text: "A" }, - { id: "t2", text: "B" }, - ]; - const result = mapTodos(todos as never); - expect(result).toHaveLength(2); - }); -}); - -// ============================================================ -// Agent mapper -// ============================================================ - -describe("mapAgent", () => { - it("should pass through agent data as AgentInfo", () => { - const agentData = { id: "agent-1", name: "Default Agent" }; - const result = mapAgent(agentData as never); - expect(result).toEqual(agentData); - }); -}); - -describe("mapAgents", () => { - it("should map an array of agents", () => { - const agents = [{ id: "a1" }, { id: "a2" }]; - const result = mapAgents(agents as never); - expect(result).toHaveLength(2); - }); -}); - -// ============================================================ -// Config mapper -// ============================================================ - -describe("mapConfig", () => { - it("should pass through config data as AppConfig", () => { - const config = { model: "claude-4", theme: "dark" }; - const result = mapConfig(config as never); - expect(result).toEqual(config); - }); -}); - -// ============================================================ -// Path mapper -// ============================================================ - -describe("mapPath", () => { - it("should pass through path data as AppPaths", () => { - const pathData = { - config: "/home/.config/opencode", - data: "/home/.local/share/opencode", - home: "/home/user", - }; - const result = mapPath(pathData as never); - expect(result).toEqual(pathData); - }); - - it("should handle path without home field", () => { - const pathData = { - config: "/home/.config/opencode", - data: "/home/.local/share/opencode", - }; - const result = mapPath(pathData as never); - expect(result).toEqual(pathData); - }); -}); - -// ============================================================ -// MCP Status mapper -// ============================================================ - -describe("mapMcpStatus", () => { - it("should pass through MCP status data", () => { - const status = { - "server-1": { connected: true, tools: ["tool-a"] }, - "server-2": { connected: false, tools: [] }, - }; - const result = mapMcpStatus(status as never); - expect(result).toEqual(status); - }); - - it("should handle empty status", () => { - const result = mapMcpStatus({} as never); - expect(result).toEqual({}); - }); -}); - -// ============================================================ -// Tool IDs mapper -// ============================================================ - -describe("mapToolIds", () => { - it("should wrap each string ID into ToolListItem", () => { - const ids = ["tool-1", "tool-2", "tool-3"]; - const result = mapToolIds(ids); - expect(result).toEqual([{ id: "tool-1" }, { id: "tool-2" }, { id: "tool-3" }]); - }); - - it("should return empty array for empty input", () => { - expect(mapToolIds([])).toEqual([]); - }); - - it("should handle single ID", () => { - expect(mapToolIds(["only-one"])).toEqual([{ id: "only-one" }]); - }); -}); - -// ============================================================ -// AllProvidersData mapper -// ============================================================ - -describe("mapAllProvidersData", () => { - it("should pass through all providers data", () => { - const data = { - all: [{ id: "p1", name: "Provider 1", models: [] }], - default: { chat: "anthropic/claude-4" }, - connected: ["p1"], - }; - const result = mapAllProvidersData(data as never); - expect(result).toEqual(data); - }); - - it("should handle empty data", () => { - const data = { all: [], default: {}, connected: [] }; - const result = mapAllProvidersData(data); - expect(result).toEqual(data); - }); -}); diff --git a/packages/agents/opencode/src/__tests__/opencode-agent.test.ts b/packages/agents/opencode/src/__tests__/opencode-agent.test.ts deleted file mode 100644 index 6e2b80c..0000000 --- a/packages/agents/opencode/src/__tests__/opencode-agent.test.ts +++ /dev/null @@ -1,945 +0,0 @@ -/** - * OpenCodeAgent のユニットテスト。 - * @opencode-ai/sdk/v2 をモックし、各パブリックメソッドが正しいパラメータで SDK を呼び出し、 - * mapper を通してドメイン型に変換されることを検証する。 - */ -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; - -// --- SDK モック --- - -/** SDK クライアントのモックを生成する */ -function createMockSdkClient() { - return { - session: { - list: vi.fn().mockResolvedValue({ data: [] }), - create: vi.fn().mockResolvedValue({ data: { id: "sess-1", title: "Test" } }), - get: vi.fn().mockResolvedValue({ data: { id: "sess-1" } }), - delete: vi.fn().mockResolvedValue(undefined), - fork: vi.fn().mockResolvedValue({ data: { id: "sess-2" } }), - messages: vi.fn().mockResolvedValue({ data: [] }), - promptAsync: vi.fn().mockResolvedValue(undefined), - abort: vi.fn().mockResolvedValue(undefined), - shell: vi.fn().mockResolvedValue(undefined), - children: vi.fn().mockResolvedValue({ data: [] }), - todo: vi.fn().mockResolvedValue({ data: [] }), - share: vi.fn().mockResolvedValue({ data: { id: "sess-1", share: { url: "https://example.com" } } }), - unshare: vi.fn().mockResolvedValue({ data: { id: "sess-1" } }), - diff: vi.fn().mockResolvedValue({ data: [] }), - revert: vi.fn().mockResolvedValue({ data: { id: "sess-1" } }), - unrevert: vi.fn().mockResolvedValue({ data: { id: "sess-1" } }), - summarize: vi.fn().mockResolvedValue(undefined), - }, - config: { - providers: vi.fn().mockResolvedValue({ data: { providers: [], default: {} } }), - get: vi.fn().mockResolvedValue({ data: {} }), - update: vi.fn().mockResolvedValue(undefined), - }, - provider: { - list: vi.fn().mockResolvedValue({ data: { all: [], default: {}, connected: [] } }), - }, - permission: { - reply: vi.fn().mockResolvedValue(undefined), - }, - question: { - reply: vi.fn().mockResolvedValue(undefined), - reject: vi.fn().mockResolvedValue(undefined), - }, - app: { - agents: vi.fn().mockResolvedValue({ data: [] }), - skills: vi.fn().mockResolvedValue({ data: [] }), - }, - mcp: { - status: vi.fn().mockResolvedValue({ data: {} }), - connect: vi.fn().mockResolvedValue(undefined), - disconnect: vi.fn().mockResolvedValue(undefined), - }, - tool: { - ids: vi.fn().mockResolvedValue({ data: ["tool-1", "tool-2"] }), - }, - path: { - get: vi - .fn() - .mockResolvedValue({ data: { config: "/home/.config/opencode", data: "/home/.local/share/opencode" } }), - }, - event: { - subscribe: vi.fn().mockResolvedValue({ - stream: (async function* () { - // デフォルトは空ストリーム - })(), - }), - }, - }; -} - -let mockClient: ReturnType; -const mockServerClose = vi.fn(); - -vi.mock("node:fs/promises", () => ({ - readFile: vi.fn(), - writeFile: vi.fn().mockResolvedValue(undefined), - mkdir: vi.fn().mockResolvedValue(undefined), -})); - -vi.mock("@opencode-ai/sdk/v2", () => ({ - createOpencodeServer: vi.fn().mockImplementation(() => - Promise.resolve({ - url: "http://localhost:12345", - close: mockServerClose, - }), - ), - createOpencodeClient: vi.fn().mockImplementation(() => mockClient), -})); - -import * as fs from "node:fs/promises"; -import { createOpencodeClient, createOpencodeServer } from "@opencode-ai/sdk/v2"; -// テスト対象 -import { OpenCodeAgent } from "../opencode-agent"; - -describe("OpenCodeAgent", () => { - let agent: OpenCodeAgent; - - beforeEach(() => { - mockClient = createMockSdkClient(); - // createOpencodeClient のモック実装を更新 - vi.mocked(createOpencodeClient).mockReturnValue(mockClient as never); - agent = new OpenCodeAgent(); - }); - - afterEach(() => { - agent.disconnect(); - vi.clearAllMocks(); - }); - - // ============================================================ - // getCapabilities - // ============================================================ - - describe("getCapabilities()", () => { - it("should return all capabilities as true", () => { - const caps = agent.getCapabilities(); - - expect(caps.sessionDelete).toBe(true); - expect(caps.sessionFork).toBe(true); - expect(caps.sessionRevert).toBe(true); - expect(caps.sessionShare).toBe(true); - expect(caps.sessionSummarize).toBe(true); - expect(caps.sessionDiff).toBe(true); - expect(caps.todo).toBe(true); - expect(caps.multiProvider).toBe(true); - expect(caps.permission).toBe(true); - expect(caps.mcp).toBe(true); - expect(caps.subAgent).toBe(true); - expect(caps.shell).toBe(true); - expect(caps.config).toBe(true); - }); - }); - - // ============================================================ - // connect / disconnect / lifecycle - // ============================================================ - - describe("connect()", () => { - it("should create server on port 0 and create client", async () => { - await agent.connect(); - - expect(createOpencodeServer).toHaveBeenCalledWith({ port: 0 }); - expect(createOpencodeClient).toHaveBeenCalledWith({ baseUrl: "http://localhost:12345" }); - }); - - it("should subscribe to SSE events after connecting", async () => { - await agent.connect(); - - expect(mockClient.event.subscribe).toHaveBeenCalled(); - }); - - it("should expose serverUrl via getServerUrl() after connecting", async () => { - expect(agent.getServerUrl()).toBeUndefined(); - await agent.connect(); - expect(agent.getServerUrl()).toBe("http://localhost:12345"); - }); - }); - - describe("disconnect()", () => { - it("should abort SSE, close server, and clear state", async () => { - await agent.connect(); - - agent.disconnect(); - - expect(mockServerClose).toHaveBeenCalled(); - expect(agent.getServerUrl()).toBeUndefined(); - }); - - it("should be idempotent (no crash when called without connect)", () => { - expect(() => agent.disconnect()).not.toThrow(); - }); - - it("should clear event listeners", async () => { - await agent.connect(); - const listener = vi.fn(); - agent.onEvent(listener); - - agent.disconnect(); - - // After disconnect, listeners should be cleared. - // Reconnect and fire events — old listener should NOT be called. - await agent.connect(); - // 新しいストリームからイベントを流しても、旧リスナーは呼ばれない - // (disconnect で listeners.clear() されているため) - }); - }); - - describe("requireClient() (via public methods)", () => { - it("should throw when not connected", async () => { - await expect(agent.listSessions()).rejects.toThrow("OpenCode client is not connected. Call connect() first."); - }); - }); - - // ============================================================ - // Session API - // ============================================================ - - describe("listSessions()", () => { - it("should call client.session.list() and return mapped data", async () => { - const sessions = [{ id: "s1" }, { id: "s2" }]; - mockClient.session.list.mockResolvedValue({ data: sessions }); - await agent.connect(); - - const result = await agent.listSessions(); - - expect(mockClient.session.list).toHaveBeenCalled(); - expect(result).toEqual(sessions); - }); - }); - - describe("createSession()", () => { - it("should call client.session.create() with title", async () => { - await agent.connect(); - - await agent.createSession("My Session"); - - expect(mockClient.session.create).toHaveBeenCalledWith({ - title: "My Session", - }); - }); - - it("should pass undefined title when not provided", async () => { - await agent.connect(); - - await agent.createSession(); - - expect(mockClient.session.create).toHaveBeenCalledWith({ - title: undefined, - }); - }); - }); - - describe("getSession()", () => { - it("should call client.session.get() with correct sessionID", async () => { - await agent.connect(); - - await agent.getSession("sess-1"); - - expect(mockClient.session.get).toHaveBeenCalledWith({ - sessionID: "sess-1", - }); - }); - }); - - describe("deleteSession()", () => { - it("should call client.session.delete() with correct sessionID", async () => { - await agent.connect(); - - await agent.deleteSession("sess-1"); - - expect(mockClient.session.delete).toHaveBeenCalledWith({ - sessionID: "sess-1", - }); - }); - }); - - describe("forkSession()", () => { - it("should call with messageId when provided", async () => { - await agent.connect(); - - await agent.forkSession("sess-1", "msg-5"); - - expect(mockClient.session.fork).toHaveBeenCalledWith({ - sessionID: "sess-1", - messageID: "msg-5", - }); - }); - - it("should call with undefined messageID when not provided", async () => { - await agent.connect(); - - await agent.forkSession("sess-1"); - - expect(mockClient.session.fork).toHaveBeenCalledWith({ - sessionID: "sess-1", - messageID: undefined, - }); - }); - }); - - // ============================================================ - // Message API - // ============================================================ - - describe("getMessages()", () => { - it("should call with correct sessionId", async () => { - await agent.connect(); - - await agent.getMessages("sess-1"); - - expect(mockClient.session.messages).toHaveBeenCalledWith({ - sessionID: "sess-1", - }); - }); - }); - - describe("sendMessage()", () => { - it("should send text-only message", async () => { - await agent.connect(); - - await agent.sendMessage("sess-1", "Hello"); - - expect(mockClient.session.promptAsync).toHaveBeenCalledWith({ - sessionID: "sess-1", - parts: [{ type: "text", text: "Hello" }], - model: undefined, - agent: undefined, - }); - }); - - it("should send message with model via options", async () => { - await agent.connect(); - const model = { providerID: "anthropic", modelID: "claude-4" }; - - await agent.sendMessage("sess-1", "Hello", { model }); - - expect(mockClient.session.promptAsync).toHaveBeenCalledWith({ - sessionID: "sess-1", - parts: [{ type: "text", text: "Hello" }], - model, - agent: undefined, - }); - }); - - it("should convert relative file paths to absolute using workspaceFolder", async () => { - await agent.connect(); - agent.workspaceFolder = "/workspace/project"; - const files = [{ filePath: "src/index.ts", fileName: "index.ts" }]; - - await agent.sendMessage("sess-1", "Check this", { files }); - - const call = mockClient.session.promptAsync.mock.calls[0][0]; - expect(call.parts).toHaveLength(2); - expect(call.parts[1]).toEqual({ - type: "file", - mime: "text/plain", - url: "file:///workspace/project/src/index.ts", - filename: "index.ts", - }); - }); - - it("should not modify absolute file paths", async () => { - await agent.connect(); - const files = [{ filePath: "/absolute/path/file.ts", fileName: "file.ts" }]; - - await agent.sendMessage("sess-1", "Check", { files }); - - const call = mockClient.session.promptAsync.mock.calls[0][0]; - expect(call.parts[1]).toEqual({ - type: "file", - mime: "text/plain", - url: "file:///absolute/path/file.ts", - filename: "file.ts", - }); - }); - - it("should add agent part when agent is provided via options", async () => { - await agent.connect(); - - await agent.sendMessage("sess-1", "Hello", { agent: "code-reviewer" }); - - const call = mockClient.session.promptAsync.mock.calls[0][0]; - expect(call.parts).toHaveLength(2); - expect(call.parts[1]).toEqual({ type: "agent", name: "code-reviewer" }); - }); - - it("should prepend synthetic skill command when skill is provided", async () => { - await agent.connect(); - - await agent.sendMessage("sess-1", "Hello", { skill: "coding-guidelines" } as never); - - const call = mockClient.session.promptAsync.mock.calls[0][0]; - expect(call.parts).toHaveLength(2); - expect(call.parts[0]).toEqual({ type: "text", text: "/coding-guidelines", synthetic: true }); - expect(call.parts[1]).toEqual({ type: "text", text: "Hello" }); - }); - - it("should include all parts when files and agent are provided", async () => { - await agent.connect(); - agent.workspaceFolder = "/ws"; - const model = { providerID: "openai", modelID: "gpt-4" }; - const files = [{ filePath: "a.ts", fileName: "a.ts" }]; - - await agent.sendMessage("sess-1", "Review", { model, files, agent: "reviewer" }); - - const call = mockClient.session.promptAsync.mock.calls[0][0]; - expect(call.parts).toHaveLength(3); - expect(call.parts[0]).toEqual({ type: "text", text: "Review" }); - expect(call.parts[1].type).toBe("file"); - expect(call.parts[2]).toEqual({ type: "agent", name: "reviewer" }); - expect(call.model).toEqual(model); - }); - }); - - describe("abortSession()", () => { - it("should call client.session.abort()", async () => { - await agent.connect(); - - await agent.abortSession("sess-1"); - - expect(mockClient.session.abort).toHaveBeenCalledWith({ - sessionID: "sess-1", - }); - }); - }); - - // ============================================================ - // Shell API - // ============================================================ - - describe("executeShell()", () => { - it("should call client.session.shell() with correct args", async () => { - await agent.connect(); - const model = { providerID: "openai", modelID: "gpt-4" }; - - await agent.executeShell("sess-1", "ls -la", model); - - expect(mockClient.session.shell).toHaveBeenCalledWith({ - sessionID: "sess-1", - agent: "default", - command: "ls -la", - model, - }); - }); - - it("should pass undefined model when not provided", async () => { - await agent.connect(); - - await agent.executeShell("sess-1", "pwd"); - - expect(mockClient.session.shell).toHaveBeenCalledWith({ - sessionID: "sess-1", - agent: "default", - command: "pwd", - model: undefined, - }); - }); - }); - - // ============================================================ - // Provider API - // ============================================================ - - describe("getProviders()", () => { - it("should return providers and default from config.providers()", async () => { - const data = { providers: [{ id: "p1" }], default: { model: "claude-4" } }; - mockClient.config.providers.mockResolvedValue({ data }); - await agent.connect(); - - const result = await agent.getProviders(); - - expect(result).toEqual(data); - }); - }); - - describe("listAllProviders()", () => { - it("should return provider list from provider.list()", async () => { - const data = { all: [{ id: "p1" }], default: {}, connected: ["p1"] }; - mockClient.provider.list.mockResolvedValue({ data }); - await agent.connect(); - - const result = await agent.listAllProviders(); - - expect(result).toEqual(data); - }); - }); - - // ============================================================ - // Permission API - // ============================================================ - - describe("replyPermission()", () => { - it("should call permission.reply with correct requestID and reply", async () => { - await agent.connect(); - - await agent.replyPermission("sess-1", "perm-1", "always"); - - expect(mockClient.permission.reply).toHaveBeenCalledWith({ - requestID: "perm-1", - reply: "always", - }); - }); - }); - - // ============================================================ - // Session Children API - // ============================================================ - - describe("getChildSessions()", () => { - it("should call client.session.children()", async () => { - const children = [{ id: "child-1" }]; - mockClient.session.children.mockResolvedValue({ data: children }); - await agent.connect(); - - const result = await agent.getChildSessions("sess-1"); - - expect(mockClient.session.children).toHaveBeenCalledWith({ sessionID: "sess-1" }); - expect(result).toEqual(children); - }); - }); - - // ============================================================ - // Session Todo API - // ============================================================ - - describe("getSessionTodos()", () => { - it("should call client.session.todo()", async () => { - const todos = [{ id: "t1", text: "Fix bug" }]; - mockClient.session.todo.mockResolvedValue({ data: todos }); - await agent.connect(); - - const result = await agent.getSessionTodos("sess-1"); - - expect(mockClient.session.todo).toHaveBeenCalledWith({ sessionID: "sess-1" }); - expect(result).toEqual(todos); - }); - }); - - // ============================================================ - // Session Share API - // ============================================================ - - describe("shareSession()", () => { - it("should call client.session.share() and return session", async () => { - const session = { id: "sess-1", share: { url: "https://share.example.com" } }; - mockClient.session.share.mockResolvedValue({ data: session }); - await agent.connect(); - - const result = await agent.shareSession("sess-1"); - - expect(mockClient.session.share).toHaveBeenCalledWith({ sessionID: "sess-1" }); - expect(result).toEqual(session); - }); - }); - - describe("unshareSession()", () => { - it("should call client.session.unshare() and return session", async () => { - const session = { id: "sess-1" }; - mockClient.session.unshare.mockResolvedValue({ data: session }); - await agent.connect(); - - const result = await agent.unshareSession("sess-1"); - - expect(mockClient.session.unshare).toHaveBeenCalledWith({ sessionID: "sess-1" }); - expect(result).toEqual(session); - }); - }); - - // ============================================================ - // Agent API - // ============================================================ - - describe("getAgents()", () => { - it("should call app.agents()", async () => { - const agents = [{ id: "agent-1" }]; - mockClient.app.agents.mockResolvedValue({ data: agents }); - await agent.connect(); - - const result = await agent.getAgents(); - - expect(mockClient.app.agents).toHaveBeenCalled(); - expect(result).toEqual(agents); - }); - }); - - // ============================================================ - // Session Diff API - // ============================================================ - - describe("getSessionDiff()", () => { - it("should call client.session.diff()", async () => { - const diffs = [{ path: "file.ts", before: "a", after: "b" }]; - mockClient.session.diff.mockResolvedValue({ data: diffs }); - await agent.connect(); - - const result = await agent.getSessionDiff("sess-1"); - - expect(mockClient.session.diff).toHaveBeenCalledWith({ sessionID: "sess-1" }); - expect(result).toEqual(diffs); - }); - }); - - // ============================================================ - // Revert / Unrevert API - // ============================================================ - - describe("revertSession()", () => { - it("should call client.session.revert() with sessionId and messageID", async () => { - await agent.connect(); - - await agent.revertSession("sess-1", "msg-3"); - - expect(mockClient.session.revert).toHaveBeenCalledWith({ - sessionID: "sess-1", - messageID: "msg-3", - }); - }); - }); - - describe("unrevertSession()", () => { - it("should call client.session.unrevert()", async () => { - await agent.connect(); - - await agent.unrevertSession("sess-1"); - - expect(mockClient.session.unrevert).toHaveBeenCalledWith({ - sessionID: "sess-1", - }); - }); - }); - - // ============================================================ - // Summarize API - // ============================================================ - - describe("summarizeSession()", () => { - it("should call with model when provided", async () => { - await agent.connect(); - const model = { providerID: "openai", modelID: "gpt-4" }; - - await agent.summarizeSession("sess-1", model); - - expect(mockClient.session.summarize).toHaveBeenCalledWith({ - sessionID: "sess-1", - providerID: "openai", - modelID: "gpt-4", - }); - }); - - it("should pass undefined model when not provided", async () => { - await agent.connect(); - - await agent.summarizeSession("sess-1"); - - expect(mockClient.session.summarize).toHaveBeenCalledWith({ - sessionID: "sess-1", - providerID: undefined, - modelID: undefined, - }); - }); - }); - - // ============================================================ - // MCP API - // ============================================================ - - describe("getMcpStatus()", () => { - it("should call mcp.status()", async () => { - const status = { server1: { connected: true } }; - mockClient.mcp.status.mockResolvedValue({ data: status }); - await agent.connect(); - - const result = await agent.getMcpStatus(); - - expect(mockClient.mcp.status).toHaveBeenCalled(); - expect(result).toEqual(status); - }); - }); - - describe("connectMcp()", () => { - it("should call mcp.connect() with name", async () => { - await agent.connect(); - - await agent.connectMcp("my-server"); - - expect(mockClient.mcp.connect).toHaveBeenCalledWith({ name: "my-server" }); - }); - }); - - describe("disconnectMcp()", () => { - it("should call mcp.disconnect() with name", async () => { - await agent.connect(); - - await agent.disconnectMcp("my-server"); - - expect(mockClient.mcp.disconnect).toHaveBeenCalledWith({ name: "my-server" }); - }); - }); - - // ============================================================ - // Tool API - // ============================================================ - - describe("getToolIds()", () => { - it("should call tool.ids() and return ToolListItem[] via mapper", async () => { - await agent.connect(); - - const result = await agent.getToolIds(); - - expect(mockClient.tool.ids).toHaveBeenCalled(); - // mapToolIds wraps each string into { id } - expect(result).toEqual([{ id: "tool-1" }, { id: "tool-2" }]); - }); - }); - - describe("getSkills()", () => { - it("should call app.skills() and return mapped skills", async () => { - mockClient.app.skills.mockResolvedValue({ - data: [{ name: "coding-guidelines", description: "desc", location: "/skills/coding-guidelines" }], - }); - await agent.connect(); - - const result = await agent.getSkills(); - - expect(mockClient.app.skills).toHaveBeenCalled(); - expect(result).toEqual([ - { name: "coding-guidelines", description: "desc", location: "/skills/coding-guidelines" }, - ]); - }); - }); - - // ============================================================ - // Config API - // ============================================================ - - describe("getConfig()", () => { - it("should call config.get()", async () => { - const config = { model: "claude-4" }; - mockClient.config.get.mockResolvedValue({ data: config }); - await agent.connect(); - - const result = await agent.getConfig(); - - expect(mockClient.config.get).toHaveBeenCalled(); - expect(result).toEqual(config); - }); - }); - - describe("updateConfig()", () => { - it("should call config.update() with config param", async () => { - await agent.connect(); - - await agent.updateConfig({ model: "gpt-4" } as never); - - expect(mockClient.config.update).toHaveBeenCalledWith({ - config: { model: "gpt-4" }, - }); - }); - }); - - // ============================================================ - // Path API - // ============================================================ - - describe("getPath()", () => { - it("should call path.get() and return mapped data", async () => { - await agent.connect(); - - const result = await agent.getPath(); - - expect(mockClient.path.get).toHaveBeenCalled(); - expect(result).toEqual({ - config: "/home/.config/opencode", - data: "/home/.local/share/opencode", - }); - }); - }); - - // ============================================================ - // Event System - // ============================================================ - - describe("onEvent()", () => { - it("should register listener and return Disposable", async () => { - await agent.connect(); - const listener = vi.fn(); - - const disposable = agent.onEvent(listener); - - expect(disposable).toBeDefined(); - expect(typeof disposable.dispose).toBe("function"); - }); - - it("should deliver events from SSE stream to listeners", async () => { - const events = [ - { type: "session.updated", properties: { id: "sess-1" } }, - { type: "message.created", properties: { id: "msg-1" } }, - ]; - let resolveStream!: () => void; - const streamDone = new Promise((r) => { - resolveStream = r; - }); - - mockClient.event.subscribe.mockResolvedValue({ - stream: (async function* () { - for (const event of events) { - yield event; - } - resolveStream(); - })(), - }); - - const listener = vi.fn(); - agent.onEvent(listener); - await agent.connect(); - - // ストリームの消費は非同期なので少し待つ - await streamDone; - // microtask を消化 - await new Promise((r) => setTimeout(r, 0)); - - expect(listener).toHaveBeenCalledTimes(2); - expect(listener).toHaveBeenCalledWith(events[0]); - expect(listener).toHaveBeenCalledWith(events[1]); - }); - - it("should remove listener when Disposable is disposed", async () => { - // ストリームを手動制御するためのセットアップ - let emitEvent: ((event: unknown) => void) | undefined; - let endStream: (() => void) | undefined; - - mockClient.event.subscribe.mockResolvedValue({ - stream: (async function* () { - const queue: unknown[] = []; - let resolve: (() => void) | undefined; - let done = false; - - emitEvent = (event: unknown) => { - queue.push(event); - resolve?.(); - }; - endStream = () => { - done = true; - resolve?.(); - }; - - while (!done) { - if (queue.length > 0) { - yield queue.shift()!; - } else { - await new Promise((r) => { - resolve = r; - }); - } - } - })(), - }); - - await agent.connect(); - const listener = vi.fn(); - const disposable = agent.onEvent(listener); - - // イベントを1つ送信 - emitEvent?.({ type: "test-event-1" }); - await new Promise((r) => setTimeout(r, 10)); - expect(listener).toHaveBeenCalledTimes(1); - - // Dispose してからイベントを送信 — 呼ばれないはず - disposable.dispose(); - emitEvent?.({ type: "test-event-2" }); - await new Promise((r) => setTimeout(r, 10)); - expect(listener).toHaveBeenCalledTimes(1); - - endStream?.(); - }); - }); - - describe("resubscribeEvents()", () => { - it("should abort old stream and create new subscription", async () => { - await agent.connect(); - - // 初回の subscribe 呼び出しを確認 - expect(mockClient.event.subscribe).toHaveBeenCalledTimes(1); - - await agent.resubscribeEvents(); - - // 2回目の subscribe 呼び出し(旧ストリームの abort + 新ストリーム開始) - expect(mockClient.event.subscribe).toHaveBeenCalledTimes(2); - }); - }); - - // ============================================================ - // workspaceFolder - // ============================================================ - - describe("workspaceFolder", () => { - it("should be settable and readable", () => { - agent.workspaceFolder = "/my/workspace"; - expect(agent.workspaceFolder).toBe("/my/workspace"); - }); - }); - - // ============================================================ - // getServerUrl - // ============================================================ - - describe("getServerUrl()", () => { - it("should return undefined before connect", () => { - expect(agent.getServerUrl()).toBeUndefined(); - }); - - it("should return server URL after connect", async () => { - await agent.connect(); - expect(agent.getServerUrl()).toBe("http://localhost:12345"); - }); - - it("should return undefined after disconnect", async () => { - await agent.connect(); - agent.disconnect(); - expect(agent.getServerUrl()).toBeUndefined(); - }); - }); - - // ============================================================ - // setModel - // ============================================================ - - describe("setModel()", () => { - beforeEach(async () => { - // Connect so that getPath() (requireClient) works - await agent.connect(); - }); - - it("should read existing config, set model, and write back", async () => { - vi.mocked(fs.readFile).mockResolvedValue('{"theme":"dark"}'); - - await agent.setModel!("anthropic/claude-4"); - - expect(fs.readFile).toHaveBeenCalledWith(expect.stringContaining("opencode.json"), "utf-8"); - expect(fs.mkdir).toHaveBeenCalled(); - // Verify the written JSON contains both the existing key and the new model - const writeCall = vi.mocked(fs.writeFile).mock.calls[0]; - const written = JSON.parse((writeCall[1] as string).trim()); - expect(written).toEqual({ theme: "dark", model: "anthropic/claude-4" }); - }); - - it("should create config from empty object when file does not exist", async () => { - vi.mocked(fs.readFile).mockRejectedValue(new Error("ENOENT")); - - await agent.setModel!("openai/gpt-4"); - - const writeCall = vi.mocked(fs.writeFile).mock.calls[0]; - const written = JSON.parse((writeCall[1] as string).trim()); - expect(written).toEqual({ model: "openai/gpt-4" }); - }); - - it("should throw if agent is not connected", async () => { - agent.disconnect(); - await expect(agent.setModel!("some-model")).rejects.toThrow("OpenCode client is not connected"); - }); - }); -}); diff --git a/packages/agents/opencode/src/index.ts b/packages/agents/opencode/src/index.ts deleted file mode 100644 index 2716809..0000000 --- a/packages/agents/opencode/src/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// @opencodegui/agent-opencode - OpenCode agent implementation - -export * from "./mappers"; -export { OpenCodeAgent } from "./opencode-agent"; diff --git a/packages/agents/opencode/src/mappers.ts b/packages/agents/opencode/src/mappers.ts deleted file mode 100644 index 750dd29..0000000 --- a/packages/agents/opencode/src/mappers.ts +++ /dev/null @@ -1,187 +0,0 @@ -/** - * @opencodegui/agent-opencode - SDK→Domain Type Mappers - * - * Converts types from @opencode-ai/sdk to @opencodegui/core domain types. - * Each mapper is a pure function with no side effects. - */ - -import type { - Agent, - Config, - Event, - Message, - Part, - Provider, - FileDiff as SdkFileDiff, - McpStatus as SdkMcpStatus, - Path as SdkPath, - Session, - Todo, -} from "@opencode-ai/sdk/v2"; - -import type { - AgentEvent, - AgentInfo, - AllProvidersData, - AppConfig, - AppPaths, - ChatMessage, - ChatMessageWithParts, - ChatSession, - FileDiff, - McpStatus, - MessagePart, - ProviderInfo, - SkillInfo, - TodoItem, - ToolListItem, -} from "@opencodegui/core"; - -// ============================================================ -// Session -// ============================================================ - -export function mapSession(session: Session): ChatSession { - // SDK Session type is structurally compatible — pass through - return session as unknown as ChatSession; -} - -export function mapSessions(sessions: Session[]): ChatSession[] { - return sessions.map(mapSession); -} - -// ============================================================ -// Message + Parts -// ============================================================ - -export function mapMessage(message: Message): ChatMessage { - return message as unknown as ChatMessage; -} - -export function mapPart(part: Part): MessagePart { - return part as unknown as MessagePart; -} - -export function mapMessageWithParts(data: { info: Message; parts: Part[] }): ChatMessageWithParts { - return { - info: mapMessage(data.info), - parts: data.parts.map(mapPart), - }; -} - -export function mapMessagesWithParts(data: Array<{ info: Message; parts: Part[] }>): ChatMessageWithParts[] { - return data.map(mapMessageWithParts); -} - -// ============================================================ -// Event -// ============================================================ - -export function mapEvent(event: Event): AgentEvent { - // SDK Event is a discriminated union structurally compatible with AgentEvent - return event as unknown as AgentEvent; -} - -// ============================================================ -// Provider -// ============================================================ - -export function mapProvider(provider: Provider): ProviderInfo { - return provider as unknown as ProviderInfo; -} - -export function mapProviders(providers: Provider[]): ProviderInfo[] { - return providers.map(mapProvider); -} - -// ============================================================ -// FileDiff -// ============================================================ - -export function mapFileDiff(diff: SdkFileDiff): FileDiff { - return diff as unknown as FileDiff; -} - -export function mapFileDiffs(diffs: SdkFileDiff[]): FileDiff[] { - return diffs.map(mapFileDiff); -} - -// ============================================================ -// Todo -// ============================================================ - -export function mapTodo(todo: Todo): TodoItem { - return todo as unknown as TodoItem; -} - -export function mapTodos(todos: Todo[]): TodoItem[] { - return todos.map(mapTodo); -} - -// ============================================================ -// Agent -// ============================================================ - -export function mapAgent(agent: Agent): AgentInfo { - return agent as unknown as AgentInfo; -} - -export function mapAgents(agents: Agent[]): AgentInfo[] { - return agents.map(mapAgent); -} - -export function mapSkills(skills: Array<{ name: string; description: string; location: string }>): SkillInfo[] { - return skills.map((skill) => ({ - name: skill.name, - description: skill.description, - location: skill.location, - })); -} - -// ============================================================ -// Config -// ============================================================ - -export function mapConfig(config: Config): AppConfig { - return config as unknown as AppConfig; -} - -// ============================================================ -// Path -// ============================================================ - -export function mapPath(sdkPath: SdkPath): AppPaths { - return sdkPath as unknown as AppPaths; -} - -// ============================================================ -// MCP Status -// ============================================================ - -export function mapMcpStatus(status: Record): McpStatus { - return status as unknown as McpStatus; -} - -// ============================================================ -// Tool IDs -// ============================================================ - -/** - * SDK's tool.ids() returns string[], but IAgent.getToolIds() returns ToolListItem[]. - * Wrap each string ID into a ToolListItem. - */ -export function mapToolIds(ids: string[]): ToolListItem[] { - return ids.map((id) => ({ id })); -} - -// ============================================================ -// AllProvidersData -// ============================================================ - -export function mapAllProvidersData(data: { - all: Array; - default: Record; - connected: string[]; -}): AllProvidersData { - return data as unknown as AllProvidersData; -} diff --git a/packages/agents/opencode/src/opencode-agent.ts b/packages/agents/opencode/src/opencode-agent.ts deleted file mode 100644 index 9740369..0000000 --- a/packages/agents/opencode/src/opencode-agent.ts +++ /dev/null @@ -1,470 +0,0 @@ -/** - * @opencodegui/agent-opencode - OpenCodeAgent - * - * Implements the IAgent interface from @opencodegui/core, wrapping the - * @opencode-ai/sdk to communicate with an OpenCode server. - * - * This is a direct port of the original `opencode-client.ts` (OpenCodeConnection), - * adapted to the IAgent contract with SDK→domain type conversion via mappers. - */ - -import * as fs from "node:fs/promises"; -import * as path from "node:path"; -import { createOpencodeClient, createOpencodeServer, type Event, type OpencodeClient } from "@opencode-ai/sdk/v2"; -import type { - AgentCapabilities, - AgentEvent, - AgentInfo, - AllProvidersData, - AppConfig, - AppPaths, - ChatMessageWithParts, - ChatSession, - Disposable, - FileDiff, - IAgent, - McpStatus, - ModelRef, - PermissionResponse, - ProviderInfo, - QuestionAnswer, - SendMessageOptions, - SkillInfo, - TodoItem, - ToolListItem, -} from "@opencodegui/core"; -import { - mapAgents, - mapAllProvidersData, - mapConfig, - mapEvent, - mapFileDiffs, - mapMcpStatus, - mapMessagesWithParts, - mapPath, - mapProviders, - mapSession, - mapSessions, - mapSkills, - mapTodos, - mapToolIds, -} from "./mappers"; - -type EventHandler = (event: AgentEvent) => void; - -export class OpenCodeAgent implements IAgent { - private client: OpencodeClient | undefined; - private server: { url: string; close(): void } | undefined; - private sseAbortController: AbortController | undefined; - private listeners: Set = new Set(); - public workspaceFolder: string | undefined; - - // --- Capability declaration --- - - getCapabilities(): AgentCapabilities { - return { - sessionDelete: true, - sessionFork: true, - sessionRevert: true, - sessionShare: true, - sessionSummarize: true, - sessionDiff: true, - todo: true, - multiProvider: true, - permission: true, - question: true, - mcp: true, - subAgent: true, - shell: true, - config: true, - }; - } - - // --- Lifecycle --- - - async connect(): Promise { - // Port 0: let OS assign a free port to avoid conflicts - const server = await createOpencodeServer({ port: 0 }); - this.server = server; - this.client = createOpencodeClient({ - baseUrl: server.url, - }); - this.subscribeToEvents(); - } - - disconnect(): void { - this.sseAbortController?.abort(); - this.sseAbortController = undefined; - this.server?.close(); - this.server = undefined; - this.client = undefined; - this.listeners.clear(); - } - - // --- Event subscription --- - - onEvent(handler: (event: AgentEvent) => void): Disposable { - this.listeners.add(handler); - return { - dispose: () => { - this.listeners.delete(handler); - }, - }; - } - - /** Resubscribe to SSE stream (e.g. after config change) */ - async resubscribeEvents(): Promise { - await this.subscribeToEvents(); - } - - private async subscribeToEvents(): Promise { - const client = this.requireClient(); - // Abort existing stream before resubscribing - this.sseAbortController?.abort(); - this.sseAbortController = new AbortController(); - const result = await client.event.subscribe(undefined, { - signal: this.sseAbortController.signal, - }); - // Read SSE stream and dispatch to listeners - (async () => { - try { - for await (const event of result.stream) { - const mapped = mapEvent(event as Event); - for (const listener of this.listeners) { - listener(mapped); - } - } - } catch (error) { - // AbortError is normal stream termination - if (error instanceof DOMException && error.name === "AbortError") { - return; - } - throw error; - } - })(); - } - - // --- Sessions (common) --- - - async listSessions(): Promise { - const client = this.requireClient(); - const response = await client.session.list(); - return mapSessions(response.data!); - } - - async createSession(title?: string): Promise { - const client = this.requireClient(); - const response = await client.session.create({ - title, - }); - return mapSession(response.data!); - } - - async getSession(id: string): Promise { - const client = this.requireClient(); - const response = await client.session.get({ - sessionID: id, - }); - return mapSession(response.data!); - } - - // --- Sessions (capabilities-dependent) --- - - async deleteSession(id: string): Promise { - const client = this.requireClient(); - await client.session.delete({ - sessionID: id, - }); - } - - async forkSession(sessionId: string, messageId?: string): Promise { - const client = this.requireClient(); - const response = await client.session.fork({ - sessionID: sessionId, - messageID: messageId, - }); - return mapSession(response.data!); - } - - async revertSession(sessionId: string, messageId: string): Promise { - const client = this.requireClient(); - const response = await client.session.revert({ - sessionID: sessionId, - messageID: messageId, - }); - return mapSession(response.data!); - } - - async unrevertSession(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.unrevert({ - sessionID: sessionId, - }); - return mapSession(response.data!); - } - - async summarizeSession(sessionId: string, model?: ModelRef): Promise { - const client = this.requireClient(); - await client.session.summarize({ - sessionID: sessionId, - providerID: model?.providerID, - modelID: model?.modelID, - }); - } - - async shareSession(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.share({ - sessionID: sessionId, - }); - return mapSession(response.data!); - } - - async unshareSession(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.unshare({ - sessionID: sessionId, - }); - return mapSession(response.data!); - } - - // --- Messages --- - - async getMessages(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.messages({ - sessionID: sessionId, - }); - return mapMessagesWithParts(response.data!); - } - - async sendMessage(sessionId: string, text: string, options?: SendMessageOptions): Promise { - const client = this.requireClient(); - const parts: Array< - | { type: "text"; text: string; synthetic?: boolean } - | { type: "file"; mime: string; url: string; filename: string } - | { type: "agent"; name: string } - > = []; - - if (options?.skill) { - parts.push({ type: "text", text: `/${options.skill}`, synthetic: true }); - } - - parts.push({ type: "text", text }); - - if (options?.files) { - for (const file of options.files) { - // filePath is workspace-relative; resolve to absolute via cwd - const absPath = path.isAbsolute(file.filePath) - ? file.filePath - : path.resolve(this.workspaceFolder ?? ".", file.filePath); - parts.push({ - type: "file", - mime: "text/plain", - url: `file://${absPath}`, - filename: file.fileName, - }); - } - } - - // @agent mention triggers sub-agent invocation via AgentPartInput - if (options?.agent) { - parts.push({ type: "agent", name: options.agent }); - } - - await client.session.promptAsync({ - sessionID: sessionId, - parts, - model: options?.model, - agent: options?.primaryAgent, - }); - } - - async abortSession(sessionId: string): Promise { - const client = this.requireClient(); - await client.session.abort({ - sessionID: sessionId, - }); - } - - // --- Shell --- - - async executeShell(sessionId: string, command: string, model?: ModelRef): Promise { - const client = this.requireClient(); - await client.session.shell({ - sessionID: sessionId, - agent: "default", - command, - model, - }); - } - - // --- Providers & models --- - - async getProviders(): Promise<{ - providers: ProviderInfo[]; - default: Record; - }> { - const client = this.requireClient(); - const response = await client.config.providers(); - const data = response.data!; - return { - providers: mapProviders(data.providers), - default: data.default, - }; - } - - async listAllProviders(): Promise { - const client = this.requireClient(); - const response = await client.provider.list(); - return mapAllProvidersData(response.data!); - } - - // --- Agent list --- - - async getAgents(): Promise { - const client = this.requireClient(); - const response = await client.app.agents(); - return mapAgents(response.data!); - } - - async getSkills(): Promise { - const client = this.requireClient(); - const response = await client.app.skills(); - return mapSkills(response.data!); - } - - async getChildSessions(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.children({ - sessionID: sessionId, - }); - return mapSessions(response.data!); - } - - // --- Permissions --- - - async replyPermission(sessionId: string, permissionId: string, response: PermissionResponse): Promise { - const client = this.requireClient(); - await client.permission.reply({ - requestID: permissionId, - reply: response as "once" | "always" | "reject", - }); - } - - // --- Questions --- - - async replyQuestion(requestId: string, answers: QuestionAnswer[]): Promise { - const client = this.requireClient(); - await client.question.reply({ - requestID: requestId, - answers, - }); - } - - async rejectQuestion(requestId: string): Promise { - const client = this.requireClient(); - await client.question.reject({ - requestID: requestId, - }); - } - - // --- Session metadata --- - - async getSessionDiff(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.diff({ - sessionID: sessionId, - }); - return mapFileDiffs(response.data!); - } - - async getSessionTodos(sessionId: string): Promise { - const client = this.requireClient(); - const response = await client.session.todo({ - sessionID: sessionId, - }); - return mapTodos(response.data!); - } - - // --- Config --- - - async getConfig(): Promise { - const client = this.requireClient(); - const response = await client.config.get(); - return mapConfig(response.data!); - } - - async updateConfig(config: Partial): Promise { - const client = this.requireClient(); - await client.config.update({ config: config as Record }); - } - - async getPath(): Promise { - const client = this.requireClient(); - const response = await client.path.get(); - return mapPath(response.data!); - } - - // --- MCP --- - - async getMcpStatus(): Promise { - const client = this.requireClient(); - const response = await client.mcp.status(); - return mapMcpStatus(response.data!); - } - - async connectMcp(server: string): Promise { - const client = this.requireClient(); - await client.mcp.connect({ name: server }); - } - - async disconnectMcp(server: string): Promise { - const client = this.requireClient(); - await client.mcp.disconnect({ name: server }); - } - - // --- Tools --- - - async getToolIds(): Promise { - const client = this.requireClient(); - const response = await client.tool.ids(); - return mapToolIds(response.data!); - } - - // --- Server URL --- - - getServerUrl(): string | undefined { - return this.server?.url; - } - - // --- Model management (setModel) --- - - /** - * setModel is an OpenCode-specific workaround: the config.update API doesn't - * persist model changes, so we edit the opencode.json config file directly. - */ - async setModel(model: string): Promise { - const paths = await this.getPath(); - const configFilePath = path.join(paths.config, "opencode.json"); - let configJson: Record = {}; - try { - const raw = await fs.readFile(configFilePath, "utf-8"); - configJson = JSON.parse(raw); - } catch { - // File may not exist yet — start from empty object - } - configJson.model = model; - await fs.mkdir(path.dirname(configFilePath), { recursive: true }); - await fs.writeFile(configFilePath, `${JSON.stringify(configJson, null, 2)}\n`); - } - - // --- Private --- - - private requireClient(): OpencodeClient { - if (!this.client) { - throw new Error("OpenCode client is not connected. Call connect() first."); - } - return this.client; - } -} diff --git a/packages/agents/opencode/tsconfig.json b/packages/agents/opencode/tsconfig.json deleted file mode 100644 index 2276adc..0000000 --- a/packages/agents/opencode/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "bundler", - "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "composite": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/packages/agents/opencode/vitest.config.ts b/packages/agents/opencode/vitest.config.ts deleted file mode 100644 index 8696084..0000000 --- a/packages/agents/opencode/vitest.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - include: ["src/__tests__/**/*.test.ts"], - }, -}); diff --git a/packages/core/package.json b/packages/core/package.json deleted file mode 100644 index 0cdfd44..0000000 --- a/packages/core/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@opencodegui/core", - "version": "0.0.1", - "private": true, - "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "files": [ - "dist" - ], - "scripts": { - "build": "tsc -p tsconfig.json" - }, - "devDependencies": { - "typescript": "^5.7.0" - } -} diff --git a/packages/core/src/agent.interface.ts b/packages/core/src/agent.interface.ts deleted file mode 100644 index f8e841e..0000000 --- a/packages/core/src/agent.interface.ts +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @opencodegui/core - Agent Interface - * - * Defines the contract between the UI/platform layer and any coding agent. - * Each agent implementation (OpenCode, Claude Code, Codex, etc.) implements - * this interface, hiding transport details (HTTP, stdio, WebSocket, etc.). - */ - -import type { - AgentEvent, - AgentInfo, - AllProvidersData, - AppConfig, - AppPaths, - ChatMessageWithParts, - ChatSession, - Disposable, - FileDiff, - McpStatus, - ModelRef, - PermissionResponse, - ProviderInfo, - QuestionAnswer, - SendMessageOptions, - SkillInfo, - TodoItem, - ToolListItem, -} from "./domain"; - -/** Agent capability declarations */ -export type AgentCapabilities = { - /** Session deletion */ - sessionDelete: boolean; - /** Session fork (branch from any message) */ - sessionFork: boolean; - /** Session revert / unrevert (undo / redo) */ - sessionRevert: boolean; - /** Session sharing (URL generation) */ - sessionShare: boolean; - /** Session summarization / context compression */ - sessionSummarize: boolean; - /** Per-session file diffs */ - sessionDiff: boolean; - /** Todo management */ - todo: boolean; - /** Multi-provider model selection */ - multiProvider: boolean; - /** Permission management (tool execution approval flow) */ - permission: boolean; - /** Question interaction (AI asks user questions with options) */ - question: boolean; - /** MCP (Model Context Protocol) support */ - mcp: boolean; - /** Sub-agents (child sessions) */ - subAgent: boolean; - /** Shell command execution */ - shell: boolean; - /** Config management API */ - config: boolean; -}; - -export interface IAgent { - // --- Capability declaration --- - getCapabilities(): AgentCapabilities; - - // --- Lifecycle --- - connect(): Promise; - disconnect(): void; - - // --- Event subscription --- - onEvent(handler: (event: AgentEvent) => void): Disposable; - - // --- Sessions (common: all agents implement) --- - listSessions(): Promise; - createSession(title?: string): Promise; - getSession(id: string): Promise; - - // --- Sessions (capabilities-dependent) --- - deleteSession(id: string): Promise; - forkSession(sessionId: string, messageId?: string): Promise; - revertSession(sessionId: string, messageId: string): Promise; - unrevertSession(sessionId: string): Promise; - summarizeSession(sessionId: string, model?: ModelRef): Promise; - shareSession(sessionId: string): Promise; - unshareSession(sessionId: string): Promise; - - // --- Messages (common: all agents implement) --- - getMessages(sessionId: string): Promise; - sendMessage(sessionId: string, text: string, options?: SendMessageOptions): Promise; - abortSession(sessionId: string): Promise; - - // --- Shell (capabilities.shell) --- - executeShell(sessionId: string, command: string, model?: ModelRef): Promise; - - // --- Providers & models (capabilities.multiProvider) --- - getProviders(): Promise<{ - providers: ProviderInfo[]; - default: Record; - }>; - listAllProviders(): Promise; - - // --- Agent list (capabilities.subAgent) --- - getAgents(): Promise; - getSkills(): Promise; - getChildSessions(sessionId: string): Promise; - - // --- Permissions (capabilities.permission) --- - replyPermission(sessionId: string, permissionId: string, response: PermissionResponse): Promise; - - // --- Questions (capabilities.question) --- - replyQuestion(requestId: string, answers: QuestionAnswer[]): Promise; - rejectQuestion(requestId: string): Promise; - - // --- Session metadata (capabilities-dependent) --- - getSessionDiff(sessionId: string): Promise; - getSessionTodos(sessionId: string): Promise; - - // --- Config (capabilities.config) --- - getConfig(): Promise; - updateConfig(config: Partial): Promise; - getPath(): Promise; - - // --- MCP (capabilities.mcp) --- - getMcpStatus(): Promise; - connectMcp(server: string): Promise; - disconnectMcp(server: string): Promise; - - // --- Tools --- - getToolIds(): Promise; - - // --- Server URL (agent-specific, for terminal attachment etc.) --- - getServerUrl(): string | undefined; - - // --- Model management --- - setModel?(model: string): Promise; -} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts deleted file mode 100644 index 0f69786..0000000 --- a/packages/core/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -// @opencodegui/core - shared interfaces and domain types - -export * from "./agent.interface"; -export * from "./domain"; -export * from "./platform.interface"; -export * from "./protocol"; diff --git a/packages/core/src/platform.interface.ts b/packages/core/src/platform.interface.ts deleted file mode 100644 index fcbdfe3..0000000 --- a/packages/core/src/platform.interface.ts +++ /dev/null @@ -1,58 +0,0 @@ -/** - * @opencodegui/core - Platform Interface - * - * Defines the contract for platform-specific functionality. - * Each platform (VS Code, Electron, Web, etc.) implements these interfaces. - */ - -import type { Disposable, FileAttachment } from "./domain"; -import type { HostToUIMessage, UIToHostMessage } from "./protocol"; - -/** UI <-> Platform communication bridge */ -export interface IBridge { - postMessage(message: UIToHostMessage): void; - onMessage(handler: (message: HostToUIMessage) => void): Disposable; - getPersistedState(): UIPersistedState | null; - setPersistedState(state: UIPersistedState): void; -} - -export type SoundEventType = "responseComplete" | "permissionRequest" | "questionAsked" | "error"; - -export type SoundEventSetting = { - enabled?: boolean; - volume?: number; -}; - -export type SoundSettings = { - [K in SoundEventType]?: SoundEventSetting; -}; - -export type UIPersistedState = { - localeSetting?: "auto" | "en" | "ja"; - inputHistory?: string[]; - soundSettings?: SoundSettings; -}; - -/** Platform-specific services */ -export interface IPlatformServices { - /** Open a diff viewer */ - openDiffEditor(filePath: string, before: string, after: string): Promise; - - /** Copy text to clipboard */ - copyToClipboard(text: string): Promise; - - /** Open a terminal and connect to the agent's server */ - openTerminal(serverUrl: string, sessionId?: string): Promise; - - /** Open a config file in the editor */ - openConfigFile(filePath: string): Promise; - - /** Open a file in the editor, optionally at a specific line */ - openFile(filePath: string, line?: number): Promise; - - /** Search for files in the workspace */ - searchWorkspaceFiles(query: string): Promise; - - /** Get currently open editor files */ - getOpenEditors(): Promise; -} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json deleted file mode 100644 index 2276adc..0000000 --- a/packages/core/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "bundler", - "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "composite": true, - "declaration": true, - "declarationMap": true, - "sourceMap": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/packages/platforms/vscode/README.md b/packages/platforms/vscode/README.md deleted file mode 100644 index 9b287d2..0000000 --- a/packages/platforms/vscode/README.md +++ /dev/null @@ -1,156 +0,0 @@ -# OpenCodeGUI - -An unofficial VS Code sidebar chat interface for [OpenCode](https://github.com/anomalyco/opencode). - -OpenCode の非公式 VS Code サイドバーチャットインターフェース。 - -## Table of Contents / 目次 - -- [English](#english) -- [日本語](#japanese) - - - -## English - -### OpenCodeGUI - -Use all OpenCode features from a familiar sidebar chat UI. - -> **This is an unofficial, community-developed extension. It is not affiliated with or endorsed by the OpenCode project.** - -> [!CAUTION] -> **Disclaimer:** -> This project is experimental and developed primarily through AI-assisted coding. It is provided "as-is" without warranty of any kind. It may contain unexpected behavior, unconventional implementations, or undiscovered defects. Use at your own risk. The authors assume no liability for any damages arising from the use of this software. - -### Demo - -![Demo](https://raw.githubusercontent.com/ktmage/opencode-gui/master/packages/platforms/vscode/media/demo.gif) - -### Features - -- Chat UI (send/receive messages, streaming display) -- Markdown rendering -- Tool call collapsible display -- Permission approval UI (Allow / Once / Deny) -- Session management (create, switch, fork, delete) -- Message editing & checkpoint restore -- Model selection -- Agent selector for primary agent selection -- File context attachment -- File changes diff view -- Session diff review via [difit](https://github.com/yoshiko-pg/difit) (opens in browser) -- Shell command execution -- Reasoning / thinking display -- Todo display -- Undo / Redo -- Session sharing -- Agent mention (`@` mention) -- Child session navigation (subtask) -- Settings panel -- Keyboard navigation for inline popups (Tab / Arrow keys) -- Subtask display -- Auto-scroll during streaming -- File type icons -- File path links (clickable file chips with extension-based icons) -- Syntax highlighting and copy button for code blocks -- Quick-add button with active editor file -- Input history navigation (ArrowUp / ArrowDown) -- Sound notification on assistant response completion -- Question interaction UI for agent-initiated questions -- i18n support (English, Japanese, Simplified Chinese, Korean, Traditional Chinese, Spanish, Brazilian Portuguese, Russian) - -### Requirements - -- [OpenCode](https://github.com/anomalyco/opencode) installed -- LLM provider authentication configured in OpenCode - -#### Optional - -- [difit](https://github.com/yoshiko-pg/difit) — enables the session diff review feature. Install with `npm install -g difit`. - -### Installation - -Search for **OpenCodeGUI** in the VS Code Extensions view (`Ctrl+Shift+X` / `Cmd+Shift+X`) and click **Install**. - -### Contributing - -Contributions are welcome! See [CONTRIBUTING.md](https://github.com/ktmage/opencode-gui/blob/master/CONTRIBUTING.md) for details. - -### License - -[MIT](https://github.com/ktmage/opencode-gui/blob/master/LICENSE) - ---- - - - -## 日本語 - -### OpenCodeGUI - -OpenCode の全機能をサイドバーのチャット UI から操作できます。 - -> **本拡張機能は非公式のコミュニティ開発プロジェクトです。OpenCode プロジェクトとは提携・推薦関係にありません。** - -> [!CAUTION] -> **免責事項:** -> 本プロジェクトは実験的な取り組みであり、主に AI を活用したコーディングにより開発されています。いかなる保証もなく「現状のまま」提供されます。予期しない動作、一般的でない実装、未発見の不具合が含まれる可能性があります。ご利用は自己責任でお願いいたします。本ソフトウェアの使用により生じたいかなる損害についても、作者は一切の責任を負いません。 - -### デモ - -![デモ](https://raw.githubusercontent.com/ktmage/opencode-gui/master/packages/platforms/vscode/media/demo.gif) - -### 機能 - -- チャット UI(メッセージ送受信、ストリーミング表示) -- Markdown レンダリング -- ツールコールの折りたたみ表示 -- パーミッション承認 UI(Allow / Once / Deny) -- セッション管理(作成、切替、フォーク、削除) -- メッセージ編集とチェックポイント復元 -- モデル選択 -- エージェントセレクター(プライマリエージェント選択) -- ファイルコンテキスト添付 -- ファイル変更差分表示 -- [difit](https://github.com/yoshiko-pg/difit) によるセッション差分レビュー(ブラウザで表示) -- シェルコマンド実行 -- 推論(思考過程)表示 -- Todo 表示 -- Undo / Redo -- セッション共有 -- エージェントメンション(`@` メンション) -- 子セッションナビゲーション(サブタスク) -- 設定パネル -- インラインポップアップのキーボードナビゲーション(Tab / 矢印キー) -- サブタスク表示 -- ストリーミング中の自動スクロール -- ファイルタイプアイコン -- ファイルパスリンク(拡張子別アイコン付きクリッカブルチップ) -- コードブロックのシンタックスハイライト・コピーボタン -- Quick-add ボタン(アクティブエディタのファイル表示) -- 入力履歴ナビゲーション(ArrowUp / ArrowDown) -- サウンド通知(アシスタント応答完了時) -- 質問インタラクション UI(エージェントからの質問対応) -- 多言語対応(英語、日本語、簡体字中国語、韓国語、繁体字中国語、スペイン語、ブラジルポルトガル語、ロシア語) - -### 必要条件 - -- [OpenCode](https://github.com/anomalyco/opencode) がインストール済みであること -- OpenCode 側で LLM プロバイダの認証が完了していること - -#### オプション - -- [difit](https://github.com/yoshiko-pg/difit) — セッション差分レビュー機能を有効にします。`npm install -g difit` でインストール。 - -### インストール - -VS Code の拡張機能ビュー(`Ctrl+Shift+X` / `Cmd+Shift+X`)で **OpenCodeGUI** を検索し、**Install** をクリック。 - -### コントリビュート - -このプロジェクトへの貢献を歓迎します。詳しくは [CONTRIBUTING.md](https://github.com/ktmage/opencode-gui/blob/master/CONTRIBUTING.md) を参照してください。 - -### ライセンス - -[MIT](https://github.com/ktmage/opencode-gui/blob/master/LICENSE) diff --git a/packages/platforms/vscode/package.json b/packages/platforms/vscode/package.json deleted file mode 100644 index 858eedc..0000000 --- a/packages/platforms/vscode/package.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "name": "opencodegui", - "displayName": "%displayName%", - "description": "%description%", - "version": "0.5.3", - "publisher": "ktmage", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/ktmage/opencode-gui" - }, - "homepage": "https://github.com/ktmage/opencode-gui#readme", - "bugs": { - "url": "https://github.com/ktmage/opencode-gui/issues" - }, - "keywords": [ - "opencode", - "ai", - "chat", - "llm", - "coding-assistant" - ], - "icon": "media/icon.png", - "preview": true, - "qna": false, - "galleryBanner": { - "color": "#1e1e1e", - "theme": "dark" - }, - "engines": { - "vscode": "^1.100.0" - }, - "categories": [ - "AI", - "Chat" - ], - "activationEvents": [], - "main": "./dist/extension.js", - "contributes": { - "viewsContainers": { - "activitybar": [ - { - "id": "opencode", - "title": "OpenCode", - "icon": "$(comment-discussion)" - } - ] - }, - "views": { - "opencode": [ - { - "type": "webview", - "id": "opencode.chatView", - "name": "Chat" - } - ] - } - }, - "scripts": { - "build": "node esbuild.mjs && vite build", - "build:ext": "node esbuild.mjs", - "build:webview": "vite build", - "watch:ext": "node esbuild.mjs --watch", - "watch:webview": "vite build --watch", - "test": "vitest run --config vitest.config.ts", - "test:ext": "vitest run --config vitest.config.ext.ts", - "test:ext:watch": "vitest --config vitest.config.ext.ts", - "test:all": "vitest run --config vitest.config.ts && vitest run --config vitest.config.ext.ts", - "test:watch": "vitest --config vitest.config.ts", - "package": "vsce package --no-dependencies", - "publish": "vsce publish --no-dependencies" - }, - "devDependencies": { - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.2", - "@testing-library/user-event": "^14.6.1", - "@types/dompurify": "^3.0.5", - "@types/node": "^22.0.0", - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "@types/vscode": "^1.100.0", - "@vitejs/plugin-react": "^5.1.4", - "@vscode/vsce": "^3.7.1", - "esbuild": "^0.25.0", - "jsdom": "^28.1.0", - "marked": "^17.0.3", - "react": "^19.0.0", - "react-dom": "^19.0.0", - "typescript": "^5.7.0", - "vite": "^6.0.0", - "vitest": "^4.0.18" - }, - "dependencies": { - "@opencodegui/agent-opencode": "workspace:*", - "@opencodegui/core": "workspace:*", - "diff": "^8.0.0", - "dompurify": "^3.3.1", - "highlight.js": "^11.11.1", - "react-icons": "^5.5.0" - } -} diff --git a/packages/platforms/vscode/src/chat-view-provider.ts b/packages/platforms/vscode/src/chat-view-provider.ts deleted file mode 100644 index 0dc4f21..0000000 --- a/packages/platforms/vscode/src/chat-view-provider.ts +++ /dev/null @@ -1,398 +0,0 @@ -import * as fs from "node:fs/promises"; -import * as path from "node:path"; -import type { ChatSession, HostToUIMessage, IAgent, IPlatformServices, UIToHostMessage } from "@opencodegui/core"; -import * as vscode from "vscode"; -import type { DiffReviewManager } from "./diff-review-manager"; - -export class ChatViewProvider implements vscode.WebviewViewProvider { - public static readonly viewType = "opencode.chatView"; - - private view: vscode.WebviewView | undefined; - // OpenCode サーバーには「現在アクティブなセッション」を保持する API がないため、 - // UI クライアント側で管理する(TUI も同様の設計)。 - private activeSession: ChatSession | null = null; - - constructor( - private readonly extensionUri: vscode.Uri, - private readonly agent: IAgent, - private readonly platformServices: IPlatformServices, - private readonly diffReviewManager: DiffReviewManager, - private readonly difitAvailable: boolean, - ) {} - - resolveWebviewView( - webviewView: vscode.WebviewView, - _context: vscode.WebviewViewResolveContext, - _token: vscode.CancellationToken, - ): void { - this.view = webviewView; - - webviewView.webview.options = { - enableScripts: true, - localResourceRoots: [vscode.Uri.joinPath(this.extensionUri, "dist", "webview")], - }; - - webviewView.webview.html = this.getHtmlForWebview(webviewView.webview); - - webviewView.webview.onDidReceiveMessage((message: UIToHostMessage) => this.handleWebviewMessage(message)); - - // SSE イベントを Webview に転送する - this.agent.onEvent((event) => { - this.postMessage({ type: "event", event }); - }); - - // アクティブエディタが変わるたびに Webview に通知する - // (プッシュ型通知はメッセージルーターの責務として残す) - vscode.window.onDidChangeActiveTextEditor((editor) => { - this.postMessage({ type: "activeEditor", file: this.getActiveEditorFile(editor) }); - }); - } - - private async handleWebviewMessage(message: UIToHostMessage): Promise { - try { - await this.handleWebviewMessageInner(message); - } catch (err) { - console.error(`[OpenCode] Error handling message '${message.type}':`, err); - } - } - - private async handleWebviewMessageInner(message: UIToHostMessage): Promise { - switch (message.type) { - case "ready": { - // Webview の初期化完了時に init メッセージを送信する(locale + toolConfig を統合) - const paths = await this.agent.getPath(); - this.postMessage({ - type: "init", - capabilities: this.agent.getCapabilities(), - locale: vscode.env.language, - paths, - }); - // セッション一覧、現在のセッション、プロバイダー一覧を送信する - const sessions = await this.agent.listSessions(); - this.postMessage({ type: "sessions", sessions }); - this.postMessage({ type: "activeSession", session: this.activeSession }); - const [providersData, allProviders] = await Promise.all([ - this.agent.getProviders(), - this.agent.listAllProviders(), - ]); - // config ファイルから model を直接読み取る(config.get API は model を正しく返さない) - let configModel: string | undefined; - try { - const raw = await fs.readFile(path.join(paths.config, "opencode.json"), "utf-8"); - const configJson = JSON.parse(raw); - configModel = configJson.model; - } catch { - // ファイルが存在しない場合は undefined のまま - } - this.postMessage({ - type: "providers", - providers: providersData.providers, - allProviders, - default: providersData.default, - configModel, - }); - // 初期アクティブエディタを送信する - this.postMessage({ type: "activeEditor", file: this.getActiveEditorFile(vscode.window.activeTextEditor) }); - // difit の利用可否を Webview に通知する - this.postMessage({ type: "difitAvailable", available: this.difitAvailable }); - break; - } - case "sendMessage": { - await this.agent.sendMessage(message.sessionId, message.text, { - model: message.model, - files: message.files, - agent: message.agent, - primaryAgent: message.primaryAgent, - skill: message.skill, - }); - break; - } - case "createSession": { - const session = await this.agent.createSession(message.title); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - const sessions = await this.agent.listSessions(); - this.postMessage({ type: "sessions", sessions }); - break; - } - case "listSessions": { - const sessions = await this.agent.listSessions(); - this.postMessage({ type: "sessions", sessions }); - break; - } - case "selectSession": { - const session = await this.agent.getSession(message.sessionId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - const messages = await this.agent.getMessages(message.sessionId); - this.postMessage({ type: "messages", sessionId: message.sessionId, messages }); - break; - } - case "deleteSession": { - await this.agent.deleteSession(message.sessionId); - if (this.activeSession?.id === message.sessionId) { - this.activeSession = null; - this.postMessage({ type: "activeSession", session: null }); - } - const sessions = await this.agent.listSessions(); - this.postMessage({ type: "sessions", sessions }); - break; - } - case "getMessages": { - const messages = await this.agent.getMessages(message.sessionId); - this.postMessage({ type: "messages", sessionId: message.sessionId, messages }); - break; - } - case "replyPermission": { - await this.agent.replyPermission(message.sessionId, message.permissionId, message.response); - break; - } - case "replyQuestion": { - await this.agent.replyQuestion(message.requestId, message.answers); - break; - } - case "rejectQuestion": { - await this.agent.rejectQuestion(message.requestId); - break; - } - case "abort": { - await this.agent.abortSession(message.sessionId); - break; - } - case "getProviders": { - const [providersData, allProviders, paths] = await Promise.all([ - this.agent.getProviders(), - this.agent.listAllProviders(), - this.agent.getPath(), - ]); - let configModel: string | undefined; - try { - const raw = await fs.readFile(path.join(paths.config, "opencode.json"), "utf-8"); - configModel = JSON.parse(raw).model; - } catch { - // ignore - } - this.postMessage({ - type: "providers", - providers: providersData.providers, - allProviders, - default: providersData.default, - configModel, - }); - break; - } - // --- Platform operations delegated to IPlatformServices --- - case "getOpenEditors": { - const files = await this.platformServices.getOpenEditors(); - this.postMessage({ type: "openEditors", files }); - break; - } - case "searchWorkspaceFiles": { - const files = await this.platformServices.searchWorkspaceFiles(message.query); - this.postMessage({ type: "workspaceFiles", files }); - break; - } - case "compressSession": { - await this.agent.summarizeSession(message.sessionId, message.model); - break; - } - case "revertToMessage": { - const session = await this.agent.revertSession(message.sessionId, message.messageId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - const messages = await this.agent.getMessages(message.sessionId); - this.postMessage({ type: "messages", sessionId: message.sessionId, messages }); - break; - } - case "editAndResend": { - // 1. 指定メッセージまで巻き戻す(そのメッセージ以降を削除) - const session = await this.agent.revertSession(message.sessionId, message.messageId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - const msgs = await this.agent.getMessages(message.sessionId); - this.postMessage({ type: "messages", sessionId: message.sessionId, messages: msgs }); - // 2. 編集後のテキストを送信 - await this.agent.sendMessage(message.sessionId, message.text, { - model: message.model, - files: message.files, - }); - break; - } - case "executeShell": { - await this.agent.executeShell(message.sessionId, message.command, message.model); - break; - } - case "openConfigFile": { - await this.platformServices.openConfigFile(message.filePath); - break; - } - case "openTerminal": { - const serverUrl = this.agent.getServerUrl(); - if (!serverUrl) break; - await this.platformServices.openTerminal(serverUrl, this.activeSession?.id); - break; - } - case "setModel": { - // Delegate model persistence to the agent (OpenCode-specific config file workaround) - await this.agent.setModel!(message.model); - this.postMessage({ type: "modelUpdated", model: message.model, default: {} }); - break; - } - case "forkSession": { - // Fork で新しいセッションを作成し、アクティブセッションを切り替える - const forkedSession = await this.agent.forkSession(message.sessionId, message.messageId); - this.activeSession = forkedSession; - this.postMessage({ type: "activeSession", session: forkedSession }); - const forkedSessions = await this.agent.listSessions(); - this.postMessage({ type: "sessions", sessions: forkedSessions }); - break; - } - case "getSessionDiff": { - const diffs = await this.agent.getSessionDiff(message.sessionId); - this.postMessage({ type: "sessionDiff", sessionId: message.sessionId, diffs }); - break; - } - case "getSessionTodos": { - const todos = await this.agent.getSessionTodos(message.sessionId); - this.postMessage({ type: "sessionTodos", sessionId: message.sessionId, todos }); - break; - } - case "getChildSessions": { - const children = await this.agent.getChildSessions(message.sessionId); - this.postMessage({ type: "childSessions", sessionId: message.sessionId, children }); - break; - } - case "getAgents": { - const agents = await this.agent.getAgents(); - this.postMessage({ type: "agents", agents }); - break; - } - case "getSkills": { - const skills = await this.agent.getSkills(); - this.postMessage({ type: "skills", skills }); - break; - } - case "shareSession": { - const session = await this.agent.shareSession(message.sessionId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - // 共有 URL をクリップボードにコピーする - if (session.share?.url) { - await this.platformServices.copyToClipboard(session.share.url); - } - break; - } - case "unshareSession": { - const session = await this.agent.unshareSession(message.sessionId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - break; - } - case "copyToClipboard": { - await this.platformServices.copyToClipboard(message.text); - break; - } - case "undoSession": { - const session = await this.agent.revertSession(message.sessionId, message.messageId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - const messages = await this.agent.getMessages(message.sessionId); - this.postMessage({ type: "messages", sessionId: message.sessionId, messages }); - break; - } - case "redoSession": { - const session = await this.agent.unrevertSession(message.sessionId); - this.activeSession = session; - this.postMessage({ type: "activeSession", session }); - const messages = await this.agent.getMessages(message.sessionId); - this.postMessage({ type: "messages", sessionId: message.sessionId, messages }); - break; - } - case "openDiffEditor": { - await this.platformServices.openDiffEditor(message.filePath, message.before, message.after); - break; - } - case "openFile": { - await this.platformServices.openFile(message.filePath, message.line); - break; - } - case "openDiffReview": { - if (!this.activeSession) { - console.warn("[openDiffReview] No active session"); - break; - } - try { - console.log("[openDiffReview] Getting diffs for session:", this.activeSession.id); - const diffs = await this.agent.getSessionDiff(this.activeSession.id); - console.log("[openDiffReview] Got diffs:", diffs.length, "files"); - if (diffs.length === 0) { - console.warn("[openDiffReview] No diffs returned from agent"); - break; - } - await this.diffReviewManager.start(diffs, message.focusFile); - this.postMessage({ type: "diffReviewStarted" }); - } catch (e) { - const errorMsg = e instanceof Error ? e.message : String(e); - console.error("[openDiffReview]", errorMsg); - this.postMessage({ type: "diffReviewError", error: errorMsg }); - } - break; - } - case "stopDiffReview": { - this.diffReviewManager.stop(); - this.postMessage({ type: "diffReviewStopped" }); - break; - } - } - } - - /** アクティブなテキストエディタから FileAttachment を生成する。エディタがない場合は null を返す。 */ - private getActiveEditorFile( - editor: vscode.TextEditor | undefined, - ): import("@opencodegui/core").FileAttachment | null { - if (!editor) return null; - const uri = editor.document.uri; - // 出力パネルや設定画面など、file スキーム以外は対象外 - if (uri.scheme !== "file") return null; - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri; - const relativePath = workspaceFolder - ? path.relative(workspaceFolder.fsPath, uri.fsPath) - : path.basename(uri.fsPath); - return { filePath: relativePath, fileName: path.basename(uri.fsPath) }; - } - - private postMessage(message: HostToUIMessage): void { - this.view?.webview.postMessage(message); - } - - private getHtmlForWebview(webview: vscode.Webview): string { - const distUri = vscode.Uri.joinPath(this.extensionUri, "dist", "webview"); - - // Vite がビルドした JS/CSS アセットを参照する - const scriptUri = webview.asWebviewUri(vscode.Uri.joinPath(distUri, "assets", "index.js")); - const styleUri = webview.asWebviewUri(vscode.Uri.joinPath(distUri, "assets", "index.css")); - - const nonce = getNonce(); - - return /* html */ ` - - - - - - - - -
- - -`; - } -} - -function getNonce(): string { - const array = new Uint8Array(16); - crypto.getRandomValues(array); - return Array.from(array, (b) => b.toString(16).padStart(2, "0")).join(""); -} diff --git a/packages/platforms/vscode/src/extension.ts b/packages/platforms/vscode/src/extension.ts deleted file mode 100644 index 10f2237..0000000 --- a/packages/platforms/vscode/src/extension.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { execFile } from "node:child_process"; -import { OpenCodeAgent } from "@opencodegui/agent-opencode"; -import * as vscode from "vscode"; -import { ChatViewProvider } from "./chat-view-provider"; -import { DiffReviewManager } from "./diff-review-manager"; -import { VscodePlatformServices } from "./vscode-platform-services"; - -const agent = new OpenCodeAgent(); - -// Extension Host プロセスが強制終了された場合でもサーバーを停止する -process.on("exit", () => agent.disconnect()); - -export async function activate(context: vscode.ExtensionContext) { - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; - if (!workspaceFolder) { - vscode.window.showWarningMessage(vscode.l10n.t("OpenCodeGUI requires an open workspace folder.")); - return; - } - - // SDK の createOpencodeServer は cwd オプションを持たないため、 - // プロセスのカレントディレクトリを変更してからサーバーを起動する。 - const originalCwd = process.cwd(); - process.chdir(workspaceFolder); - try { - agent.workspaceFolder = workspaceFolder; - await agent.connect(); - } catch (error) { - const isNotFound = - error instanceof Error && - (("code" in error && (error as NodeJS.ErrnoException).code === "ENOENT") || error.message.includes("ENOENT")); - if (isNotFound) { - vscode.window.showWarningMessage( - vscode.l10n.t( - 'OpenCodeGUI: "opencode" command not found. Please install OpenCode first: https://github.com/anomalyco/opencode', - ), - ); - return; - } - throw error; - } finally { - process.chdir(originalCwd); - } - - const platformServices = new VscodePlatformServices(); - - // PATH 上に difit が存在するか確認する。 - // 存在しない場合はレビューボタンを非表示にするだけでエラーは出さない。 - const difitAvailable = await checkDifitAvailable(); - - const diffReviewManager = new DiffReviewManager(); - const chatViewProvider = new ChatViewProvider( - context.extensionUri, - agent, - platformServices, - diffReviewManager, - difitAvailable, - ); - context.subscriptions.push(vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, chatViewProvider)); - context.subscriptions.push(diffReviewManager); - - // diff エディタ用の仮想ドキュメントプロバイダー。 - // URI のクエリ部分にエンコードされたコンテンツを返す。 - const diffContentProvider: vscode.TextDocumentContentProvider = { - provideTextDocumentContent(uri: vscode.Uri): string { - return decodeURIComponent(uri.query); - }, - }; - context.subscriptions.push( - vscode.workspace.registerTextDocumentContentProvider("opencode-diff-before", diffContentProvider), - vscode.workspace.registerTextDocumentContentProvider("opencode-diff-after", diffContentProvider), - ); - - context.subscriptions.push(new vscode.Disposable(() => agent.disconnect())); -} - -export function deactivate() { - agent.disconnect(); -} - -/** PATH 上に difit コマンドが存在するかチェックする */ -function checkDifitAvailable(): Promise { - return new Promise((resolve) => { - execFile("which", ["difit"], (error) => { - resolve(!error); - }); - }); -} diff --git a/packages/platforms/vscode/src/vscode-platform-services.ts b/packages/platforms/vscode/src/vscode-platform-services.ts deleted file mode 100644 index e5c74d9..0000000 --- a/packages/platforms/vscode/src/vscode-platform-services.ts +++ /dev/null @@ -1,93 +0,0 @@ -/** - * VscodePlatformServices - IPlatformServices implementation for VS Code. - * - * Encapsulates all VS Code-specific platform operations that were previously - * embedded in ChatViewProvider's message handlers. - */ - -import * as path from "node:path"; -import type { FileAttachment, IPlatformServices } from "@opencodegui/core"; -import * as vscode from "vscode"; - -export class VscodePlatformServices implements IPlatformServices { - async openDiffEditor(filePath: string, before: string, after: string): Promise { - // 仮想ドキュメントを使って VS Code のネイティブ diff エディタを開く - const beforeUri = vscode.Uri.parse(`opencode-diff-before:${filePath}?${encodeURIComponent(before)}`); - const afterUri = vscode.Uri.parse(`opencode-diff-after:${filePath}?${encodeURIComponent(after)}`); - const fileName = path.basename(filePath); - await vscode.commands.executeCommand("vscode.diff", beforeUri, afterUri, `${fileName} (Changes)`); - } - - async copyToClipboard(text: string): Promise { - await vscode.env.clipboard.writeText(text); - } - - async openTerminal(serverUrl: string, sessionId?: string): Promise { - const args = ["attach", serverUrl]; - if (sessionId) { - args.push("--session", sessionId); - } - const wsFolder = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath; - const terminal = vscode.window.createTerminal({ - name: "OpenCode", - cwd: wsFolder, - }); - terminal.show(); - terminal.sendText(`opencode ${args.map((a) => JSON.stringify(a)).join(" ")}`); - } - - async openConfigFile(filePath: string): Promise { - const uri = vscode.Uri.file(filePath); - try { - await vscode.workspace.fs.stat(uri); - } catch { - // ファイルが存在しない場合は初期内容で作成する - const dir = vscode.Uri.file(filePath.substring(0, filePath.lastIndexOf("/"))); - await vscode.workspace.fs.createDirectory(dir); - await vscode.workspace.fs.writeFile(uri, Buffer.from('{\n "$schema": "https://opencode.ai/config.json"\n}\n')); - } - const doc = await vscode.workspace.openTextDocument(uri); - await vscode.window.showTextDocument(doc); - } - - async openFile(filePath: string, line?: number): Promise { - const uri = vscode.Uri.file(filePath); - const doc = await vscode.workspace.openTextDocument(uri); - const editor = await vscode.window.showTextDocument(doc); - if (line !== undefined && line >= 1) { - const position = new vscode.Position(line - 1, 0); - editor.selection = new vscode.Selection(position, position); - editor.revealRange(new vscode.Range(position, position), vscode.TextEditorRevealType.InCenter); - } - } - - async searchWorkspaceFiles(query: string): Promise { - const pattern = query ? `**/*${query}*` : "**/*"; - const uris = await vscode.workspace.findFiles(pattern, "**/node_modules/**", 20); - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri; - return uris.map((uri) => { - const relativePath = workspaceFolder - ? path.relative(workspaceFolder.fsPath, uri.fsPath) - : path.basename(uri.fsPath); - return { filePath: relativePath, fileName: path.basename(uri.fsPath) }; - }); - } - - async getOpenEditors(): Promise { - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]?.uri; - return ( - vscode.window.tabGroups.all - .flatMap((group) => group.tabs) - .filter((tab) => tab.input instanceof vscode.TabInputText) - .map((tab) => { - const uri = (tab.input as vscode.TabInputText).uri; - const relativePath = workspaceFolder - ? path.relative(workspaceFolder.fsPath, uri.fsPath) - : path.basename(uri.fsPath); - return { filePath: relativePath, fileName: path.basename(uri.fsPath) }; - }) - // 重複除去 - .filter((f, i, arr) => arr.findIndex((a) => a.filePath === f.filePath) === i) - ); - } -} diff --git a/packages/platforms/vscode/tsconfig.json b/packages/platforms/vscode/tsconfig.json deleted file mode 100644 index c2b161f..0000000 --- a/packages/platforms/vscode/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "bundler", - "lib": ["ES2022"], - "outDir": "./dist", - "rootDir": "./src", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "declaration": false, - "sourceMap": true, - "jsx": "react-jsx" - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "webview"] -} diff --git a/packages/platforms/vscode/vitest.config.ext.ts b/packages/platforms/vscode/vitest.config.ext.ts deleted file mode 100644 index 8f5a6d5..0000000 --- a/packages/platforms/vscode/vitest.config.ext.ts +++ /dev/null @@ -1,17 +0,0 @@ -import path from "node:path"; -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - resolve: { - alias: { - "@opencodegui/agent-opencode": path.resolve(__dirname, "../../agents/opencode/src/index.ts"), - "@opencodegui/core": path.resolve(__dirname, "../../core/src/index.ts"), - }, - }, - test: { - environment: "node", - globals: true, - include: ["src/__tests__/**/*.test.ts"], - setupFiles: ["src/__tests__/setup.ts"], - }, -}); diff --git a/packages/platforms/vscode/webview/utils/todo.ts b/packages/platforms/vscode/webview/utils/todo.ts deleted file mode 100644 index 7ad4f0a..0000000 --- a/packages/platforms/vscode/webview/utils/todo.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type TodoItem = { content: string; status?: string; priority?: string }; - -export function parseTodos(raw: unknown): TodoItem[] | null { - try { - const data = typeof raw === "string" ? JSON.parse(raw) : raw; - const arr = Array.isArray(data) ? data : (data?.todos ?? data?.items ?? null); - if (!Array.isArray(arr) || arr.length === 0) return null; - if (!arr.every((item: unknown) => typeof item === "object" && item !== null && "content" in item)) return null; - return arr as TodoItem[]; - } catch { - return null; - } -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index 1b59ff2..0000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,4445 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - devDependencies: - '@biomejs/biome': - specifier: 2.4.4 - version: 2.4.4 - - packages/agents/opencode: - dependencies: - '@opencode-ai/sdk': - specifier: ^1.2.10 - version: 1.2.17 - '@opencodegui/core': - specifier: workspace:* - version: link:../../core - devDependencies: - typescript: - specifier: ^5.7.0 - version: 5.9.3 - vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@22.19.13)(jsdom@28.1.0) - - packages/core: - devDependencies: - typescript: - specifier: ^5.7.0 - version: 5.9.3 - - packages/platforms/vscode: - dependencies: - '@opencodegui/agent-opencode': - specifier: workspace:* - version: link:../../agents/opencode - '@opencodegui/core': - specifier: workspace:* - version: link:../../core - diff: - specifier: ^8.0.0 - version: 8.0.3 - dompurify: - specifier: ^3.3.1 - version: 3.3.1 - highlight.js: - specifier: ^11.11.1 - version: 11.11.1 - react-icons: - specifier: ^5.5.0 - version: 5.6.0(react@19.2.4) - devDependencies: - '@testing-library/jest-dom': - specifier: ^6.9.1 - version: 6.9.1 - '@testing-library/react': - specifier: ^16.3.2 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@testing-library/user-event': - specifier: ^14.6.1 - version: 14.6.1(@testing-library/dom@10.4.1) - '@types/dompurify': - specifier: ^3.0.5 - version: 3.2.0 - '@types/node': - specifier: ^22.0.0 - version: 22.19.13 - '@types/react': - specifier: ^19.0.0 - version: 19.2.14 - '@types/react-dom': - specifier: ^19.0.0 - version: 19.2.3(@types/react@19.2.14) - '@types/vscode': - specifier: ^1.100.0 - version: 1.109.0 - '@vitejs/plugin-react': - specifier: ^5.1.4 - version: 5.1.4(vite@6.4.1(@types/node@22.19.13)) - '@vscode/vsce': - specifier: ^3.7.1 - version: 3.7.1 - esbuild: - specifier: ^0.25.0 - version: 0.25.12 - jsdom: - specifier: ^28.1.0 - version: 28.1.0 - marked: - specifier: ^17.0.3 - version: 17.0.4 - react: - specifier: ^19.0.0 - version: 19.2.4 - react-dom: - specifier: ^19.0.0 - version: 19.2.4(react@19.2.4) - typescript: - specifier: ^5.7.0 - version: 5.9.3 - vite: - specifier: ^6.0.0 - version: 6.4.1(@types/node@22.19.13) - vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@22.19.13)(jsdom@28.1.0) - -packages: - - '@acemir/cssom@0.9.31': - resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} - - '@adobe/css-tools@4.4.4': - resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - - '@asamuzakjp/css-color@5.0.1': - resolution: {integrity: sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/dom-selector@6.8.1': - resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - - '@azu/format-text@1.0.2': - resolution: {integrity: sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==} - - '@azu/style-format@1.0.1': - resolution: {integrity: sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==} - - '@azure/abort-controller@2.1.2': - resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} - engines: {node: '>=18.0.0'} - - '@azure/core-auth@1.10.1': - resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} - engines: {node: '>=20.0.0'} - - '@azure/core-client@1.10.1': - resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} - engines: {node: '>=20.0.0'} - - '@azure/core-rest-pipeline@1.22.2': - resolution: {integrity: sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==} - engines: {node: '>=20.0.0'} - - '@azure/core-tracing@1.3.1': - resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} - engines: {node: '>=20.0.0'} - - '@azure/core-util@1.13.1': - resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} - engines: {node: '>=20.0.0'} - - '@azure/identity@4.13.0': - resolution: {integrity: sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==} - engines: {node: '>=20.0.0'} - - '@azure/logger@1.3.0': - resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} - engines: {node: '>=20.0.0'} - - '@azure/msal-browser@4.29.0': - resolution: {integrity: sha512-/f3eHkSNUTl6DLQHm+bKecjBKcRQxbd/XLx8lvSYp8Nl/HRyPuIPOijt9Dt0sH50/SxOwQ62RnFCmFlGK+bR/w==} - engines: {node: '>=0.8.0'} - - '@azure/msal-common@15.15.0': - resolution: {integrity: sha512-/n+bN0AKlVa+AOcETkJSKj38+bvFs78BaP4rNtv3MJCmPH0YrHiskMRe74OhyZ5DZjGISlFyxqvf9/4QVEi2tw==} - engines: {node: '>=0.8.0'} - - '@azure/msal-node@3.8.8': - resolution: {integrity: sha512-+f1VrJH1iI517t4zgmuhqORja0bL6LDQXfBqkjuMmfTYXTQQnh1EvwwxO3UbKLT05N0obF72SRHFrC1RBDv5Gg==} - engines: {node: '>=16'} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.28.6': - resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.6': - resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.0': - resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} - 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'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@biomejs/biome@2.4.4': - resolution: {integrity: sha512-tigwWS5KfJf0cABVd52NVaXyAVv4qpUXOWJ1rxFL8xF1RVoeS2q/LK+FHgYoKMclJCuRoCWAPy1IXaN9/mS61Q==} - engines: {node: '>=14.21.3'} - hasBin: true - - '@biomejs/cli-darwin-arm64@2.4.4': - resolution: {integrity: sha512-jZ+Xc6qvD6tTH5jM6eKX44dcbyNqJHssfl2nnwT6vma6B1sj7ZLTGIk6N5QwVBs5xGN52r3trk5fgd3sQ9We9A==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [darwin] - - '@biomejs/cli-darwin-x64@2.4.4': - resolution: {integrity: sha512-Dh1a/+W+SUCXhEdL7TiX3ArPTFCQKJTI1mGncZNWfO+6suk+gYA4lNyJcBB+pwvF49uw0pEbUS49BgYOY4hzUg==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [darwin] - - '@biomejs/cli-linux-arm64-musl@2.4.4': - resolution: {integrity: sha512-+sPAXq3bxmFwhVFJnSwkSF5Rw2ZAJMH3MF6C9IveAEOdSpgajPhoQhbbAK12SehN9j2QrHpk4J/cHsa/HqWaYQ==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@biomejs/cli-linux-arm64@2.4.4': - resolution: {integrity: sha512-V/NFfbWhsUU6w+m5WYbBenlEAz8eYnSqRMDMAW3K+3v0tYVkNyZn8VU0XPxk/lOqNXLSCCrV7FmV/u3SjCBShg==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@biomejs/cli-linux-x64-musl@2.4.4': - resolution: {integrity: sha512-gGvFTGpOIQDb5CQ2VC0n9Z2UEqlP46c4aNgHmAMytYieTGEcfqhfCFnhs6xjt0S3igE6q5GLuIXtdQt3Izok+g==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@biomejs/cli-linux-x64@2.4.4': - resolution: {integrity: sha512-R4+ZCDtG9kHArasyBO+UBD6jr/FcFCTH8QkNTOCu0pRJzCWyWC4EtZa2AmUZB5h3e0jD7bRV2KvrENcf8rndBg==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@biomejs/cli-win32-arm64@2.4.4': - resolution: {integrity: sha512-trzCqM7x+Gn832zZHgr28JoYagQNX4CZkUZhMUac2YxvvyDRLJDrb5m9IA7CaZLlX6lTQmADVfLEKP1et1Ma4Q==} - engines: {node: '>=14.21.3'} - cpu: [arm64] - os: [win32] - - '@biomejs/cli-win32-x64@2.4.4': - resolution: {integrity: sha512-gnOHKVPFAAPrpoPt2t+Q6FZ7RPry/FDV3GcpU53P3PtLNnQjBmKyN2Vh/JtqXet+H4pme8CC76rScwdjDcT1/A==} - engines: {node: '>=14.21.3'} - cpu: [x64] - os: [win32] - - '@bramus/specificity@2.4.2': - resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} - hasBin: true - - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} - engines: {node: '>=20.19.0'} - - '@csstools/css-calc@3.1.1': - resolution: {integrity: sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-color-parser@4.0.2': - resolution: {integrity: sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} - engines: {node: '>=20.19.0'} - peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 - - '@csstools/css-syntax-patches-for-csstree@1.0.29': - resolution: {integrity: sha512-jx9GjkkP5YHuTmko2eWAvpPnb0mB4mGRr2U7XwVNwevm8nlpobZEVk+GNmiYMk2VuA75v+plfXWyroWKmICZXg==} - - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} - engines: {node: '>=20.19.0'} - - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@exodus/bytes@1.15.0': - resolution: {integrity: sha512-UY0nlA+feH81UGSHv92sLEPLCeZFjXOuHhrIo0HQydScuQc8s0A7kL/UdgwgDq8g8ilksmuoF35YVTNphV2aBQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@noble/hashes': ^1.8.0 || ^2.0.0 - peerDependenciesMeta: - '@noble/hashes': - optional: true - - '@isaacs/cliui@9.0.0': - resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} - engines: {node: '>=18'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@opencode-ai/sdk@1.2.17': - resolution: {integrity: sha512-HdeLeyJ2/Yl/NBHqw9pGFBnkIXuf0Id1kX1GMXDcnZwbJROUJ6TtrW/wLngTYW478E4CCm1jwknjxxmDuxzVMQ==} - - '@rolldown/pluginutils@1.0.0-rc.3': - resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} - - '@rollup/rollup-android-arm-eabi@4.59.0': - resolution: {integrity: sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.59.0': - resolution: {integrity: sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.59.0': - resolution: {integrity: sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.59.0': - resolution: {integrity: sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.59.0': - resolution: {integrity: sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.59.0': - resolution: {integrity: sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - resolution: {integrity: sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - resolution: {integrity: sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - resolution: {integrity: sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-musl@4.59.0': - resolution: {integrity: sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - resolution: {integrity: sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loong64-musl@4.59.0': - resolution: {integrity: sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==} - cpu: [loong64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - resolution: {integrity: sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - resolution: {integrity: sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==} - cpu: [ppc64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - resolution: {integrity: sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - resolution: {integrity: sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - resolution: {integrity: sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.59.0': - resolution: {integrity: sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-musl@4.59.0': - resolution: {integrity: sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-openbsd-x64@4.59.0': - resolution: {integrity: sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.59.0': - resolution: {integrity: sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - resolution: {integrity: sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - resolution: {integrity: sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.59.0': - resolution: {integrity: sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.59.0': - resolution: {integrity: sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==} - cpu: [x64] - os: [win32] - - '@secretlint/config-creator@10.2.2': - resolution: {integrity: sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==} - engines: {node: '>=20.0.0'} - - '@secretlint/config-loader@10.2.2': - resolution: {integrity: sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==} - engines: {node: '>=20.0.0'} - - '@secretlint/core@10.2.2': - resolution: {integrity: sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==} - engines: {node: '>=20.0.0'} - - '@secretlint/formatter@10.2.2': - resolution: {integrity: sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==} - engines: {node: '>=20.0.0'} - - '@secretlint/node@10.2.2': - resolution: {integrity: sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==} - engines: {node: '>=20.0.0'} - - '@secretlint/profiler@10.2.2': - resolution: {integrity: sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==} - - '@secretlint/resolver@10.2.2': - resolution: {integrity: sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==} - - '@secretlint/secretlint-formatter-sarif@10.2.2': - resolution: {integrity: sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==} - - '@secretlint/secretlint-rule-no-dotenv@10.2.2': - resolution: {integrity: sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==} - engines: {node: '>=20.0.0'} - - '@secretlint/secretlint-rule-preset-recommend@10.2.2': - resolution: {integrity: sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==} - engines: {node: '>=20.0.0'} - - '@secretlint/source-creator@10.2.2': - resolution: {integrity: sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==} - engines: {node: '>=20.0.0'} - - '@secretlint/types@10.2.2': - resolution: {integrity: sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==} - engines: {node: '>=20.0.0'} - - '@sindresorhus/merge-streams@2.3.0': - resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} - engines: {node: '>=18'} - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} - - '@testing-library/jest-dom@6.9.1': - resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} - engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - - '@testing-library/react@16.3.2': - resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} - engines: {node: '>=18'} - peerDependencies: - '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} - engines: {node: '>=12', npm: '>=6'} - peerDependencies: - '@testing-library/dom': '>=7.21.4' - - '@textlint/ast-node-types@15.5.2': - resolution: {integrity: sha512-fCaOxoup5LIyBEo7R1oYWE7V4bSX0KQeHh66twon9e9usaLE3ijgF8QjYsR6joCssdeCHVd0wHm7ppsEyTr6vg==} - - '@textlint/linter-formatter@15.5.2': - resolution: {integrity: sha512-jAw7jWM8+wU9cG6Uu31jGyD1B+PAVePCvnPKC/oov+2iBPKk3ao30zc/Itmi7FvXo4oPaL9PmzPPQhyniPVgVg==} - - '@textlint/module-interop@15.5.2': - resolution: {integrity: sha512-mg6rMQ3+YjwiXCYoQXbyVfDucpTa1q5mhspd/9qHBxUq4uY6W8GU42rmT3GW0V1yOfQ9z/iRrgPtkp71s8JzXg==} - - '@textlint/resolver@15.5.2': - resolution: {integrity: sha512-YEITdjRiJaQrGLUWxWXl4TEg+d2C7+TNNjbGPHPH7V7CCnXm+S9GTjGAL7Q2WSGJyFEKt88Jvx6XdJffRv4HEA==} - - '@textlint/types@15.5.2': - resolution: {integrity: sha512-sJOrlVLLXp4/EZtiWKWq9y2fWyZlI8GP+24rnU5avtPWBIMm/1w97yzKrAqYF8czx2MqR391z5akhnfhj2f/AQ==} - - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/dompurify@3.2.0': - resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==} - deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed. - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/node@22.19.13': - resolution: {integrity: sha512-akNQMv0wW5uyRpD2v2IEyRSZiR+BeGuoB6L310EgGObO44HSMNT8z1xzio28V8qOrgYaopIDNA18YgdXd+qTiw==} - - '@types/normalize-package-data@2.4.4': - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.14': - resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==} - - '@types/sarif@2.1.7': - resolution: {integrity: sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==} - - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - - '@types/vscode@1.109.0': - resolution: {integrity: sha512-0Pf95rnwEIwDbmXGC08r0B4TQhAbsHQ5UyTIgVgoieDe4cOnf92usuR5dEczb6bTKEp7ziZH4TV1TRGPPCExtw==} - - '@typespec/ts-http-runtime@0.3.3': - resolution: {integrity: sha512-91fp6CAAJSRtH5ja95T1FHSKa8aPW9/Zw6cta81jlZTUw/+Vq8jM/AfF/14h2b71wwR84JUTW/3Y8QPhDAawFA==} - engines: {node: '>=20.0.0'} - - '@vitejs/plugin-react@5.1.4': - resolution: {integrity: sha512-VIcFLdRi/VYRU8OL/puL7QXMYafHmqOnwTZY50U1JPlCNj30PxCMx65c494b1K9be9hX83KVt0+gTEwTWLqToA==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} - - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} - - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} - - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} - - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} - - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - - '@vscode/vsce-sign-alpine-arm64@2.0.6': - resolution: {integrity: sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==} - cpu: [arm64] - os: [alpine] - - '@vscode/vsce-sign-alpine-x64@2.0.6': - resolution: {integrity: sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==} - cpu: [x64] - os: [alpine] - - '@vscode/vsce-sign-darwin-arm64@2.0.6': - resolution: {integrity: sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==} - cpu: [arm64] - os: [darwin] - - '@vscode/vsce-sign-darwin-x64@2.0.6': - resolution: {integrity: sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==} - cpu: [x64] - os: [darwin] - - '@vscode/vsce-sign-linux-arm64@2.0.6': - resolution: {integrity: sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==} - cpu: [arm64] - os: [linux] - - '@vscode/vsce-sign-linux-arm@2.0.6': - resolution: {integrity: sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==} - cpu: [arm] - os: [linux] - - '@vscode/vsce-sign-linux-x64@2.0.6': - resolution: {integrity: sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==} - cpu: [x64] - os: [linux] - - '@vscode/vsce-sign-win32-arm64@2.0.6': - resolution: {integrity: sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==} - cpu: [arm64] - os: [win32] - - '@vscode/vsce-sign-win32-x64@2.0.6': - resolution: {integrity: sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==} - cpu: [x64] - os: [win32] - - '@vscode/vsce-sign@2.0.9': - resolution: {integrity: sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==} - - '@vscode/vsce@3.7.1': - resolution: {integrity: sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==} - engines: {node: '>= 20'} - hasBin: true - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - - ansi-escapes@7.3.0: - resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} - engines: {node: '>=18'} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - azure-devops-node-api@12.5.0: - resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - baseline-browser-mapping@2.10.0: - resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==} - engines: {node: '>=6.0.0'} - hasBin: true - - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - - binaryextensions@6.11.0: - resolution: {integrity: sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==} - engines: {node: '>=4'} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - - boundary@2.0.0: - resolution: {integrity: sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@5.0.4: - resolution: {integrity: sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==} - engines: {node: 18 || 20 || >=22} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - - buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - caniuse-lite@1.0.30001776: - resolution: {integrity: sha512-sg01JDPzZ9jGshqKSckOQthXnYwOEP50jeVFhaSFbZcOy05TiuuaffDOfcwtCisJ9kNQuLBFibYywv2Bgm9osw==} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - 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'} - - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} - - cockatiel@3.2.1: - resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==} - engines: {node: '>=16'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} - - css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - - cssstyle@6.2.0: - resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==} - engines: {node: '>=20'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - data-urls@7.0.0: - resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.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'} - - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - diff@8.0.3: - resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} - engines: {node: '>=0.3.1'} - - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - - dom-accessibility-api@0.6.3: - resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} - - dompurify@3.3.1: - resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} - - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} - - editions@6.22.0: - resolution: {integrity: sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==} - engines: {ecmascript: '>= es5', node: '>=4'} - - electron-to-chromium@1.5.307: - resolution: {integrity: sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==} - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - 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==} - - entities@4.5.0: - 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'} - - environment@1.1.0: - resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} - engines: {node: '>=18'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - form-data@4.0.5: - resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} - engines: {node: '>= 6'} - - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-extra@11.3.4: - resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} - engines: {node: '>=14.14'} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob@11.1.0: - resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} - engines: {node: 20 || >=22} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true - - globby@14.1.0: - resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} - engines: {node: '>=18'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - highlight.js@11.11.1: - resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} - engines: {node: '>=12.0.0'} - - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - - hosted-git-info@7.0.2: - resolution: {integrity: sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==} - engines: {node: ^16.14.0 || >=18.0.0} - - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - htmlparser2@10.1.0: - resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - 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==} - - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - 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-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - - is-wsl@3.1.1: - resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} - engines: {node: '>=16'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - istextorbinary@9.5.0: - resolution: {integrity: sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==} - engines: {node: '>=4'} - - jackspeak@4.2.3: - resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} - engines: {node: 20 || >=22} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsdom@28.1.0: - resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonc-parser@3.3.1: - resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} - - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} - - jsonwebtoken@9.0.3: - resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} - engines: {node: '>=12', npm: '>=6'} - - jwa@2.0.1: - resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} - - jws@4.0.1: - resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} - - keytar@7.9.0: - resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} - - leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - - linkify-it@5.0.0: - resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} - - lodash.includes@4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - - lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - - lodash.isinteger@4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - - lodash.isnumber@3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - - lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - - lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - - lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - - lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - - lodash@4.17.23: - resolution: {integrity: sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@11.2.6: - resolution: {integrity: sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==} - engines: {node: 20 || >=22} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - markdown-it@14.1.1: - resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} - hasBin: true - - marked@17.0.4: - resolution: {integrity: sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ==} - engines: {node: '>= 20'} - hasBin: true - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - - mdurl@2.0.0: - resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - napi-build-utils@2.0.0: - resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - - node-abi@3.87.0: - resolution: {integrity: sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==} - engines: {node: '>=10'} - - node-addon-api@4.3.0: - resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} - - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - - node-sarif-builder@3.4.0: - resolution: {integrity: sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==} - engines: {node: '>=20'} - - normalize-package-data@6.0.2: - resolution: {integrity: sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==} - engines: {node: ^16.14.0 || >=18.0.0} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - open@10.2.0: - resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} - engines: {node: '>=18'} - - p-map@7.0.4: - resolution: {integrity: sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==} - engines: {node: '>=18'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parse-json@8.3.0: - resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} - engines: {node: '>=18'} - - parse-semver@1.1.1: - resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} - - 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==} - - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-scurry@2.0.2: - resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} - engines: {node: 18 || 20 || >=22} - - path-type@6.0.0: - resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} - engines: {node: '>=18'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - pluralize@2.0.0: - resolution: {integrity: sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==} - - pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} - engines: {node: ^10 || ^12 || >=14} - - prebuild-install@7.1.3: - resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} - engines: {node: '>=10'} - deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. - hasBin: true - - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - pump@3.0.4: - resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} - - punycode.js@2.3.1: - resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} - engines: {node: '>=6'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} - engines: {node: '>=0.6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - rc-config-loader@4.1.4: - resolution: {integrity: sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==} - - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - react-dom@19.2.4: - resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} - peerDependencies: - react: ^19.2.4 - - react-icons@5.6.0: - resolution: {integrity: sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==} - peerDependencies: - react: '*' - - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} - - react@19.2.4: - resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} - engines: {node: '>=0.10.0'} - - read-pkg@9.0.1: - resolution: {integrity: sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==} - engines: {node: '>=18'} - - read@1.0.7: - resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} - engines: {node: '>=0.8'} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rollup@4.59.0: - resolution: {integrity: sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - 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==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sax@1.5.0: - resolution: {integrity: sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==} - engines: {node: '>=11.0.0'} - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - secretlint@10.2.2: - resolution: {integrity: sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==} - engines: {node: '>=20.0.0'} - hasBin: true - - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - - slash@5.1.0: - resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} - engines: {node: '>=14.16'} - - slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - - spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - - spdx-license-ids@3.0.23: - resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - structured-source@4.0.0: - resolution: {integrity: sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-hyperlinks@3.2.0: - resolution: {integrity: sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==} - engines: {node: '>=14.18'} - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - - table@6.9.0: - resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} - engines: {node: '>=10.0.0'} - - tar-fs@2.1.4: - resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} - - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} - - terminal-link@4.0.0: - resolution: {integrity: sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==} - engines: {node: '>=18'} - - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - - textextensions@6.11.0: - resolution: {integrity: sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==} - engines: {node: '>=4'} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} - engines: {node: '>=14.0.0'} - - tldts-core@7.0.24: - resolution: {integrity: sha512-pj7yygNMoMRqG7ML2SDQ0xNIOfN3IBDUcPVM2Sg6hP96oFNN2nqnzHreT3z9xLq85IWJyNTvD38O002DdOrPMw==} - - tldts@7.0.24: - resolution: {integrity: sha512-1r6vQTTt1rUiJkI5vX7KG8PR342Ru/5Oh13kEQP2SMbRSZpOey9SrBe27IDxkoWulx8ShWu4K6C0BkctP8Z1bQ==} - hasBin: true - - tmp@0.2.5: - resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} - engines: {node: '>=14.14'} - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} - engines: {node: '>=16'} - - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - - tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - - typed-rest-client@1.8.11: - resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - uc.micro@2.1.0: - resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} - - underscore@1.13.8: - resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici@7.22.0: - resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} - engines: {node: '>=20.18.1'} - - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} - - unicorn-magic@0.3.0: - resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} - engines: {node: '>=18'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - url-join@4.0.1: - resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - - validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - - version-range@4.15.0: - resolution: {integrity: sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==} - engines: {node: '>=4'} - - vite@6.4.1: - resolution: {integrity: sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - - 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-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - - whatwg-url@16.0.1: - resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - wsl-utils@0.1.0: - resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} - engines: {node: '>=18'} - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xml2js@0.5.0: - resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} - engines: {node: '>=4.0.0'} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - - yazl@2.5.1: - resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} - -snapshots: - - '@acemir/cssom@0.9.31': {} - - '@adobe/css-tools@4.4.4': {} - - '@asamuzakjp/css-color@5.0.1': - dependencies: - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - lru-cache: 11.2.6 - - '@asamuzakjp/dom-selector@6.8.1': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.6 - - '@asamuzakjp/nwsapi@2.3.9': {} - - '@azu/format-text@1.0.2': {} - - '@azu/style-format@1.0.1': - dependencies: - '@azu/format-text': 1.0.2 - - '@azure/abort-controller@2.1.2': - dependencies: - tslib: 2.8.1 - - '@azure/core-auth@1.10.1': - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.13.1 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@azure/core-client@1.10.1': - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 - '@azure/core-tracing': 1.3.1 - '@azure/core-util': 1.13.1 - '@azure/logger': 1.3.0 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@azure/core-rest-pipeline@1.22.2': - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.10.1 - '@azure/core-tracing': 1.3.1 - '@azure/core-util': 1.13.1 - '@azure/logger': 1.3.0 - '@typespec/ts-http-runtime': 0.3.3 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@azure/core-tracing@1.3.1': - dependencies: - tslib: 2.8.1 - - '@azure/core-util@1.13.1': - dependencies: - '@azure/abort-controller': 2.1.2 - '@typespec/ts-http-runtime': 0.3.3 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@azure/identity@4.13.0': - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.10.1 - '@azure/core-client': 1.10.1 - '@azure/core-rest-pipeline': 1.22.2 - '@azure/core-tracing': 1.3.1 - '@azure/core-util': 1.13.1 - '@azure/logger': 1.3.0 - '@azure/msal-browser': 4.29.0 - '@azure/msal-node': 3.8.8 - open: 10.2.0 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@azure/logger@1.3.0': - dependencies: - '@typespec/ts-http-runtime': 0.3.3 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@azure/msal-browser@4.29.0': - dependencies: - '@azure/msal-common': 15.15.0 - - '@azure/msal-common@15.15.0': {} - - '@azure/msal-node@3.8.8': - dependencies: - '@azure/msal-common': 15.15.0 - jsonwebtoken: 9.0.3 - uuid: 8.3.2 - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.28.6 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.28.6': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.0': - dependencies: - '@babel/types': 7.29.0 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/runtime@7.28.6': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.0 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@biomejs/biome@2.4.4': - optionalDependencies: - '@biomejs/cli-darwin-arm64': 2.4.4 - '@biomejs/cli-darwin-x64': 2.4.4 - '@biomejs/cli-linux-arm64': 2.4.4 - '@biomejs/cli-linux-arm64-musl': 2.4.4 - '@biomejs/cli-linux-x64': 2.4.4 - '@biomejs/cli-linux-x64-musl': 2.4.4 - '@biomejs/cli-win32-arm64': 2.4.4 - '@biomejs/cli-win32-x64': 2.4.4 - - '@biomejs/cli-darwin-arm64@2.4.4': - optional: true - - '@biomejs/cli-darwin-x64@2.4.4': - optional: true - - '@biomejs/cli-linux-arm64-musl@2.4.4': - optional: true - - '@biomejs/cli-linux-arm64@2.4.4': - optional: true - - '@biomejs/cli-linux-x64-musl@2.4.4': - optional: true - - '@biomejs/cli-linux-x64@2.4.4': - optional: true - - '@biomejs/cli-win32-arm64@2.4.4': - optional: true - - '@biomejs/cli-win32-x64@2.4.4': - optional: true - - '@bramus/specificity@2.4.2': - dependencies: - css-tree: 3.1.0 - - '@csstools/color-helpers@6.0.2': {} - - '@csstools/css-calc@3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - - '@csstools/css-color-parser@4.0.2(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-tokenizer': 4.0.0 - - '@csstools/css-syntax-patches-for-csstree@1.0.29': {} - - '@csstools/css-tokenizer@4.0.0': {} - - '@esbuild/aix-ppc64@0.25.12': - optional: true - - '@esbuild/android-arm64@0.25.12': - optional: true - - '@esbuild/android-arm@0.25.12': - optional: true - - '@esbuild/android-x64@0.25.12': - optional: true - - '@esbuild/darwin-arm64@0.25.12': - optional: true - - '@esbuild/darwin-x64@0.25.12': - optional: true - - '@esbuild/freebsd-arm64@0.25.12': - optional: true - - '@esbuild/freebsd-x64@0.25.12': - optional: true - - '@esbuild/linux-arm64@0.25.12': - optional: true - - '@esbuild/linux-arm@0.25.12': - optional: true - - '@esbuild/linux-ia32@0.25.12': - optional: true - - '@esbuild/linux-loong64@0.25.12': - optional: true - - '@esbuild/linux-mips64el@0.25.12': - optional: true - - '@esbuild/linux-ppc64@0.25.12': - optional: true - - '@esbuild/linux-riscv64@0.25.12': - optional: true - - '@esbuild/linux-s390x@0.25.12': - optional: true - - '@esbuild/linux-x64@0.25.12': - optional: true - - '@esbuild/netbsd-arm64@0.25.12': - optional: true - - '@esbuild/netbsd-x64@0.25.12': - optional: true - - '@esbuild/openbsd-arm64@0.25.12': - optional: true - - '@esbuild/openbsd-x64@0.25.12': - optional: true - - '@esbuild/openharmony-arm64@0.25.12': - optional: true - - '@esbuild/sunos-x64@0.25.12': - optional: true - - '@esbuild/win32-arm64@0.25.12': - optional: true - - '@esbuild/win32-ia32@0.25.12': - optional: true - - '@esbuild/win32-x64@0.25.12': - optional: true - - '@exodus/bytes@1.15.0': {} - - '@isaacs/cliui@9.0.0': {} - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@opencode-ai/sdk@1.2.17': {} - - '@rolldown/pluginutils@1.0.0-rc.3': {} - - '@rollup/rollup-android-arm-eabi@4.59.0': - optional: true - - '@rollup/rollup-android-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.59.0': - optional: true - - '@rollup/rollup-darwin-x64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.59.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.59.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.59.0': - optional: true - - '@rollup/rollup-openbsd-x64@4.59.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.59.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.59.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.59.0': - optional: true - - '@secretlint/config-creator@10.2.2': - dependencies: - '@secretlint/types': 10.2.2 - - '@secretlint/config-loader@10.2.2': - dependencies: - '@secretlint/profiler': 10.2.2 - '@secretlint/resolver': 10.2.2 - '@secretlint/types': 10.2.2 - ajv: 8.18.0 - debug: 4.4.3 - rc-config-loader: 4.1.4 - transitivePeerDependencies: - - supports-color - - '@secretlint/core@10.2.2': - dependencies: - '@secretlint/profiler': 10.2.2 - '@secretlint/types': 10.2.2 - debug: 4.4.3 - structured-source: 4.0.0 - transitivePeerDependencies: - - supports-color - - '@secretlint/formatter@10.2.2': - dependencies: - '@secretlint/resolver': 10.2.2 - '@secretlint/types': 10.2.2 - '@textlint/linter-formatter': 15.5.2 - '@textlint/module-interop': 15.5.2 - '@textlint/types': 15.5.2 - chalk: 5.6.2 - debug: 4.4.3 - pluralize: 8.0.0 - strip-ansi: 7.2.0 - table: 6.9.0 - terminal-link: 4.0.0 - transitivePeerDependencies: - - supports-color - - '@secretlint/node@10.2.2': - dependencies: - '@secretlint/config-loader': 10.2.2 - '@secretlint/core': 10.2.2 - '@secretlint/formatter': 10.2.2 - '@secretlint/profiler': 10.2.2 - '@secretlint/source-creator': 10.2.2 - '@secretlint/types': 10.2.2 - debug: 4.4.3 - p-map: 7.0.4 - transitivePeerDependencies: - - supports-color - - '@secretlint/profiler@10.2.2': {} - - '@secretlint/resolver@10.2.2': {} - - '@secretlint/secretlint-formatter-sarif@10.2.2': - dependencies: - node-sarif-builder: 3.4.0 - - '@secretlint/secretlint-rule-no-dotenv@10.2.2': - dependencies: - '@secretlint/types': 10.2.2 - - '@secretlint/secretlint-rule-preset-recommend@10.2.2': {} - - '@secretlint/source-creator@10.2.2': - dependencies: - '@secretlint/types': 10.2.2 - istextorbinary: 9.5.0 - - '@secretlint/types@10.2.2': {} - - '@sindresorhus/merge-streams@2.3.0': {} - - '@standard-schema/spec@1.1.0': {} - - '@testing-library/dom@10.4.1': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 - - '@testing-library/jest-dom@6.9.1': - dependencies: - '@adobe/css-tools': 4.4.4 - aria-query: 5.3.2 - css.escape: 1.5.1 - dom-accessibility-api: 0.6.3 - picocolors: 1.1.1 - redent: 3.0.0 - - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/runtime': 7.28.6 - '@testing-library/dom': 10.4.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': - dependencies: - '@testing-library/dom': 10.4.1 - - '@textlint/ast-node-types@15.5.2': {} - - '@textlint/linter-formatter@15.5.2': - dependencies: - '@azu/format-text': 1.0.2 - '@azu/style-format': 1.0.1 - '@textlint/module-interop': 15.5.2 - '@textlint/resolver': 15.5.2 - '@textlint/types': 15.5.2 - chalk: 4.1.2 - debug: 4.4.3 - js-yaml: 4.1.1 - lodash: 4.17.23 - pluralize: 2.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - table: 6.9.0 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - - '@textlint/module-interop@15.5.2': {} - - '@textlint/resolver@15.5.2': {} - - '@textlint/types@15.5.2': - dependencies: - '@textlint/ast-node-types': 15.5.2 - - '@types/aria-query@5.0.4': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.29.0 - '@babel/types': 7.29.0 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.29.0 - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/deep-eql@4.0.2': {} - - '@types/dompurify@3.2.0': - dependencies: - dompurify: 3.3.1 - - '@types/estree@1.0.8': {} - - '@types/node@22.19.13': - dependencies: - undici-types: 6.21.0 - - '@types/normalize-package-data@2.4.4': {} - - '@types/react-dom@19.2.3(@types/react@19.2.14)': - dependencies: - '@types/react': 19.2.14 - - '@types/react@19.2.14': - dependencies: - csstype: 3.2.3 - - '@types/sarif@2.1.7': {} - - '@types/trusted-types@2.0.7': - optional: true - - '@types/vscode@1.109.0': {} - - '@typespec/ts-http-runtime@0.3.3': - dependencies: - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - tslib: 2.8.1 - transitivePeerDependencies: - - supports-color - - '@vitejs/plugin-react@5.1.4(vite@6.4.1(@types/node@22.19.13))': - dependencies: - '@babel/core': 7.29.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) - '@rolldown/pluginutils': 1.0.0-rc.3 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: 6.4.1(@types/node@22.19.13) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@4.0.18': - dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - chai: 6.2.2 - tinyrainbow: 3.0.3 - - '@vitest/mocker@4.0.18(vite@6.4.1(@types/node@22.19.13))': - dependencies: - '@vitest/spy': 4.0.18 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 6.4.1(@types/node@22.19.13) - - '@vitest/pretty-format@4.0.18': - dependencies: - tinyrainbow: 3.0.3 - - '@vitest/runner@4.0.18': - dependencies: - '@vitest/utils': 4.0.18 - pathe: 2.0.3 - - '@vitest/snapshot@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.0.18': {} - - '@vitest/utils@4.0.18': - dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - - '@vscode/vsce-sign-alpine-arm64@2.0.6': - optional: true - - '@vscode/vsce-sign-alpine-x64@2.0.6': - optional: true - - '@vscode/vsce-sign-darwin-arm64@2.0.6': - optional: true - - '@vscode/vsce-sign-darwin-x64@2.0.6': - optional: true - - '@vscode/vsce-sign-linux-arm64@2.0.6': - optional: true - - '@vscode/vsce-sign-linux-arm@2.0.6': - optional: true - - '@vscode/vsce-sign-linux-x64@2.0.6': - optional: true - - '@vscode/vsce-sign-win32-arm64@2.0.6': - optional: true - - '@vscode/vsce-sign-win32-x64@2.0.6': - optional: true - - '@vscode/vsce-sign@2.0.9': - optionalDependencies: - '@vscode/vsce-sign-alpine-arm64': 2.0.6 - '@vscode/vsce-sign-alpine-x64': 2.0.6 - '@vscode/vsce-sign-darwin-arm64': 2.0.6 - '@vscode/vsce-sign-darwin-x64': 2.0.6 - '@vscode/vsce-sign-linux-arm': 2.0.6 - '@vscode/vsce-sign-linux-arm64': 2.0.6 - '@vscode/vsce-sign-linux-x64': 2.0.6 - '@vscode/vsce-sign-win32-arm64': 2.0.6 - '@vscode/vsce-sign-win32-x64': 2.0.6 - - '@vscode/vsce@3.7.1': - dependencies: - '@azure/identity': 4.13.0 - '@secretlint/node': 10.2.2 - '@secretlint/secretlint-formatter-sarif': 10.2.2 - '@secretlint/secretlint-rule-no-dotenv': 10.2.2 - '@secretlint/secretlint-rule-preset-recommend': 10.2.2 - '@vscode/vsce-sign': 2.0.9 - azure-devops-node-api: 12.5.0 - chalk: 4.1.2 - cheerio: 1.2.0 - cockatiel: 3.2.1 - commander: 12.1.0 - form-data: 4.0.5 - glob: 11.1.0 - hosted-git-info: 4.1.0 - jsonc-parser: 3.3.1 - leven: 3.1.0 - markdown-it: 14.1.1 - mime: 1.6.0 - minimatch: 3.1.5 - parse-semver: 1.1.1 - read: 1.0.7 - secretlint: 10.2.2 - semver: 7.7.4 - tmp: 0.2.5 - typed-rest-client: 1.8.11 - url-join: 4.0.1 - xml2js: 0.5.0 - yauzl: 2.10.0 - yazl: 2.5.1 - optionalDependencies: - keytar: 7.9.0 - transitivePeerDependencies: - - supports-color - - agent-base@7.1.4: {} - - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-escapes@7.3.0: - dependencies: - environment: 1.1.0 - - ansi-regex@5.0.1: {} - - ansi-regex@6.2.2: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - argparse@2.0.1: {} - - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - - aria-query@5.3.2: {} - - assertion-error@2.0.1: {} - - astral-regex@2.0.0: {} - - asynckit@0.4.0: {} - - azure-devops-node-api@12.5.0: - dependencies: - tunnel: 0.0.6 - typed-rest-client: 1.8.11 - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - base64-js@1.5.1: - optional: true - - baseline-browser-mapping@2.10.0: {} - - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - - binaryextensions@6.11.0: - dependencies: - editions: 6.22.0 - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - optional: true - - boolbase@1.0.0: {} - - boundary@2.0.0: {} - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@5.0.4: - dependencies: - balanced-match: 4.0.4 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.0 - caniuse-lite: 1.0.30001776 - electron-to-chromium: 1.5.307 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - buffer-crc32@0.2.13: {} - - buffer-equal-constant-time@1.0.1: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - optional: true - - bundle-name@4.1.0: - dependencies: - run-applescript: 7.1.0 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - caniuse-lite@1.0.30001776: {} - - chai@6.2.2: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.6.2: {} - - 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.22.0 - whatwg-mimetype: 4.0.0 - - chownr@1.1.4: - optional: true - - cockatiel@3.2.1: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@12.1.0: {} - - concat-map@0.0.1: {} - - convert-source-map@2.0.0: {} - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - css-select@5.2.2: - dependencies: - boolbase: 1.0.0 - css-what: 6.2.2 - domhandler: 5.0.3 - domutils: 3.2.2 - nth-check: 2.1.1 - - css-tree@3.1.0: - dependencies: - mdn-data: 2.12.2 - source-map-js: 1.2.1 - - css-what@6.2.2: {} - - css.escape@1.5.1: {} - - cssstyle@6.2.0: - dependencies: - '@asamuzakjp/css-color': 5.0.1 - '@csstools/css-syntax-patches-for-csstree': 1.0.29 - css-tree: 3.1.0 - lru-cache: 11.2.6 - - csstype@3.2.3: {} - - data-urls@7.0.0: - dependencies: - whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 - transitivePeerDependencies: - - '@noble/hashes' - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decimal.js@10.6.0: {} - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - optional: true - - deep-extend@0.6.0: - optional: true - - default-browser-id@5.0.1: {} - - default-browser@5.5.0: - dependencies: - bundle-name: 4.1.0 - default-browser-id: 5.0.1 - - define-lazy-prop@3.0.0: {} - - delayed-stream@1.0.0: {} - - dequal@2.0.3: {} - - detect-libc@2.1.2: - optional: true - - diff@8.0.3: {} - - dom-accessibility-api@0.5.16: {} - - dom-accessibility-api@0.6.3: {} - - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - dompurify@3.3.1: - optionalDependencies: - '@types/trusted-types': 2.0.7 - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - ecdsa-sig-formatter@1.0.11: - dependencies: - safe-buffer: 5.2.1 - - editions@6.22.0: - dependencies: - version-range: 4.15.0 - - electron-to-chromium@1.5.307: {} - - emoji-regex@8.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 - optional: true - - entities@4.5.0: {} - - entities@6.0.1: {} - - entities@7.0.1: {} - - environment@1.1.0: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-module-lexer@1.7.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - esbuild@0.25.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - - escalade@3.2.0: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - expand-template@2.0.3: - optional: true - - expect-type@1.3.0: {} - - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-uri@3.1.0: {} - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 - - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - form-data@4.0.5: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - fs-constants@1.0.0: - optional: true - - fs-extra@11.3.4: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - github-from-package@0.0.0: - optional: true - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob@11.1.0: - dependencies: - foreground-child: 3.3.1 - jackspeak: 4.2.3 - minimatch: 10.2.4 - minipass: 7.1.3 - package-json-from-dist: 1.0.1 - path-scurry: 2.0.2 - - globby@14.1.0: - dependencies: - '@sindresorhus/merge-streams': 2.3.0 - fast-glob: 3.3.3 - ignore: 7.0.5 - path-type: 6.0.0 - slash: 5.1.0 - unicorn-magic: 0.3.0 - - gopd@1.2.0: {} - - graceful-fs@4.2.11: {} - - has-flag@4.0.0: {} - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - highlight.js@11.11.1: {} - - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - - hosted-git-info@7.0.2: - dependencies: - lru-cache: 10.4.3 - - html-encoding-sniffer@6.0.0: - dependencies: - '@exodus/bytes': 1.15.0 - transitivePeerDependencies: - - '@noble/hashes' - - htmlparser2@10.1.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 7.0.1 - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ieee754@1.2.1: - optional: true - - ignore@7.0.5: {} - - indent-string@4.0.0: {} - - index-to-position@1.2.0: {} - - inherits@2.0.4: - optional: true - - ini@1.3.8: - optional: true - - is-docker@3.0.0: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 - - is-number@7.0.0: {} - - is-potential-custom-element-name@1.0.1: {} - - is-wsl@3.1.1: - dependencies: - is-inside-container: 1.0.0 - - isexe@2.0.0: {} - - istextorbinary@9.5.0: - dependencies: - binaryextensions: 6.11.0 - editions: 6.22.0 - textextensions: 6.11.0 - - jackspeak@4.2.3: - dependencies: - '@isaacs/cliui': 9.0.0 - - js-tokens@4.0.0: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsdom@28.1.0: - dependencies: - '@acemir/cssom': 0.9.31 - '@asamuzakjp/dom-selector': 6.8.1 - '@bramus/specificity': 2.4.2 - '@exodus/bytes': 1.15.0 - cssstyle: 6.2.0 - data-urls: 7.0.0 - decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.0 - undici: 7.22.0 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - '@noble/hashes' - - supports-color - - jsesc@3.1.0: {} - - json-schema-traverse@1.0.0: {} - - json5@2.2.3: {} - - jsonc-parser@3.3.1: {} - - jsonfile@6.2.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - jsonwebtoken@9.0.3: - dependencies: - jws: 4.0.1 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 - ms: 2.1.3 - semver: 7.7.4 - - jwa@2.0.1: - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - - jws@4.0.1: - dependencies: - jwa: 2.0.1 - safe-buffer: 5.2.1 - - keytar@7.9.0: - dependencies: - node-addon-api: 4.3.0 - prebuild-install: 7.1.3 - optional: true - - leven@3.1.0: {} - - linkify-it@5.0.0: - dependencies: - uc.micro: 2.1.0 - - lodash.includes@4.3.0: {} - - lodash.isboolean@3.0.3: {} - - lodash.isinteger@4.0.4: {} - - lodash.isnumber@3.0.3: {} - - lodash.isplainobject@4.0.6: {} - - lodash.isstring@4.0.1: {} - - lodash.once@4.1.1: {} - - lodash.truncate@4.4.2: {} - - lodash@4.17.23: {} - - lru-cache@10.4.3: {} - - lru-cache@11.2.6: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - lz-string@1.5.0: {} - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - markdown-it@14.1.1: - dependencies: - argparse: 2.0.1 - entities: 4.5.0 - linkify-it: 5.0.0 - mdurl: 2.0.0 - punycode.js: 2.3.1 - uc.micro: 2.1.0 - - marked@17.0.4: {} - - math-intrinsics@1.1.0: {} - - mdn-data@2.12.2: {} - - mdurl@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - - mime-db@1.52.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime@1.6.0: {} - - mimic-response@3.1.0: - optional: true - - min-indent@1.0.1: {} - - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.4 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.12 - - minimist@1.2.8: - optional: true - - minipass@7.1.3: {} - - mkdirp-classic@0.5.3: - optional: true - - ms@2.1.3: {} - - mute-stream@0.0.8: {} - - nanoid@3.3.11: {} - - napi-build-utils@2.0.0: - optional: true - - node-abi@3.87.0: - dependencies: - semver: 7.7.4 - optional: true - - node-addon-api@4.3.0: - optional: true - - node-releases@2.0.36: {} - - node-sarif-builder@3.4.0: - dependencies: - '@types/sarif': 2.1.7 - fs-extra: 11.3.4 - - normalize-package-data@6.0.2: - dependencies: - hosted-git-info: 7.0.2 - semver: 7.7.4 - validate-npm-package-license: 3.0.4 - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 - - object-inspect@1.13.4: {} - - obug@2.1.1: {} - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - optional: true - - open@10.2.0: - dependencies: - default-browser: 5.5.0 - define-lazy-prop: 3.0.0 - is-inside-container: 1.0.0 - wsl-utils: 0.1.0 - - p-map@7.0.4: {} - - package-json-from-dist@1.0.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-semver@1.1.1: - dependencies: - semver: 5.7.2 - - 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 - - parse5@8.0.0: - dependencies: - entities: 6.0.1 - - path-key@3.1.1: {} - - path-scurry@2.0.2: - dependencies: - lru-cache: 11.2.6 - minipass: 7.1.3 - - path-type@6.0.0: {} - - pathe@2.0.3: {} - - pend@1.2.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - pluralize@2.0.0: {} - - pluralize@8.0.0: {} - - postcss@8.5.8: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - prebuild-install@7.1.3: - dependencies: - detect-libc: 2.1.2 - expand-template: 2.0.3 - github-from-package: 0.0.0 - minimist: 1.2.8 - mkdirp-classic: 0.5.3 - napi-build-utils: 2.0.0 - node-abi: 3.87.0 - pump: 3.0.4 - rc: 1.2.8 - simple-get: 4.0.1 - tar-fs: 2.1.4 - tunnel-agent: 0.6.0 - optional: true - - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - - pump@3.0.4: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - optional: true - - punycode.js@2.3.1: {} - - punycode@2.3.1: {} - - qs@6.15.0: - dependencies: - side-channel: 1.1.0 - - queue-microtask@1.2.3: {} - - rc-config-loader@4.1.4: - dependencies: - debug: 4.4.3 - js-yaml: 4.1.1 - json5: 2.2.3 - require-from-string: 2.0.2 - transitivePeerDependencies: - - supports-color - - rc@1.2.8: - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - optional: true - - react-dom@19.2.4(react@19.2.4): - dependencies: - react: 19.2.4 - scheduler: 0.27.0 - - react-icons@5.6.0(react@19.2.4): - dependencies: - react: 19.2.4 - - react-is@17.0.2: {} - - react-refresh@0.18.0: {} - - react@19.2.4: {} - - read-pkg@9.0.1: - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 6.0.2 - parse-json: 8.3.0 - type-fest: 4.41.0 - unicorn-magic: 0.1.0 - - read@1.0.7: - dependencies: - mute-stream: 0.0.8 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - optional: true - - redent@3.0.0: - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - - require-from-string@2.0.2: {} - - reusify@1.1.0: {} - - rollup@4.59.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.59.0 - '@rollup/rollup-android-arm64': 4.59.0 - '@rollup/rollup-darwin-arm64': 4.59.0 - '@rollup/rollup-darwin-x64': 4.59.0 - '@rollup/rollup-freebsd-arm64': 4.59.0 - '@rollup/rollup-freebsd-x64': 4.59.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.59.0 - '@rollup/rollup-linux-arm-musleabihf': 4.59.0 - '@rollup/rollup-linux-arm64-gnu': 4.59.0 - '@rollup/rollup-linux-arm64-musl': 4.59.0 - '@rollup/rollup-linux-loong64-gnu': 4.59.0 - '@rollup/rollup-linux-loong64-musl': 4.59.0 - '@rollup/rollup-linux-ppc64-gnu': 4.59.0 - '@rollup/rollup-linux-ppc64-musl': 4.59.0 - '@rollup/rollup-linux-riscv64-gnu': 4.59.0 - '@rollup/rollup-linux-riscv64-musl': 4.59.0 - '@rollup/rollup-linux-s390x-gnu': 4.59.0 - '@rollup/rollup-linux-x64-gnu': 4.59.0 - '@rollup/rollup-linux-x64-musl': 4.59.0 - '@rollup/rollup-openbsd-x64': 4.59.0 - '@rollup/rollup-openharmony-arm64': 4.59.0 - '@rollup/rollup-win32-arm64-msvc': 4.59.0 - '@rollup/rollup-win32-ia32-msvc': 4.59.0 - '@rollup/rollup-win32-x64-gnu': 4.59.0 - '@rollup/rollup-win32-x64-msvc': 4.59.0 - fsevents: 2.3.3 - - run-applescript@7.1.0: {} - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - - safe-buffer@5.2.1: {} - - safer-buffer@2.1.2: {} - - sax@1.5.0: {} - - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - - scheduler@0.27.0: {} - - secretlint@10.2.2: - dependencies: - '@secretlint/config-creator': 10.2.2 - '@secretlint/formatter': 10.2.2 - '@secretlint/node': 10.2.2 - '@secretlint/profiler': 10.2.2 - debug: 4.4.3 - globby: 14.1.0 - read-pkg: 9.0.1 - transitivePeerDependencies: - - supports-color - - semver@5.7.2: {} - - semver@6.3.1: {} - - semver@7.7.4: {} - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - siginfo@2.0.0: {} - - signal-exit@4.1.0: {} - - simple-concat@1.0.1: - optional: true - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - optional: true - - slash@5.1.0: {} - - slice-ansi@4.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - - source-map-js@1.2.1: {} - - spdx-correct@3.2.0: - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.23 - - spdx-exceptions@2.5.0: {} - - spdx-expression-parse@3.0.1: - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.23 - - spdx-license-ids@3.0.23: {} - - stackback@0.0.2: {} - - std-env@3.10.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - optional: true - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - - strip-json-comments@2.0.1: - optional: true - - structured-source@4.0.0: - dependencies: - boundary: 2.0.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-hyperlinks@3.2.0: - dependencies: - has-flag: 4.0.0 - supports-color: 7.2.0 - - symbol-tree@3.2.4: {} - - table@6.9.0: - dependencies: - ajv: 8.18.0 - lodash.truncate: 4.4.2 - slice-ansi: 4.0.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - tar-fs@2.1.4: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.4 - tar-stream: 2.2.0 - optional: true - - tar-stream@2.2.0: - dependencies: - bl: 4.1.0 - end-of-stream: 1.4.5 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 - optional: true - - terminal-link@4.0.0: - dependencies: - ansi-escapes: 7.3.0 - supports-hyperlinks: 3.2.0 - - text-table@0.2.0: {} - - textextensions@6.11.0: - dependencies: - editions: 6.22.0 - - tinybench@2.9.0: {} - - tinyexec@1.0.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - - tinyrainbow@3.0.3: {} - - tldts-core@7.0.24: {} - - tldts@7.0.24: - dependencies: - tldts-core: 7.0.24 - - tmp@0.2.5: {} - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - tough-cookie@6.0.0: - dependencies: - tldts: 7.0.24 - - tr46@6.0.0: - dependencies: - punycode: 2.3.1 - - tslib@2.8.1: {} - - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - optional: true - - tunnel@0.0.6: {} - - type-fest@4.41.0: {} - - typed-rest-client@1.8.11: - dependencies: - qs: 6.15.0 - tunnel: 0.0.6 - underscore: 1.13.8 - - typescript@5.9.3: {} - - uc.micro@2.1.0: {} - - underscore@1.13.8: {} - - undici-types@6.21.0: {} - - undici@7.22.0: {} - - unicorn-magic@0.1.0: {} - - unicorn-magic@0.3.0: {} - - universalify@2.0.1: {} - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - url-join@4.0.1: {} - - util-deprecate@1.0.2: - optional: true - - uuid@8.3.2: {} - - validate-npm-package-license@3.0.4: - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - - version-range@4.15.0: {} - - vite@6.4.1(@types/node@22.19.13): - dependencies: - esbuild: 0.25.12 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.8 - rollup: 4.59.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 22.19.13 - fsevents: 2.3.3 - - vitest@4.0.18(@types/node@22.19.13)(jsdom@28.1.0): - dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@6.4.1(@types/node@22.19.13)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 6.4.1(@types/node@22.19.13) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 22.19.13 - jsdom: 28.1.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - - webidl-conversions@8.0.1: {} - - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@4.0.0: {} - - whatwg-mimetype@5.0.0: {} - - whatwg-url@16.0.1: - dependencies: - '@exodus/bytes': 1.15.0 - tr46: 6.0.0 - webidl-conversions: 8.0.1 - transitivePeerDependencies: - - '@noble/hashes' - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - wrappy@1.0.2: - optional: true - - wsl-utils@0.1.0: - dependencies: - is-wsl: 3.1.1 - - xml-name-validator@5.0.0: {} - - xml2js@0.5.0: - dependencies: - sax: 1.5.0 - xmlbuilder: 11.0.1 - - xmlbuilder@11.0.1: {} - - xmlchars@2.2.0: {} - - yallist@3.1.1: {} - - yallist@4.0.0: {} - - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - - yazl@2.5.1: - dependencies: - buffer-crc32: 0.2.13 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml deleted file mode 100644 index 332c086..0000000 --- a/pnpm-workspace.yaml +++ /dev/null @@ -1,6 +0,0 @@ -packages: - - "packages/*" - - "packages/agents/*" - - "packages/platforms/*" -onlyBuiltDependencies: - - esbuild diff --git a/packages/core/src/domain.ts b/shared/domain.ts similarity index 88% rename from packages/core/src/domain.ts rename to shared/domain.ts index d825bb6..209d390 100644 --- a/packages/core/src/domain.ts +++ b/shared/domain.ts @@ -1,10 +1,9 @@ /** - * @opencodegui/core - Domain types + * @shared - Domain types * - * Agent/platform-independent types representing the application's domain. - * These types are shaped to match the actual data flowing through the system - * (originally from @opencode-ai/sdk) so that the webview can consume them - * without depending on any specific agent SDK. + * Shared types representing data passed between the extension host and webview. + * These types intentionally follow the OpenCode SDK payloads closely; the + * extension host forwards most SDK data without a separate mapping layer. */ // ============================================================ @@ -368,7 +367,7 @@ export type FileAttachment = { // File Diff // ============================================================ -export type FileDiff = { +export type FileContentDiff = { file: string; before: string; after: string; @@ -376,12 +375,21 @@ export type FileDiff = { deletions: number; }; +export type FilePatchDiff = { + file: string; + patch: string; + additions: number; + deletions: number; + status?: "added" | "deleted" | "modified"; +}; + +export type FileDiff = FileContentDiff | FilePatchDiff; + // ============================================================ // Todo // ============================================================ export type TodoItem = { - id: string; content: string; status: string; priority: string; @@ -492,3 +500,29 @@ export type ToolListItem = { export type Disposable = { dispose(): void; }; + +// ============================================================ +// Webview persisted UI state +// ============================================================ + +export type SoundEventType = "responseComplete" | "permissionRequest" | "questionAsked" | "error"; + +export type SoundEventSetting = { + enabled?: boolean; + volume?: number; +}; + +export type SoundSettings = Partial>; + +export type UIPersistedState = { + localeSetting?: string; + inputHistory?: string[]; + soundSettings?: SoundSettings; +}; + +export type IBridge = { + postMessage(message: import("./protocol").UIToHostMessage): void; + onMessage(handler: (message: import("./protocol").HostToUIMessage) => void): Disposable; + getPersistedState(): UIPersistedState | null; + setPersistedState(state: UIPersistedState): void; +}; diff --git a/shared/index.ts b/shared/index.ts new file mode 100644 index 0000000..9234cc9 --- /dev/null +++ b/shared/index.ts @@ -0,0 +1,4 @@ +// Shared domain and protocol types used by the extension host and webview. + +export * from "./domain"; +export * from "./protocol"; diff --git a/packages/core/src/protocol.ts b/shared/protocol.ts similarity index 93% rename from packages/core/src/protocol.ts rename to shared/protocol.ts index cd80c6b..784a9fc 100644 --- a/packages/core/src/protocol.ts +++ b/shared/protocol.ts @@ -1,12 +1,6 @@ /** - * @opencodegui/core - Protocol Types - * - * Message types for UI <-> Host communication. - * These define the protocol used between the webview (React UI) and the - * host process (VS Code extension host, Electron main process, etc.). + * Message types for UI <-> VS Code extension host communication. */ - -import type { AgentCapabilities } from "./agent.interface"; import type { AgentEvent, AgentInfo, @@ -145,7 +139,6 @@ export type HostToUIMessage = // --- Initialization --- | { type: "init"; - capabilities: AgentCapabilities; locale: string; paths: AppPaths; } diff --git a/packages/platforms/vscode/webview/tsconfig.json b/tsconfig.base.json similarity index 52% rename from packages/platforms/vscode/webview/tsconfig.json rename to tsconfig.base.json index db82f5f..b750baf 100644 --- a/packages/platforms/vscode/webview/tsconfig.json +++ b/tsconfig.base.json @@ -1,16 +1,19 @@ { "compilerOptions": { "target": "ES2022", - "module": "ES2022", + "module": "ESNext", "moduleResolution": "bundler", - "lib": ["ES2022", "DOM", "DOM.Iterable"], "strict": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, + "noEmit": true, + "moduleDetection": "force", + "paths": { + "@shared": ["./shared/index.ts"] + }, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "declaration": false, "jsx": "react-jsx" - }, - "include": ["./**/*"], - "exclude": ["node_modules"] + } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..64dc399 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.base.json", + "compilerOptions": { + "lib": ["ES2022"], + "types": ["node", "vscode", "vitest/globals"], + "rootDir": "." + }, + "include": ["extension/**/*", "shared/**/*"], + "exclude": ["node_modules", "dist", "webview"] +} diff --git a/packages/platforms/vscode/vite.config.ts b/vite.config.ts similarity index 81% rename from packages/platforms/vscode/vite.config.ts rename to vite.config.ts index 9481a14..aef571a 100644 --- a/packages/platforms/vscode/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,15 @@ +import path from "node:path"; import react from "@vitejs/plugin-react"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [react()], root: "webview", + resolve: { + alias: { + "@shared": path.resolve(__dirname, "shared/index.ts"), + }, + }, build: { outDir: "../dist/webview", emptyOutDir: true, diff --git a/vitest.config.extension.ts b/vitest.config.extension.ts new file mode 100644 index 0000000..e689cb7 --- /dev/null +++ b/vitest.config.extension.ts @@ -0,0 +1,16 @@ +import path from "node:path"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + resolve: { + alias: { + "@shared": path.resolve(__dirname, "shared/index.ts"), + }, + }, + test: { + environment: "node", + globals: true, + include: ["extension/__tests__/**/*.test.ts"], + setupFiles: ["extension/__tests__/setup.ts"], + }, +}); diff --git a/packages/platforms/vscode/vitest.config.ts b/vitest.config.ts similarity index 64% rename from packages/platforms/vscode/vitest.config.ts rename to vitest.config.ts index 0d2b4b4..f777a9c 100644 --- a/packages/platforms/vscode/vitest.config.ts +++ b/vitest.config.ts @@ -1,12 +1,18 @@ +import path from "node:path"; import react from "@vitejs/plugin-react"; import { defineConfig } from "vitest/config"; export default defineConfig({ plugins: [react()], + resolve: { + alias: { + "@shared": path.resolve(__dirname, "shared/index.ts"), + }, + }, test: { environment: "jsdom", root: "webview", - setupFiles: ["./__tests__/setup.ts"], + setupFiles: [path.resolve(__dirname, "webview/__tests__/setup.ts")], include: ["./__tests__/**/*.test.{ts,tsx}"], globals: true, css: { diff --git a/packages/platforms/vscode/webview/App.tsx b/webview/App.tsx similarity index 99% rename from packages/platforms/vscode/webview/App.tsx rename to webview/App.tsx index 1effc02..ffe8e4b 100644 --- a/packages/platforms/vscode/webview/App.tsx +++ b/webview/App.tsx @@ -1,4 +1,4 @@ -import type { AgentEvent, AgentInfo, ChatSession, SkillInfo, TodoItem } from "@opencodegui/core"; +import type { AgentEvent, AgentInfo, ChatSession, SkillInfo, TodoItem } from "@shared"; import { useCallback, useEffect, useRef, useState } from "react"; import { EmptyState } from "./components/molecules/EmptyState"; import { FileChangesHeader } from "./components/molecules/FileChangesHeader"; diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/ActionButton.test.tsx b/webview/__tests__/components/atoms/ActionButton.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/ActionButton.test.tsx rename to webview/__tests__/components/atoms/ActionButton.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/IconButton.test.tsx b/webview/__tests__/components/atoms/IconButton.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/IconButton.test.tsx rename to webview/__tests__/components/atoms/IconButton.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/LinkButton.test.tsx b/webview/__tests__/components/atoms/LinkButton.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/LinkButton.test.tsx rename to webview/__tests__/components/atoms/LinkButton.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/ListItem.test.tsx b/webview/__tests__/components/atoms/ListItem.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/ListItem.test.tsx rename to webview/__tests__/components/atoms/ListItem.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/Popover.test.tsx b/webview/__tests__/components/atoms/Popover.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/Popover.test.tsx rename to webview/__tests__/components/atoms/Popover.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/StatusItem.test.tsx b/webview/__tests__/components/atoms/StatusItem.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/StatusItem.test.tsx rename to webview/__tests__/components/atoms/StatusItem.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/StreamingIndicator.test.tsx b/webview/__tests__/components/atoms/StreamingIndicator.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/StreamingIndicator.test.tsx rename to webview/__tests__/components/atoms/StreamingIndicator.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/file-type-icons.test.tsx b/webview/__tests__/components/atoms/file-type-icons.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/file-type-icons.test.tsx rename to webview/__tests__/components/atoms/file-type-icons.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/atoms/icons.test.tsx b/webview/__tests__/components/atoms/icons.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/atoms/icons.test.tsx rename to webview/__tests__/components/atoms/icons.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/AgentPopup.test.tsx b/webview/__tests__/components/molecules/AgentPopup.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/AgentPopup.test.tsx rename to webview/__tests__/components/molecules/AgentPopup.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/DiffView.test.tsx b/webview/__tests__/components/molecules/DiffView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/DiffView.test.tsx rename to webview/__tests__/components/molecules/DiffView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/EmptyState.test.tsx b/webview/__tests__/components/molecules/EmptyState.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/EmptyState.test.tsx rename to webview/__tests__/components/molecules/EmptyState.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/FileAttachmentBar.test.tsx b/webview/__tests__/components/molecules/FileAttachmentBar.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/FileAttachmentBar.test.tsx rename to webview/__tests__/components/molecules/FileAttachmentBar.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/FileChangesHeader.test.tsx b/webview/__tests__/components/molecules/FileChangesHeader.test.tsx similarity index 99% rename from packages/platforms/vscode/webview/__tests__/components/molecules/FileChangesHeader.test.tsx rename to webview/__tests__/components/molecules/FileChangesHeader.test.tsx index 5bfd43e..7ea119c 100644 --- a/packages/platforms/vscode/webview/__tests__/components/molecules/FileChangesHeader.test.tsx +++ b/webview/__tests__/components/molecules/FileChangesHeader.test.tsx @@ -1,4 +1,4 @@ -import type { FileDiff } from "@opencodegui/core"; +import type { FileDiff } from "@shared"; import { fireEvent, render, screen } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import { FileChangesHeader } from "../../../components/molecules/FileChangesHeader"; diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/FileCreateView.test.tsx b/webview/__tests__/components/molecules/FileCreateView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/FileCreateView.test.tsx rename to webview/__tests__/components/molecules/FileCreateView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/HashFilePopup.test.tsx b/webview/__tests__/components/molecules/HashFilePopup.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/HashFilePopup.test.tsx rename to webview/__tests__/components/molecules/HashFilePopup.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/ModelSelector.test.tsx b/webview/__tests__/components/molecules/ModelSelector.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/ModelSelector.test.tsx rename to webview/__tests__/components/molecules/ModelSelector.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/ShellResultView.test.tsx b/webview/__tests__/components/molecules/ShellResultView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/ShellResultView.test.tsx rename to webview/__tests__/components/molecules/ShellResultView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/SkillPopup.test.tsx b/webview/__tests__/components/molecules/SkillPopup.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/SkillPopup.test.tsx rename to webview/__tests__/components/molecules/SkillPopup.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/TextPartView.test.tsx b/webview/__tests__/components/molecules/TextPartView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/molecules/TextPartView.test.tsx rename to webview/__tests__/components/molecules/TextPartView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/TodoHeader.test.tsx b/webview/__tests__/components/molecules/TodoHeader.test.tsx similarity index 89% rename from packages/platforms/vscode/webview/__tests__/components/molecules/TodoHeader.test.tsx rename to webview/__tests__/components/molecules/TodoHeader.test.tsx index 19d4afa..34b3d95 100644 --- a/packages/platforms/vscode/webview/__tests__/components/molecules/TodoHeader.test.tsx +++ b/webview/__tests__/components/molecules/TodoHeader.test.tsx @@ -4,9 +4,9 @@ import { TodoHeader } from "../../../components/molecules/TodoHeader"; import type { TodoItem } from "../../../utils/todo"; const sampleTodos: TodoItem[] = [ - { content: "Task 1", status: "completed", priority: undefined }, + { content: "Task 1", status: "completed", priority: "medium" }, { content: "Task 2", status: "in_progress", priority: "high" }, - { content: "Task 3", status: "pending", priority: undefined }, + { content: "Task 3", status: "pending", priority: "medium" }, ]; describe("TodoHeader", () => { @@ -53,8 +53,8 @@ describe("TodoHeader", () => { // shows full completion count it("全完了数を表示すること", () => { const allDone: TodoItem[] = [ - { content: "Done 1", status: "completed", priority: undefined }, - { content: "Done 2", status: "done", priority: undefined }, + { content: "Done 1", status: "completed", priority: "medium" }, + { content: "Done 2", status: "done", priority: "medium" }, ]; const { container } = render(); expect(container.querySelector(".count")?.textContent).toBe("2/2"); diff --git a/packages/platforms/vscode/webview/__tests__/components/molecules/TodoView.test.tsx b/webview/__tests__/components/molecules/TodoView.test.tsx similarity index 97% rename from packages/platforms/vscode/webview/__tests__/components/molecules/TodoView.test.tsx rename to webview/__tests__/components/molecules/TodoView.test.tsx index a7dd911..df48209 100644 --- a/packages/platforms/vscode/webview/__tests__/components/molecules/TodoView.test.tsx +++ b/webview/__tests__/components/molecules/TodoView.test.tsx @@ -4,7 +4,7 @@ import { TodoView } from "../../../components/molecules/TodoView"; import type { TodoItem } from "../../../utils/todo"; const sampleTodos: TodoItem[] = [ - { content: "Task 1", status: "completed", priority: undefined }, + { content: "Task 1", status: "completed", priority: "medium" }, { content: "Task 2", status: "in_progress", priority: "high" }, { content: "Task 3", status: "pending", priority: "low" }, ]; diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/ChatHeader.test.tsx b/webview/__tests__/components/organisms/ChatHeader.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/ChatHeader.test.tsx rename to webview/__tests__/components/organisms/ChatHeader.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/MessageItem.test.tsx b/webview/__tests__/components/organisms/MessageItem.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/MessageItem.test.tsx rename to webview/__tests__/components/organisms/MessageItem.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/MessagesArea.test.tsx b/webview/__tests__/components/organisms/MessagesArea.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/MessagesArea.test.tsx rename to webview/__tests__/components/organisms/MessagesArea.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/PermissionView.test.tsx b/webview/__tests__/components/organisms/PermissionView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/PermissionView.test.tsx rename to webview/__tests__/components/organisms/PermissionView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/QuestionView.test.tsx b/webview/__tests__/components/organisms/QuestionView.test.tsx similarity index 99% rename from packages/platforms/vscode/webview/__tests__/components/organisms/QuestionView.test.tsx rename to webview/__tests__/components/organisms/QuestionView.test.tsx index eec4ffc..4a44353 100644 --- a/packages/platforms/vscode/webview/__tests__/components/organisms/QuestionView.test.tsx +++ b/webview/__tests__/components/organisms/QuestionView.test.tsx @@ -1,4 +1,4 @@ -import type { QuestionRequest } from "@opencodegui/core"; +import type { QuestionRequest } from "@shared"; import { fireEvent, render } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { QuestionView } from "../../../components/organisms/QuestionView"; diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/SessionList.test.tsx b/webview/__tests__/components/organisms/SessionList.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/SessionList.test.tsx rename to webview/__tests__/components/organisms/SessionList.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/SubtaskPartView.test.tsx b/webview/__tests__/components/organisms/SubtaskPartView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/SubtaskPartView.test.tsx rename to webview/__tests__/components/organisms/SubtaskPartView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx b/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/ToolConfigPanel.test.tsx rename to webview/__tests__/components/organisms/ToolConfigPanel.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/components/organisms/ToolPartView.test.tsx b/webview/__tests__/components/organisms/ToolPartView.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/components/organisms/ToolPartView.test.tsx rename to webview/__tests__/components/organisms/ToolPartView.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/factories.ts b/webview/__tests__/factories.ts similarity index 96% rename from packages/platforms/vscode/webview/__tests__/factories.ts rename to webview/__tests__/factories.ts index 50b9d5b..2287a74 100644 --- a/packages/platforms/vscode/webview/__tests__/factories.ts +++ b/webview/__tests__/factories.ts @@ -1,12 +1,4 @@ -import type { - AgentEvent, - ChatMessage, - ChatSession, - Permission, - ProviderInfo, - TextPart, - ToolPart, -} from "@opencodegui/core"; +import type { AgentEvent, ChatMessage, ChatSession, Permission, ProviderInfo, TextPart, ToolPart } from "@shared"; // --- Session --- diff --git a/packages/platforms/vscode/webview/__tests__/helpers.tsx b/webview/__tests__/helpers.tsx similarity index 86% rename from packages/platforms/vscode/webview/__tests__/helpers.tsx rename to webview/__tests__/helpers.tsx index 1c66313..8c9fb88 100644 --- a/packages/platforms/vscode/webview/__tests__/helpers.tsx +++ b/webview/__tests__/helpers.tsx @@ -4,7 +4,7 @@ import type { HostToUIMessage } from "../vscode-api"; /** * Extension Host → Webview メッセージを擬似送信する。 - * chat-view-provider.ts が panel.webview.postMessage() で送るメッセージを再現する。 + * chat-panel.ts が panel.webview.postMessage() で送るメッセージを再現する。 */ export async function sendExtMessage(msg: HostToUIMessage): Promise { await act(async () => { diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useAutoScroll.test.ts b/webview/__tests__/hooks/useAutoScroll.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/hooks/useAutoScroll.test.ts rename to webview/__tests__/hooks/useAutoScroll.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useClickOutside.test.ts b/webview/__tests__/hooks/useClickOutside.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/hooks/useClickOutside.test.ts rename to webview/__tests__/hooks/useClickOutside.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useFileChanges.test.ts b/webview/__tests__/hooks/useFileChanges.test.ts similarity index 97% rename from packages/platforms/vscode/webview/__tests__/hooks/useFileChanges.test.ts rename to webview/__tests__/hooks/useFileChanges.test.ts index d2dd584..c389902 100644 --- a/packages/platforms/vscode/webview/__tests__/hooks/useFileChanges.test.ts +++ b/webview/__tests__/hooks/useFileChanges.test.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, FileDiff } from "@opencodegui/core"; +import type { AgentEvent, FileDiff } from "@shared"; import { act, renderHook } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { useFileChanges } from "../../hooks/useFileChanges"; diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useInputHistory.test.ts b/webview/__tests__/hooks/useInputHistory.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/hooks/useInputHistory.test.ts rename to webview/__tests__/hooks/useInputHistory.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useLocale.test.ts b/webview/__tests__/hooks/useLocale.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/hooks/useLocale.test.ts rename to webview/__tests__/hooks/useLocale.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useMessages.test.ts b/webview/__tests__/hooks/useMessages.test.ts similarity index 99% rename from packages/platforms/vscode/webview/__tests__/hooks/useMessages.test.ts rename to webview/__tests__/hooks/useMessages.test.ts index df95727..30d2032 100644 --- a/packages/platforms/vscode/webview/__tests__/hooks/useMessages.test.ts +++ b/webview/__tests__/hooks/useMessages.test.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, ChatSession } from "@opencodegui/core"; +import type { AgentEvent, ChatSession } from "@shared"; import { act, renderHook } from "@testing-library/react"; import { createRef, type RefObject } from "react"; import { describe, expect, it } from "vitest"; diff --git a/packages/platforms/vscode/webview/__tests__/hooks/usePermissions.test.ts b/webview/__tests__/hooks/usePermissions.test.ts similarity index 98% rename from packages/platforms/vscode/webview/__tests__/hooks/usePermissions.test.ts rename to webview/__tests__/hooks/usePermissions.test.ts index e83476f..aba5480 100644 --- a/packages/platforms/vscode/webview/__tests__/hooks/usePermissions.test.ts +++ b/webview/__tests__/hooks/usePermissions.test.ts @@ -1,4 +1,4 @@ -import type { AgentEvent } from "@opencodegui/core"; +import type { AgentEvent } from "@shared"; import { act, renderHook } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { usePermissions } from "../../hooks/usePermissions"; diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useProviders.test.ts b/webview/__tests__/hooks/useProviders.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/hooks/useProviders.test.ts rename to webview/__tests__/hooks/useProviders.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useQuestions.test.ts b/webview/__tests__/hooks/useQuestions.test.ts similarity index 98% rename from packages/platforms/vscode/webview/__tests__/hooks/useQuestions.test.ts rename to webview/__tests__/hooks/useQuestions.test.ts index aefca58..89ad479 100644 --- a/packages/platforms/vscode/webview/__tests__/hooks/useQuestions.test.ts +++ b/webview/__tests__/hooks/useQuestions.test.ts @@ -1,4 +1,4 @@ -import type { AgentEvent } from "@opencodegui/core"; +import type { AgentEvent } from "@shared"; import { act, renderHook } from "@testing-library/react"; import { describe, expect, it } from "vitest"; import { useQuestions } from "../../hooks/useQuestions"; diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useSession.test.ts b/webview/__tests__/hooks/useSession.test.ts similarity index 99% rename from packages/platforms/vscode/webview/__tests__/hooks/useSession.test.ts rename to webview/__tests__/hooks/useSession.test.ts index ac2ea58..3452ad9 100644 --- a/packages/platforms/vscode/webview/__tests__/hooks/useSession.test.ts +++ b/webview/__tests__/hooks/useSession.test.ts @@ -1,4 +1,4 @@ -import type { AgentEvent } from "@opencodegui/core"; +import type { AgentEvent } from "@shared"; import { act, renderHook } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import { useSession } from "../../hooks/useSession"; diff --git a/packages/platforms/vscode/webview/__tests__/hooks/useSoundNotification.test.ts b/webview/__tests__/hooks/useSoundNotification.test.ts similarity index 91% rename from packages/platforms/vscode/webview/__tests__/hooks/useSoundNotification.test.ts rename to webview/__tests__/hooks/useSoundNotification.test.ts index 620facf..268b873 100644 --- a/packages/platforms/vscode/webview/__tests__/hooks/useSoundNotification.test.ts +++ b/webview/__tests__/hooks/useSoundNotification.test.ts @@ -1,4 +1,4 @@ -import type { AgentEvent } from "@opencodegui/core"; +import type { AgentEvent } from "@shared"; import { act, renderHook } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { useSoundNotification } from "../../hooks/useSoundNotification"; @@ -95,16 +95,16 @@ describe("useSoundNotification", () => { }); }); - // permission.updated triggers permissionRequest - context("permission.updated イベントを受信した場合", () => { + // permission.asked triggers permissionRequest + context("permission.asked イベントを受信した場合", () => { // plays sound it("サウンドが再生されること", () => { const { result } = renderHook(() => useSoundNotification()); act(() => { result.current.handleSoundEvent({ - type: "permission.updated", - properties: { id: "perm1", title: "allow bash" }, + type: "permission.asked", + properties: { id: "perm1", sessionID: "s1", permission: "execute", patterns: ["bash"], metadata: {}, always: [] }, } as unknown as AgentEvent); }); @@ -140,8 +140,8 @@ describe("useSoundNotification", () => { act(() => { result.current.handleSoundEvent({ - type: "permission.updated", - properties: { id: "perm1", title: "allow bash" }, + type: "permission.asked", + properties: { id: "perm1", sessionID: "s1", permission: "execute", patterns: ["bash"], metadata: {}, always: [] }, } as unknown as AgentEvent); }); diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/01-initialization.test.tsx b/webview/__tests__/scenarios/01-initialization.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/01-initialization.test.tsx rename to webview/__tests__/scenarios/01-initialization.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/02-session-lifecycle.test.tsx b/webview/__tests__/scenarios/02-session-lifecycle.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/02-session-lifecycle.test.tsx rename to webview/__tests__/scenarios/02-session-lifecycle.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/03-messaging.test.tsx b/webview/__tests__/scenarios/03-messaging.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/03-messaging.test.tsx rename to webview/__tests__/scenarios/03-messaging.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/04-message-editing.test.tsx b/webview/__tests__/scenarios/04-message-editing.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/04-message-editing.test.tsx rename to webview/__tests__/scenarios/04-message-editing.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/05-permissions.test.tsx b/webview/__tests__/scenarios/05-permissions.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/05-permissions.test.tsx rename to webview/__tests__/scenarios/05-permissions.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/06-model-selection.test.tsx b/webview/__tests__/scenarios/06-model-selection.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/06-model-selection.test.tsx rename to webview/__tests__/scenarios/06-model-selection.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/07-file-context.test.tsx b/webview/__tests__/scenarios/07-file-context.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/07-file-context.test.tsx rename to webview/__tests__/scenarios/07-file-context.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/09-settings.test.tsx b/webview/__tests__/scenarios/09-settings.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/09-settings.test.tsx rename to webview/__tests__/scenarios/09-settings.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/10-tool-display.test.tsx b/webview/__tests__/scenarios/10-tool-display.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/10-tool-display.test.tsx rename to webview/__tests__/scenarios/10-tool-display.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/11-todo.test.tsx b/webview/__tests__/scenarios/11-todo.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/11-todo.test.tsx rename to webview/__tests__/scenarios/11-todo.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/12-reasoning-display.test.tsx b/webview/__tests__/scenarios/12-reasoning-display.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/12-reasoning-display.test.tsx rename to webview/__tests__/scenarios/12-reasoning-display.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/13-keyboard-ime.test.tsx b/webview/__tests__/scenarios/13-keyboard-ime.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/13-keyboard-ime.test.tsx rename to webview/__tests__/scenarios/13-keyboard-ime.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/14-shell-command.test.tsx b/webview/__tests__/scenarios/14-shell-command.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/14-shell-command.test.tsx rename to webview/__tests__/scenarios/14-shell-command.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/15-file-changes.test.tsx b/webview/__tests__/scenarios/15-file-changes.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/15-file-changes.test.tsx rename to webview/__tests__/scenarios/15-file-changes.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/16-session-fork.test.tsx b/webview/__tests__/scenarios/16-session-fork.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/16-session-fork.test.tsx rename to webview/__tests__/scenarios/16-session-fork.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/17-child-session-nav.test.tsx b/webview/__tests__/scenarios/17-child-session-nav.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/17-child-session-nav.test.tsx rename to webview/__tests__/scenarios/17-child-session-nav.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/18-agent-mention.test.tsx b/webview/__tests__/scenarios/18-agent-mention.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/18-agent-mention.test.tsx rename to webview/__tests__/scenarios/18-agent-mention.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/19-session-share.test.tsx b/webview/__tests__/scenarios/19-session-share.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/19-session-share.test.tsx rename to webview/__tests__/scenarios/19-session-share.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/20-undo-redo.test.tsx b/webview/__tests__/scenarios/20-undo-redo.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/20-undo-redo.test.tsx rename to webview/__tests__/scenarios/20-undo-redo.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/21-popup-tab-select.test.tsx b/webview/__tests__/scenarios/21-popup-tab-select.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/21-popup-tab-select.test.tsx rename to webview/__tests__/scenarios/21-popup-tab-select.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/22-auto-scroll-streaming.test.tsx b/webview/__tests__/scenarios/22-auto-scroll-streaming.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/22-auto-scroll-streaming.test.tsx rename to webview/__tests__/scenarios/22-auto-scroll-streaming.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/23-clip-context-menu.test.tsx b/webview/__tests__/scenarios/23-clip-context-menu.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/23-clip-context-menu.test.tsx rename to webview/__tests__/scenarios/23-clip-context-menu.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/24-input-history.test.tsx b/webview/__tests__/scenarios/24-input-history.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/24-input-history.test.tsx rename to webview/__tests__/scenarios/24-input-history.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/25-diff-review.test.tsx b/webview/__tests__/scenarios/25-diff-review.test.tsx similarity index 100% rename from packages/platforms/vscode/webview/__tests__/scenarios/25-diff-review.test.tsx rename to webview/__tests__/scenarios/25-diff-review.test.tsx diff --git a/packages/platforms/vscode/webview/__tests__/scenarios/25-sound-notification.test.tsx b/webview/__tests__/scenarios/25-sound-notification.test.tsx similarity index 92% rename from packages/platforms/vscode/webview/__tests__/scenarios/25-sound-notification.test.tsx rename to webview/__tests__/scenarios/25-sound-notification.test.tsx index 2a7d6bb..f353de0 100644 --- a/packages/platforms/vscode/webview/__tests__/scenarios/25-sound-notification.test.tsx +++ b/webview/__tests__/scenarios/25-sound-notification.test.tsx @@ -95,8 +95,16 @@ describe("サウンド通知", () => { await sendExtMessage({ type: "event", event: { - type: "permission.updated", - properties: { id: "perm1", title: "allow bash", sessionID: "s1", messageID: "m1", type: "execute" }, + type: "permission.asked", + properties: { + id: "perm1", + sessionID: "s1", + permission: "execute", + patterns: ["bash"], + metadata: {}, + always: [], + tool: { messageID: "m1", callID: "c1" }, + }, }, }); diff --git a/packages/platforms/vscode/webview/__tests__/setup.ts b/webview/__tests__/setup.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/setup.ts rename to webview/__tests__/setup.ts diff --git a/packages/platforms/vscode/webview/__tests__/utils/diff.test.ts b/webview/__tests__/utils/diff.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/utils/diff.test.ts rename to webview/__tests__/utils/diff.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/utils/file-icons.test.ts b/webview/__tests__/utils/file-icons.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/utils/file-icons.test.ts rename to webview/__tests__/utils/file-icons.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/utils/markdown.test.ts b/webview/__tests__/utils/markdown.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/utils/markdown.test.ts rename to webview/__tests__/utils/markdown.test.ts diff --git a/packages/platforms/vscode/webview/__tests__/utils/todo.test.ts b/webview/__tests__/utils/todo.test.ts similarity index 81% rename from packages/platforms/vscode/webview/__tests__/utils/todo.test.ts rename to webview/__tests__/utils/todo.test.ts index 0ad97a0..6c47a92 100644 --- a/packages/platforms/vscode/webview/__tests__/utils/todo.test.ts +++ b/webview/__tests__/utils/todo.test.ts @@ -7,7 +7,10 @@ describe("parseTodos", () => { it("TodoItem 配列を返すこと", () => { const json = JSON.stringify([{ content: "task1" }, { content: "task2", status: "done" }]); const result = parseTodos(json); - expect(result).toEqual([{ content: "task1" }, { content: "task2", status: "done" }]); + expect(result).toEqual([ + { content: "task1", status: "pending", priority: "medium" }, + { content: "task2", status: "done", priority: "medium" }, + ]); }); }); @@ -15,7 +18,7 @@ describe("parseTodos", () => { context("オブジェクト配列を直接渡した場合", () => { it("TodoItem 配列を返すこと", () => { const arr = [{ content: "task1", priority: "high" }]; - expect(parseTodos(arr)).toEqual(arr); + expect(parseTodos(arr)).toEqual([{ content: "task1", status: "pending", priority: "high" }]); }); }); @@ -23,7 +26,7 @@ describe("parseTodos", () => { context("todos キーを持つラッパーオブジェクトの場合", () => { it("todos 配列を返すこと", () => { const data = { todos: [{ content: "a" }] }; - expect(parseTodos(data)).toEqual([{ content: "a" }]); + expect(parseTodos(data)).toEqual([{ content: "a", status: "pending", priority: "medium" }]); }); }); @@ -31,7 +34,7 @@ describe("parseTodos", () => { context("items キーを持つラッパーオブジェクトの場合", () => { it("items 配列を返すこと", () => { const data = { items: [{ content: "b" }] }; - expect(parseTodos(data)).toEqual([{ content: "b" }]); + expect(parseTodos(data)).toEqual([{ content: "b", status: "pending", priority: "medium" }]); }); }); diff --git a/packages/platforms/vscode/webview/__tests__/utils/tool-categories.test.ts b/webview/__tests__/utils/tool-categories.test.ts similarity index 100% rename from packages/platforms/vscode/webview/__tests__/utils/tool-categories.test.ts rename to webview/__tests__/utils/tool-categories.test.ts diff --git a/packages/platforms/vscode/webview/bridges/VscodeBridge.ts b/webview/bridges/VscodeBridge.ts similarity index 96% rename from packages/platforms/vscode/webview/bridges/VscodeBridge.ts rename to webview/bridges/VscodeBridge.ts index b6b31ac..50036af 100644 --- a/packages/platforms/vscode/webview/bridges/VscodeBridge.ts +++ b/webview/bridges/VscodeBridge.ts @@ -5,7 +5,7 @@ * platform-independent communication between UI and extension host. */ -import type { Disposable, HostToUIMessage, IBridge, UIPersistedState, UIToHostMessage } from "@opencodegui/core"; +import type { Disposable, HostToUIMessage, IBridge, UIPersistedState, UIToHostMessage } from "@shared"; interface VsCodeApi { postMessage(message: UIToHostMessage): void; diff --git a/packages/platforms/vscode/webview/components/atoms/ActionButton/ActionButton.module.css b/webview/components/atoms/ActionButton/ActionButton.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ActionButton/ActionButton.module.css rename to webview/components/atoms/ActionButton/ActionButton.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/ActionButton/ActionButton.tsx b/webview/components/atoms/ActionButton/ActionButton.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ActionButton/ActionButton.tsx rename to webview/components/atoms/ActionButton/ActionButton.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/ActionButton/index.ts b/webview/components/atoms/ActionButton/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ActionButton/index.ts rename to webview/components/atoms/ActionButton/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/IconButton/IconButton.module.css b/webview/components/atoms/IconButton/IconButton.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/IconButton/IconButton.module.css rename to webview/components/atoms/IconButton/IconButton.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/IconButton/IconButton.tsx b/webview/components/atoms/IconButton/IconButton.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/IconButton/IconButton.tsx rename to webview/components/atoms/IconButton/IconButton.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/IconButton/index.ts b/webview/components/atoms/IconButton/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/IconButton/index.ts rename to webview/components/atoms/IconButton/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/LinkButton/LinkButton.module.css b/webview/components/atoms/LinkButton/LinkButton.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/LinkButton/LinkButton.module.css rename to webview/components/atoms/LinkButton/LinkButton.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/LinkButton/LinkButton.tsx b/webview/components/atoms/LinkButton/LinkButton.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/LinkButton/LinkButton.tsx rename to webview/components/atoms/LinkButton/LinkButton.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/LinkButton/index.ts b/webview/components/atoms/LinkButton/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/LinkButton/index.ts rename to webview/components/atoms/LinkButton/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/ListItem/ListItem.module.css b/webview/components/atoms/ListItem/ListItem.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ListItem/ListItem.module.css rename to webview/components/atoms/ListItem/ListItem.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/ListItem/ListItem.tsx b/webview/components/atoms/ListItem/ListItem.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ListItem/ListItem.tsx rename to webview/components/atoms/ListItem/ListItem.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/ListItem/index.ts b/webview/components/atoms/ListItem/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ListItem/index.ts rename to webview/components/atoms/ListItem/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/Popover/Popover.module.css b/webview/components/atoms/Popover/Popover.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/Popover/Popover.module.css rename to webview/components/atoms/Popover/Popover.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/Popover/Popover.tsx b/webview/components/atoms/Popover/Popover.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/Popover/Popover.tsx rename to webview/components/atoms/Popover/Popover.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/Popover/index.ts b/webview/components/atoms/Popover/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/Popover/index.ts rename to webview/components/atoms/Popover/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.module.css b/webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.module.css rename to webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.tsx b/webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.tsx rename to webview/components/atoms/ScrollToBottomButton/ScrollToBottomButton.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/ScrollToBottomButton/index.ts b/webview/components/atoms/ScrollToBottomButton/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/ScrollToBottomButton/index.ts rename to webview/components/atoms/ScrollToBottomButton/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/StatusItem/StatusItem.module.css b/webview/components/atoms/StatusItem/StatusItem.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/StatusItem/StatusItem.module.css rename to webview/components/atoms/StatusItem/StatusItem.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/StatusItem/StatusItem.tsx b/webview/components/atoms/StatusItem/StatusItem.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/StatusItem/StatusItem.tsx rename to webview/components/atoms/StatusItem/StatusItem.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/StatusItem/index.ts b/webview/components/atoms/StatusItem/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/StatusItem/index.ts rename to webview/components/atoms/StatusItem/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/StreamingIndicator/StreamingIndicator.module.css b/webview/components/atoms/StreamingIndicator/StreamingIndicator.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/StreamingIndicator/StreamingIndicator.module.css rename to webview/components/atoms/StreamingIndicator/StreamingIndicator.module.css diff --git a/packages/platforms/vscode/webview/components/atoms/StreamingIndicator/StreamingIndicator.tsx b/webview/components/atoms/StreamingIndicator/StreamingIndicator.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/StreamingIndicator/StreamingIndicator.tsx rename to webview/components/atoms/StreamingIndicator/StreamingIndicator.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/StreamingIndicator/index.ts b/webview/components/atoms/StreamingIndicator/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/StreamingIndicator/index.ts rename to webview/components/atoms/StreamingIndicator/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/icons/file-type-icons/file-type-icons.tsx b/webview/components/atoms/icons/file-type-icons/file-type-icons.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/icons/file-type-icons/file-type-icons.tsx rename to webview/components/atoms/icons/file-type-icons/file-type-icons.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/icons/file-type-icons/index.ts b/webview/components/atoms/icons/file-type-icons/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/icons/file-type-icons/index.ts rename to webview/components/atoms/icons/file-type-icons/index.ts diff --git a/packages/platforms/vscode/webview/components/atoms/icons/icons.tsx b/webview/components/atoms/icons/icons.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/icons/icons.tsx rename to webview/components/atoms/icons/icons.tsx diff --git a/packages/platforms/vscode/webview/components/atoms/icons/index.ts b/webview/components/atoms/icons/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/atoms/icons/index.ts rename to webview/components/atoms/icons/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/AgentPopup/AgentPopup.module.css b/webview/components/molecules/AgentPopup/AgentPopup.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/AgentPopup/AgentPopup.module.css rename to webview/components/molecules/AgentPopup/AgentPopup.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/AgentPopup/AgentPopup.tsx b/webview/components/molecules/AgentPopup/AgentPopup.tsx similarity index 94% rename from packages/platforms/vscode/webview/components/molecules/AgentPopup/AgentPopup.tsx rename to webview/components/molecules/AgentPopup/AgentPopup.tsx index c64b2a4..1e66920 100644 --- a/packages/platforms/vscode/webview/components/molecules/AgentPopup/AgentPopup.tsx +++ b/webview/components/molecules/AgentPopup/AgentPopup.tsx @@ -1,4 +1,4 @@ -import type { AgentInfo } from "@opencodegui/core"; +import type { AgentInfo } from "@shared"; import { useLocale } from "../../../locales"; import { ListItem } from "../../atoms/ListItem"; import styles from "./AgentPopup.module.css"; diff --git a/packages/platforms/vscode/webview/components/molecules/AgentPopup/index.ts b/webview/components/molecules/AgentPopup/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/AgentPopup/index.ts rename to webview/components/molecules/AgentPopup/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/AgentSelector/AgentSelector.module.css b/webview/components/molecules/AgentSelector/AgentSelector.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/AgentSelector/AgentSelector.module.css rename to webview/components/molecules/AgentSelector/AgentSelector.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/AgentSelector/AgentSelector.tsx b/webview/components/molecules/AgentSelector/AgentSelector.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/molecules/AgentSelector/AgentSelector.tsx rename to webview/components/molecules/AgentSelector/AgentSelector.tsx index 62b4ff5..1c46a49 100644 --- a/packages/platforms/vscode/webview/components/molecules/AgentSelector/AgentSelector.tsx +++ b/webview/components/molecules/AgentSelector/AgentSelector.tsx @@ -1,4 +1,4 @@ -import type { AgentInfo } from "@opencodegui/core"; +import type { AgentInfo } from "@shared"; import { useMemo } from "react"; import { useLocale } from "../../../locales"; import { AgentIcon, ChevronRightIcon } from "../../atoms/icons"; diff --git a/packages/platforms/vscode/webview/components/molecules/AgentSelector/index.ts b/webview/components/molecules/AgentSelector/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/AgentSelector/index.ts rename to webview/components/molecules/AgentSelector/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/DiffView/DiffView.module.css b/webview/components/molecules/DiffView/DiffView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/DiffView/DiffView.module.css rename to webview/components/molecules/DiffView/DiffView.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/DiffView/DiffView.tsx b/webview/components/molecules/DiffView/DiffView.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/DiffView/DiffView.tsx rename to webview/components/molecules/DiffView/DiffView.tsx diff --git a/packages/platforms/vscode/webview/components/molecules/DiffView/index.ts b/webview/components/molecules/DiffView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/DiffView/index.ts rename to webview/components/molecules/DiffView/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/EmptyState/EmptyState.module.css b/webview/components/molecules/EmptyState/EmptyState.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/EmptyState/EmptyState.module.css rename to webview/components/molecules/EmptyState/EmptyState.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/EmptyState/EmptyState.tsx b/webview/components/molecules/EmptyState/EmptyState.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/EmptyState/EmptyState.tsx rename to webview/components/molecules/EmptyState/EmptyState.tsx diff --git a/packages/platforms/vscode/webview/components/molecules/EmptyState/index.ts b/webview/components/molecules/EmptyState/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/EmptyState/index.ts rename to webview/components/molecules/EmptyState/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.module.css b/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.module.css rename to webview/components/molecules/FileAttachmentBar/FileAttachmentBar.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.tsx b/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.tsx similarity index 99% rename from packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.tsx rename to webview/components/molecules/FileAttachmentBar/FileAttachmentBar.tsx index 8daf58c..9fd643d 100644 --- a/packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.tsx +++ b/webview/components/molecules/FileAttachmentBar/FileAttachmentBar.tsx @@ -1,4 +1,4 @@ -import type { AgentInfo, SkillInfo } from "@opencodegui/core"; +import type { AgentInfo, SkillInfo } from "@shared"; import { useLocale } from "../../../locales"; import { getFileIcon } from "../../../utils/file-icons"; import type { FileAttachment } from "../../../vscode-api"; diff --git a/packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/index.ts b/webview/components/molecules/FileAttachmentBar/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/FileAttachmentBar/index.ts rename to webview/components/molecules/FileAttachmentBar/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/FileChangesHeader/FileChangesHeader.module.css b/webview/components/molecules/FileChangesHeader/FileChangesHeader.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/FileChangesHeader/FileChangesHeader.module.css rename to webview/components/molecules/FileChangesHeader/FileChangesHeader.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/FileChangesHeader/FileChangesHeader.tsx b/webview/components/molecules/FileChangesHeader/FileChangesHeader.tsx similarity index 89% rename from packages/platforms/vscode/webview/components/molecules/FileChangesHeader/FileChangesHeader.tsx rename to webview/components/molecules/FileChangesHeader/FileChangesHeader.tsx index d9fb49b..dd69916 100644 --- a/packages/platforms/vscode/webview/components/molecules/FileChangesHeader/FileChangesHeader.tsx +++ b/webview/components/molecules/FileChangesHeader/FileChangesHeader.tsx @@ -1,4 +1,4 @@ -import type { FileDiff } from "@opencodegui/core"; +import type { FileDiff } from "@shared"; import { useState } from "react"; import { useLocale } from "../../../locales"; import { getFileIcon } from "../../../utils/file-icons"; @@ -11,7 +11,7 @@ import styles from "./FileChangesHeader.module.css"; type Props = { diffs: FileDiff[]; onOpenDiffEditor: (filePath: string, before: string, after: string) => void; - difitAvailable: boolean; + difitAvailable?: boolean; }; /** ファイルパスから basename を取得 */ @@ -29,11 +29,17 @@ function dirname(filePath: string): string { /** ファイルの変更種別を判定 */ function getFileStatus(diff: FileDiff): "added" | "deleted" | "modified" { + if ("status" in diff && diff.status) return diff.status; + if (!("before" in diff) || !("after" in diff)) return "modified"; if (diff.before === "" && diff.after !== "") return "added"; if (diff.before !== "" && diff.after === "") return "deleted"; return "modified"; } +function hasContentDiff(diff: FileDiff): diff is FileDiff & { before: string; after: string } { + return "before" in diff && "after" in diff; +} + function FileChangeItem({ diff, onOpenDiffEditor, @@ -84,9 +90,12 @@ function FileChangeItem({ className={styles.openButton} onClick={(e) => { e.stopPropagation(); - onOpenDiffEditor(diff.file, diff.before, diff.after); + if (hasContentDiff(diff)) { + onOpenDiffEditor(diff.file, diff.before, diff.after); + } }} title={t["fileChanges.openDiff"]} + disabled={!hasContentDiff(diff)} > @@ -105,14 +114,14 @@ function FileChangeItem({ {expanded && (
- + {hasContentDiff(diff) ? :
{diff.patch}
}
)} ); } -export function FileChangesHeader({ diffs, onOpenDiffEditor, difitAvailable }: Props) { +export function FileChangesHeader({ diffs, onOpenDiffEditor, difitAvailable = false }: Props) { const t = useLocale(); const [expanded, setExpanded] = useState(false); diff --git a/packages/platforms/vscode/webview/components/molecules/FileChangesHeader/index.ts b/webview/components/molecules/FileChangesHeader/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/FileChangesHeader/index.ts rename to webview/components/molecules/FileChangesHeader/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/FileCreateView/FileCreateView.tsx b/webview/components/molecules/FileCreateView/FileCreateView.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/FileCreateView/FileCreateView.tsx rename to webview/components/molecules/FileCreateView/FileCreateView.tsx diff --git a/packages/platforms/vscode/webview/components/molecules/FileCreateView/index.ts b/webview/components/molecules/FileCreateView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/FileCreateView/index.ts rename to webview/components/molecules/FileCreateView/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/HashFilePopup/HashFilePopup.module.css b/webview/components/molecules/HashFilePopup/HashFilePopup.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/HashFilePopup/HashFilePopup.module.css rename to webview/components/molecules/HashFilePopup/HashFilePopup.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/HashFilePopup/HashFilePopup.tsx b/webview/components/molecules/HashFilePopup/HashFilePopup.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/HashFilePopup/HashFilePopup.tsx rename to webview/components/molecules/HashFilePopup/HashFilePopup.tsx diff --git a/packages/platforms/vscode/webview/components/molecules/HashFilePopup/index.ts b/webview/components/molecules/HashFilePopup/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/HashFilePopup/index.ts rename to webview/components/molecules/HashFilePopup/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/ModelSelector/ModelSelector.module.css b/webview/components/molecules/ModelSelector/ModelSelector.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/ModelSelector/ModelSelector.module.css rename to webview/components/molecules/ModelSelector/ModelSelector.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/ModelSelector/ModelSelector.tsx b/webview/components/molecules/ModelSelector/ModelSelector.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/molecules/ModelSelector/ModelSelector.tsx rename to webview/components/molecules/ModelSelector/ModelSelector.tsx index 85e9f14..136f603 100644 --- a/packages/platforms/vscode/webview/components/molecules/ModelSelector/ModelSelector.tsx +++ b/webview/components/molecules/ModelSelector/ModelSelector.tsx @@ -1,4 +1,4 @@ -import type { ProviderInfo as CoreProviderInfo } from "@opencodegui/core"; +import type { ProviderInfo as CoreProviderInfo } from "@shared"; import { useMemo, useState } from "react"; import { useLocale } from "../../../locales"; import type { AllProvidersData, ModelInfo, ProviderInfo } from "../../../vscode-api"; diff --git a/packages/platforms/vscode/webview/components/molecules/ModelSelector/index.ts b/webview/components/molecules/ModelSelector/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/ModelSelector/index.ts rename to webview/components/molecules/ModelSelector/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/ShellResultView/ShellResultView.module.css b/webview/components/molecules/ShellResultView/ShellResultView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/ShellResultView/ShellResultView.module.css rename to webview/components/molecules/ShellResultView/ShellResultView.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/ShellResultView/ShellResultView.tsx b/webview/components/molecules/ShellResultView/ShellResultView.tsx similarity index 90% rename from packages/platforms/vscode/webview/components/molecules/ShellResultView/ShellResultView.tsx rename to webview/components/molecules/ShellResultView/ShellResultView.tsx index 85e2c73..0e83344 100644 --- a/packages/platforms/vscode/webview/components/molecules/ShellResultView/ShellResultView.tsx +++ b/webview/components/molecules/ShellResultView/ShellResultView.tsx @@ -1,4 +1,4 @@ -import type { ToolPart } from "@opencodegui/core"; +import type { ToolPart } from "@shared"; import { useMemo, useState } from "react"; import { useLocale } from "../../../locales"; import { ChevronRightIcon, SpinnerIcon, TerminalIcon } from "../../atoms/icons"; @@ -8,6 +8,10 @@ type Props = { parts: ToolPart[]; }; +function formatOutput(value: unknown): string { + return typeof value === "string" ? value : JSON.stringify(value, null, 2); +} + /** * ユーザーが ! プレフィクスで実行したシェルコマンドの結果をターミナル風に表示する。 * 通常の ToolPartView(折りたたみカード)ではなく、コマンドと出力を一体で見せる。 @@ -25,7 +29,7 @@ export function ShellResultView({ parts }: Props) { const command = (input?.command as string) ?? ""; const isRunning = state.status === "running" || state.status === "pending"; const isError = state.status === "error"; - const output = state.status === "completed" ? state.output : null; + const output = state.status === "completed" ? formatOutput(state.output) : null; const error = state.status === "error" ? state.error : null; return { command, output, error, isRunning, isError }; }); diff --git a/packages/platforms/vscode/webview/components/molecules/ShellResultView/index.ts b/webview/components/molecules/ShellResultView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/ShellResultView/index.ts rename to webview/components/molecules/ShellResultView/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/SkillPopup/SkillPopup.module.css b/webview/components/molecules/SkillPopup/SkillPopup.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/SkillPopup/SkillPopup.module.css rename to webview/components/molecules/SkillPopup/SkillPopup.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/SkillPopup/SkillPopup.tsx b/webview/components/molecules/SkillPopup/SkillPopup.tsx similarity index 95% rename from packages/platforms/vscode/webview/components/molecules/SkillPopup/SkillPopup.tsx rename to webview/components/molecules/SkillPopup/SkillPopup.tsx index 4b0efb8..5ff0f39 100644 --- a/packages/platforms/vscode/webview/components/molecules/SkillPopup/SkillPopup.tsx +++ b/webview/components/molecules/SkillPopup/SkillPopup.tsx @@ -1,4 +1,4 @@ -import type { SkillInfo } from "@opencodegui/core"; +import type { SkillInfo } from "@shared"; import { useLocale } from "../../../locales"; import { GearIcon } from "../../atoms/icons"; import { ListItem } from "../../atoms/ListItem"; diff --git a/packages/platforms/vscode/webview/components/molecules/SkillPopup/index.ts b/webview/components/molecules/SkillPopup/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/SkillPopup/index.ts rename to webview/components/molecules/SkillPopup/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/TextPartView/TextPartView.tsx b/webview/components/molecules/TextPartView/TextPartView.tsx similarity index 84% rename from packages/platforms/vscode/webview/components/molecules/TextPartView/TextPartView.tsx rename to webview/components/molecules/TextPartView/TextPartView.tsx index f0fa4f4..0b4a0ff 100644 --- a/packages/platforms/vscode/webview/components/molecules/TextPartView/TextPartView.tsx +++ b/webview/components/molecules/TextPartView/TextPartView.tsx @@ -1,39 +1,15 @@ -import type { TextPart } from "@opencodegui/core"; -import DOMPurify from "dompurify"; +import type { TextPart } from "@shared"; +import DOMPurify, { type Config as DOMPurifyConfig } from "dompurify"; import hljs from "highlight.js/lib/common"; import { Marked, type Renderer, type Tokens } from "marked"; -import { createElement, useCallback, useMemo } from "react"; -import { flushSync } from "react-dom"; -import { createRoot } from "react-dom/client"; -import { getFileIcon } from "../../../utils/file-icons"; +import { useCallback, useMemo } from "react"; import { preprocessNestedCodeBlocks } from "../../../utils/markdown"; import { postMessage } from "../../../vscode-api"; // --- SVG アイコン (VSC アイコン相当) --- const COPY_ICON = ``; const CHECK_ICON = ``; - -/** ファイルパスから拡張子に応じたアイコンの HTML 文字列を生成する(結果はキャッシュ) */ -const fileIconHtmlCache = new Map(); -function getFileIconHtml(filePath: string): string { - const fileName = filePath.split("/").pop() || filePath; - const FileTypeIcon = getFileIcon(fileName); - const key = FileTypeIcon.name; - - const cached = fileIconHtmlCache.get(key); - if (cached) return cached; - - const container = document.createElement("span"); - const root = createRoot(container); - flushSync(() => { - root.render(createElement(FileTypeIcon, { width: 12, height: 12, className: "file-chip-icon" })); - }); - const html = container.innerHTML; - root.unmount(); - - fileIconHtmlCache.set(key, html); - return html; -} +const FILE_ICON = ``; /** * コードブロック用カスタムレンダラー。 @@ -67,15 +43,14 @@ const linkRenderer: Partial = { const filePath = lineMatch ? href.slice(0, lineMatch.index) : href; const lineAttr = lineMatch ? ` data-file-line="${lineMatch[1]}"` : ""; const escapedPath = filePath.replace(/"/g, """); - const iconHtml = getFileIconHtml(filePath); - return `${iconHtml}${text}`; + return `${FILE_ICON}${text}`; } return `${text}`; }, }; // DOMPurify で SVG 要素とカスタム data 属性を許可する設定 -const PURIFY_CONFIG: DOMPurify.Config = { +const PURIFY_CONFIG: DOMPurifyConfig = { ADD_TAGS: ["svg", "path", "rect", "circle", "ellipse", "polygon", "text", "linearGradient", "stop", "defs"], ADD_ATTR: [ "viewBox", @@ -147,8 +122,7 @@ function linkifyAbsolutePaths(html: string): string { const escapedPath = filePath.replace(/"/g, """); const lineAttr = lineNum ? ` data-file-line="${lineNum}"` : ""; const display = lineNum ? `${filePath}:${lineNum}` : filePath; - const iconHtml = getFileIconHtml(filePath); - return `${iconHtml}${display}`; + return `${FILE_ICON}${display}`; }); }); } diff --git a/packages/platforms/vscode/webview/components/molecules/TextPartView/index.ts b/webview/components/molecules/TextPartView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/TextPartView/index.ts rename to webview/components/molecules/TextPartView/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/TodoHeader/TodoHeader.module.css b/webview/components/molecules/TodoHeader/TodoHeader.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/TodoHeader/TodoHeader.module.css rename to webview/components/molecules/TodoHeader/TodoHeader.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/TodoHeader/TodoHeader.tsx b/webview/components/molecules/TodoHeader/TodoHeader.tsx similarity index 97% rename from packages/platforms/vscode/webview/components/molecules/TodoHeader/TodoHeader.tsx rename to webview/components/molecules/TodoHeader/TodoHeader.tsx index 5f263cc..94da0eb 100644 --- a/packages/platforms/vscode/webview/components/molecules/TodoHeader/TodoHeader.tsx +++ b/webview/components/molecules/TodoHeader/TodoHeader.tsx @@ -1,4 +1,4 @@ -import type { TodoItem } from "@opencodegui/core"; +import type { TodoItem } from "@shared"; import { useState } from "react"; import { useLocale } from "../../../locales"; import { CheckboxIcon, ChevronRightIcon } from "../../atoms/icons"; diff --git a/packages/platforms/vscode/webview/components/molecules/TodoHeader/index.ts b/webview/components/molecules/TodoHeader/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/TodoHeader/index.ts rename to webview/components/molecules/TodoHeader/index.ts diff --git a/packages/platforms/vscode/webview/components/molecules/TodoView/TodoView.module.css b/webview/components/molecules/TodoView/TodoView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/TodoView/TodoView.module.css rename to webview/components/molecules/TodoView/TodoView.module.css diff --git a/packages/platforms/vscode/webview/components/molecules/TodoView/TodoView.tsx b/webview/components/molecules/TodoView/TodoView.tsx similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/TodoView/TodoView.tsx rename to webview/components/molecules/TodoView/TodoView.tsx diff --git a/packages/platforms/vscode/webview/components/molecules/TodoView/index.ts b/webview/components/molecules/TodoView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/molecules/TodoView/index.ts rename to webview/components/molecules/TodoView/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/ChatHeader/ChatHeader.module.css b/webview/components/organisms/ChatHeader/ChatHeader.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/ChatHeader/ChatHeader.module.css rename to webview/components/organisms/ChatHeader/ChatHeader.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/ChatHeader/ChatHeader.tsx b/webview/components/organisms/ChatHeader/ChatHeader.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/organisms/ChatHeader/ChatHeader.tsx rename to webview/components/organisms/ChatHeader/ChatHeader.tsx index 5a8a841..7d1e368 100644 --- a/packages/platforms/vscode/webview/components/organisms/ChatHeader/ChatHeader.tsx +++ b/webview/components/organisms/ChatHeader/ChatHeader.tsx @@ -1,4 +1,4 @@ -import type { ChatSession } from "@opencodegui/core"; +import type { ChatSession } from "@shared"; import { useLocale } from "../../../locales"; import { IconButton } from "../../atoms/IconButton"; import { AddIcon, BackIcon, ListIcon, RedoIcon, ShareIcon, UndoIcon, UnshareIcon } from "../../atoms/icons"; diff --git a/packages/platforms/vscode/webview/components/organisms/ChatHeader/index.ts b/webview/components/organisms/ChatHeader/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/ChatHeader/index.ts rename to webview/components/organisms/ChatHeader/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/InputArea/InputArea.module.css b/webview/components/organisms/InputArea/InputArea.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/InputArea/InputArea.module.css rename to webview/components/organisms/InputArea/InputArea.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/InputArea/InputArea.tsx b/webview/components/organisms/InputArea/InputArea.tsx similarity index 99% rename from packages/platforms/vscode/webview/components/organisms/InputArea/InputArea.tsx rename to webview/components/organisms/InputArea/InputArea.tsx index 3607753..1497cfb 100644 --- a/packages/platforms/vscode/webview/components/organisms/InputArea/InputArea.tsx +++ b/webview/components/organisms/InputArea/InputArea.tsx @@ -1,11 +1,4 @@ -import type { - AgentInfo, - ProviderInfo, - SkillInfo, - SoundEventSetting, - SoundEventType, - SoundSettings, -} from "@opencodegui/core"; +import type { AgentInfo, ProviderInfo, SkillInfo, SoundEventSetting, SoundEventType, SoundSettings } from "@shared"; import { type KeyboardEvent, useCallback, useEffect, useRef, useState } from "react"; import { useClickOutside } from "../../../hooks/useClickOutside"; import { useInputHistory } from "../../../hooks/useInputHistory"; diff --git a/packages/platforms/vscode/webview/components/organisms/InputArea/index.ts b/webview/components/organisms/InputArea/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/InputArea/index.ts rename to webview/components/organisms/InputArea/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/MessageItem/MessageItem.module.css b/webview/components/organisms/MessageItem/MessageItem.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/MessageItem/MessageItem.module.css rename to webview/components/organisms/MessageItem/MessageItem.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/MessageItem/MessageItem.tsx b/webview/components/organisms/MessageItem/MessageItem.tsx similarity index 99% rename from packages/platforms/vscode/webview/components/organisms/MessageItem/MessageItem.tsx rename to webview/components/organisms/MessageItem/MessageItem.tsx index f13f629..2d08f85 100644 --- a/packages/platforms/vscode/webview/components/organisms/MessageItem/MessageItem.tsx +++ b/webview/components/organisms/MessageItem/MessageItem.tsx @@ -1,4 +1,4 @@ -import type { QuestionRequest, ReasoningPart as ReasoningPartType, TextPart, ToolPart } from "@opencodegui/core"; +import type { QuestionRequest, ReasoningPart as ReasoningPartType, TextPart, ToolPart } from "@shared"; import { useCallback, useEffect, useRef, useState } from "react"; import type { MessageWithParts } from "../../../App"; import { useAppContext } from "../../../contexts/AppContext"; diff --git a/packages/platforms/vscode/webview/components/organisms/MessageItem/index.ts b/webview/components/organisms/MessageItem/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/MessageItem/index.ts rename to webview/components/organisms/MessageItem/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/MessagesArea/MessagesArea.module.css b/webview/components/organisms/MessagesArea/MessagesArea.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/MessagesArea/MessagesArea.module.css rename to webview/components/organisms/MessagesArea/MessagesArea.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/MessagesArea/MessagesArea.tsx b/webview/components/organisms/MessagesArea/MessagesArea.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/organisms/MessagesArea/MessagesArea.tsx rename to webview/components/organisms/MessagesArea/MessagesArea.tsx index ebbe1ad..65bfb55 100644 --- a/packages/platforms/vscode/webview/components/organisms/MessagesArea/MessagesArea.tsx +++ b/webview/components/organisms/MessagesArea/MessagesArea.tsx @@ -1,4 +1,4 @@ -import type { QuestionRequest } from "@opencodegui/core"; +import type { QuestionRequest } from "@shared"; import type { MessageWithParts } from "../../../App"; import { useAutoScroll } from "../../../hooks/useAutoScroll"; import { useLocale } from "../../../locales"; diff --git a/packages/platforms/vscode/webview/components/organisms/MessagesArea/index.ts b/webview/components/organisms/MessagesArea/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/MessagesArea/index.ts rename to webview/components/organisms/MessagesArea/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/PermissionView/PermissionView.module.css b/webview/components/organisms/PermissionView/PermissionView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/PermissionView/PermissionView.module.css rename to webview/components/organisms/PermissionView/PermissionView.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/PermissionView/PermissionView.tsx b/webview/components/organisms/PermissionView/PermissionView.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/organisms/PermissionView/PermissionView.tsx rename to webview/components/organisms/PermissionView/PermissionView.tsx index 2133433..227b8cb 100644 --- a/packages/platforms/vscode/webview/components/organisms/PermissionView/PermissionView.tsx +++ b/webview/components/organisms/PermissionView/PermissionView.tsx @@ -1,4 +1,4 @@ -import type { Permission } from "@opencodegui/core"; +import type { Permission } from "@shared"; import { useState } from "react"; import { useLocale } from "../../../locales"; import { postMessage } from "../../../vscode-api"; diff --git a/packages/platforms/vscode/webview/components/organisms/PermissionView/index.ts b/webview/components/organisms/PermissionView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/PermissionView/index.ts rename to webview/components/organisms/PermissionView/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/QuestionView/QuestionView.module.css b/webview/components/organisms/QuestionView/QuestionView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/QuestionView/QuestionView.module.css rename to webview/components/organisms/QuestionView/QuestionView.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/QuestionView/QuestionView.tsx b/webview/components/organisms/QuestionView/QuestionView.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/organisms/QuestionView/QuestionView.tsx rename to webview/components/organisms/QuestionView/QuestionView.tsx index 3eb0a63..dc1f1a0 100644 --- a/packages/platforms/vscode/webview/components/organisms/QuestionView/QuestionView.tsx +++ b/webview/components/organisms/QuestionView/QuestionView.tsx @@ -1,4 +1,4 @@ -import type { QuestionAnswer, QuestionRequest } from "@opencodegui/core"; +import type { QuestionAnswer, QuestionRequest } from "@shared"; import { useCallback, useState } from "react"; import { useLocale } from "../../../locales"; import { postMessage } from "../../../vscode-api"; diff --git a/packages/platforms/vscode/webview/components/organisms/QuestionView/index.ts b/webview/components/organisms/QuestionView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/QuestionView/index.ts rename to webview/components/organisms/QuestionView/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/SessionList/SessionList.module.css b/webview/components/organisms/SessionList/SessionList.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/SessionList/SessionList.module.css rename to webview/components/organisms/SessionList/SessionList.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/SessionList/SessionList.tsx b/webview/components/organisms/SessionList/SessionList.tsx similarity index 94% rename from packages/platforms/vscode/webview/components/organisms/SessionList/SessionList.tsx rename to webview/components/organisms/SessionList/SessionList.tsx index 0e936c8..1078b1a 100644 --- a/packages/platforms/vscode/webview/components/organisms/SessionList/SessionList.tsx +++ b/webview/components/organisms/SessionList/SessionList.tsx @@ -1,6 +1,6 @@ -import type { ChatSession } from "@opencodegui/core"; +import type { ChatSession } from "@shared"; import { useLocale } from "../../../locales"; -import type { en } from "../../../locales/en"; +import type { LocaleSchema } from "../../../locales/en"; import { IconButton } from "../../atoms/IconButton"; import { DeleteIcon, FileIcon } from "../../atoms/icons"; import styles from "./SessionList.module.css"; @@ -13,7 +13,7 @@ type Props = { onClose: () => void; }; -export function formatRelativeTime(timestamp: number, t: typeof en): string { +export function formatRelativeTime(timestamp: number, t: LocaleSchema): string { const now = Date.now(); const diff = now - timestamp; const seconds = Math.floor(diff / 1000); diff --git a/packages/platforms/vscode/webview/components/organisms/SessionList/index.ts b/webview/components/organisms/SessionList/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/SessionList/index.ts rename to webview/components/organisms/SessionList/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/SubtaskPartView/SubtaskPartView.module.css b/webview/components/organisms/SubtaskPartView/SubtaskPartView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/SubtaskPartView/SubtaskPartView.module.css rename to webview/components/organisms/SubtaskPartView/SubtaskPartView.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/SubtaskPartView/SubtaskPartView.tsx b/webview/components/organisms/SubtaskPartView/SubtaskPartView.tsx similarity index 98% rename from packages/platforms/vscode/webview/components/organisms/SubtaskPartView/SubtaskPartView.tsx rename to webview/components/organisms/SubtaskPartView/SubtaskPartView.tsx index 9672a42..67d9681 100644 --- a/packages/platforms/vscode/webview/components/organisms/SubtaskPartView/SubtaskPartView.tsx +++ b/webview/components/organisms/SubtaskPartView/SubtaskPartView.tsx @@ -1,4 +1,4 @@ -import type { ChatSession, ToolPart } from "@opencodegui/core"; +import type { ChatSession, ToolPart } from "@shared"; import { useLocale } from "../../../locales"; import { AgentIcon, ChevronRightIcon, SpinnerIcon } from "../../atoms/icons"; import styles from "./SubtaskPartView.module.css"; diff --git a/packages/platforms/vscode/webview/components/organisms/SubtaskPartView/index.ts b/webview/components/organisms/SubtaskPartView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/SubtaskPartView/index.ts rename to webview/components/organisms/SubtaskPartView/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.module.css b/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.module.css rename to webview/components/organisms/ToolConfigPanel/ToolConfigPanel.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx b/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx similarity index 99% rename from packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx rename to webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx index 25626fb..4a1244e 100644 --- a/packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx +++ b/webview/components/organisms/ToolConfigPanel/ToolConfigPanel.tsx @@ -1,4 +1,4 @@ -import type { SoundEventSetting, SoundEventType, SoundSettings } from "@opencodegui/core"; +import type { SoundEventSetting, SoundEventType, SoundSettings } from "@shared"; import type { LocaleSetting } from "../../../locales"; import { useLocale } from "../../../locales"; import { IconButton } from "../../atoms/IconButton"; diff --git a/packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/index.ts b/webview/components/organisms/ToolConfigPanel/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/ToolConfigPanel/index.ts rename to webview/components/organisms/ToolConfigPanel/index.ts diff --git a/packages/platforms/vscode/webview/components/organisms/ToolPartView/ToolPartView.module.css b/webview/components/organisms/ToolPartView/ToolPartView.module.css similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/ToolPartView/ToolPartView.module.css rename to webview/components/organisms/ToolPartView/ToolPartView.module.css diff --git a/packages/platforms/vscode/webview/components/organisms/ToolPartView/ToolPartView.tsx b/webview/components/organisms/ToolPartView/ToolPartView.tsx similarity index 97% rename from packages/platforms/vscode/webview/components/organisms/ToolPartView/ToolPartView.tsx rename to webview/components/organisms/ToolPartView/ToolPartView.tsx index 53d4709..8822d0a 100644 --- a/packages/platforms/vscode/webview/components/organisms/ToolPartView/ToolPartView.tsx +++ b/webview/components/organisms/ToolPartView/ToolPartView.tsx @@ -1,4 +1,4 @@ -import type { ToolPart } from "@opencodegui/core"; +import type { ToolPart } from "@shared"; import { useCallback, useMemo, useState } from "react"; import { useAppContext } from "../../../contexts/AppContext"; import { useLocale } from "../../../locales"; @@ -47,6 +47,10 @@ function isFileCreateInput(input: Record): boolean { return typeof input.content === "string" && getFilePath(input) !== null && typeof input.oldString !== "string"; } +function formatOutput(value: unknown): string { + return typeof value === "string" ? value : JSON.stringify(value, null, 2); +} + function ActionIcon({ category }: { category: ToolCategory }) { switch (category) { case "read": @@ -190,7 +194,7 @@ export function ToolPartView({ part }: Props) { ) : ( <> - {isCompleted && state.output &&
{state.output}
} + {isCompleted && state.output &&
{formatOutput(state.output)}
} {isError &&
{state.error}
} {isActive && input &&
{JSON.stringify(input, null, 2)}
} diff --git a/packages/platforms/vscode/webview/components/organisms/ToolPartView/index.ts b/webview/components/organisms/ToolPartView/index.ts similarity index 100% rename from packages/platforms/vscode/webview/components/organisms/ToolPartView/index.ts rename to webview/components/organisms/ToolPartView/index.ts diff --git a/packages/platforms/vscode/webview/contexts/AppContext.tsx b/webview/contexts/AppContext.tsx similarity index 99% rename from packages/platforms/vscode/webview/contexts/AppContext.tsx rename to webview/contexts/AppContext.tsx index cc30179..3803356 100644 --- a/packages/platforms/vscode/webview/contexts/AppContext.tsx +++ b/webview/contexts/AppContext.tsx @@ -8,7 +8,7 @@ import type { SoundEventType, SoundSettings, TodoItem, -} from "@opencodegui/core"; +} from "@shared"; import { createContext, useContext } from "react"; import type { MessageWithParts } from "../hooks/useMessages"; import type { LocaleSetting } from "../locales"; diff --git a/packages/platforms/vscode/webview/css-modules.d.ts b/webview/css-modules.d.ts similarity index 100% rename from packages/platforms/vscode/webview/css-modules.d.ts rename to webview/css-modules.d.ts diff --git a/packages/platforms/vscode/webview/hooks/useAutoScroll.ts b/webview/hooks/useAutoScroll.ts similarity index 100% rename from packages/platforms/vscode/webview/hooks/useAutoScroll.ts rename to webview/hooks/useAutoScroll.ts diff --git a/packages/platforms/vscode/webview/hooks/useClickOutside.ts b/webview/hooks/useClickOutside.ts similarity index 100% rename from packages/platforms/vscode/webview/hooks/useClickOutside.ts rename to webview/hooks/useClickOutside.ts diff --git a/packages/platforms/vscode/webview/hooks/useFileChanges.ts b/webview/hooks/useFileChanges.ts similarity index 92% rename from packages/platforms/vscode/webview/hooks/useFileChanges.ts rename to webview/hooks/useFileChanges.ts index b466321..da45a73 100644 --- a/packages/platforms/vscode/webview/hooks/useFileChanges.ts +++ b/webview/hooks/useFileChanges.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, FileDiff } from "@opencodegui/core"; +import type { AgentEvent, FileDiff } from "@shared"; import { useCallback, useState } from "react"; /** diff --git a/packages/platforms/vscode/webview/hooks/useInputHistory.ts b/webview/hooks/useInputHistory.ts similarity index 100% rename from packages/platforms/vscode/webview/hooks/useInputHistory.ts rename to webview/hooks/useInputHistory.ts diff --git a/packages/platforms/vscode/webview/hooks/useLocale.ts b/webview/hooks/useLocale.ts similarity index 100% rename from packages/platforms/vscode/webview/hooks/useLocale.ts rename to webview/hooks/useLocale.ts diff --git a/packages/platforms/vscode/webview/hooks/useMessages.ts b/webview/hooks/useMessages.ts similarity index 99% rename from packages/platforms/vscode/webview/hooks/useMessages.ts rename to webview/hooks/useMessages.ts index 57b1ad1..062b7fb 100644 --- a/packages/platforms/vscode/webview/hooks/useMessages.ts +++ b/webview/hooks/useMessages.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, ChatMessage, ChatSession, MessagePart } from "@opencodegui/core"; +import type { AgentEvent, ChatMessage, ChatSession, MessagePart } from "@shared"; import { type RefObject, useCallback, useRef, useState } from "react"; export type MessageWithParts = { info: ChatMessage; parts: MessagePart[] }; diff --git a/packages/platforms/vscode/webview/hooks/usePermissions.ts b/webview/hooks/usePermissions.ts similarity index 95% rename from packages/platforms/vscode/webview/hooks/usePermissions.ts rename to webview/hooks/usePermissions.ts index 3d7b05b..e4aca6e 100644 --- a/packages/platforms/vscode/webview/hooks/usePermissions.ts +++ b/webview/hooks/usePermissions.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, Permission } from "@opencodegui/core"; +import type { AgentEvent, Permission } from "@shared"; import { useCallback, useState } from "react"; /** diff --git a/packages/platforms/vscode/webview/hooks/useProviders.ts b/webview/hooks/useProviders.ts similarity index 93% rename from packages/platforms/vscode/webview/hooks/useProviders.ts rename to webview/hooks/useProviders.ts index ae62068..c74593d 100644 --- a/packages/platforms/vscode/webview/hooks/useProviders.ts +++ b/webview/hooks/useProviders.ts @@ -1,4 +1,4 @@ -import type { ProviderInfo } from "@opencodegui/core"; +import type { ProviderInfo } from "@shared"; import { useCallback, useState } from "react"; import type { AllProvidersData } from "../vscode-api"; import { postMessage } from "../vscode-api"; diff --git a/packages/platforms/vscode/webview/hooks/useQuestions.ts b/webview/hooks/useQuestions.ts similarity index 95% rename from packages/platforms/vscode/webview/hooks/useQuestions.ts rename to webview/hooks/useQuestions.ts index 32292e2..fb8b4ff 100644 --- a/packages/platforms/vscode/webview/hooks/useQuestions.ts +++ b/webview/hooks/useQuestions.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, QuestionRequest } from "@opencodegui/core"; +import type { AgentEvent, QuestionRequest } from "@shared"; import { useCallback, useState } from "react"; /** diff --git a/packages/platforms/vscode/webview/hooks/useSession.ts b/webview/hooks/useSession.ts similarity index 96% rename from packages/platforms/vscode/webview/hooks/useSession.ts rename to webview/hooks/useSession.ts index 85be60b..a2b4d31 100644 --- a/packages/platforms/vscode/webview/hooks/useSession.ts +++ b/webview/hooks/useSession.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, ChatSession } from "@opencodegui/core"; +import type { AgentEvent, ChatSession } from "@shared"; import { useCallback, useState } from "react"; import { postMessage } from "../vscode-api"; diff --git a/packages/platforms/vscode/webview/hooks/useSoundNotification.ts b/webview/hooks/useSoundNotification.ts similarity index 98% rename from packages/platforms/vscode/webview/hooks/useSoundNotification.ts rename to webview/hooks/useSoundNotification.ts index a5177d2..8af1949 100644 --- a/packages/platforms/vscode/webview/hooks/useSoundNotification.ts +++ b/webview/hooks/useSoundNotification.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, SoundEventSetting, SoundEventType, SoundSettings } from "@opencodegui/core"; +import type { AgentEvent, SoundEventSetting, SoundEventType, SoundSettings } from "@shared"; import { useCallback, useRef, useState } from "react"; import { getPersistedState, setPersistedState } from "../vscode-api"; @@ -93,7 +93,7 @@ export function useSoundNotification() { } break; } - case "permission.updated": + case "permission.asked": eventType = "permissionRequest"; break; case "question.asked": diff --git a/packages/platforms/vscode/webview/index.html b/webview/index.html similarity index 100% rename from packages/platforms/vscode/webview/index.html rename to webview/index.html diff --git a/packages/platforms/vscode/webview/locales/en.ts b/webview/locales/en.ts similarity index 100% rename from packages/platforms/vscode/webview/locales/en.ts rename to webview/locales/en.ts diff --git a/packages/platforms/vscode/webview/locales/es.ts b/webview/locales/es.ts similarity index 98% rename from packages/platforms/vscode/webview/locales/es.ts rename to webview/locales/es.ts index def2883..310303d 100644 --- a/packages/platforms/vscode/webview/locales/es.ts +++ b/webview/locales/es.ts @@ -145,8 +145,10 @@ export const es: LocaleSchema = { // Context menu sections "input.section.files": "Archivos", "input.section.agents": "Sub-agentes", + "input.section.skills": "Habilidades", "input.section.shell": "Modo Shell", // AgentMention "input.noAgents": "No hay sub-agentes disponibles", + "input.noSkills": "No hay habilidades disponibles", }; diff --git a/packages/platforms/vscode/webview/locales/index.ts b/webview/locales/index.ts similarity index 82% rename from packages/platforms/vscode/webview/locales/index.ts rename to webview/locales/index.ts index ab79986..fc983c1 100644 --- a/packages/platforms/vscode/webview/locales/index.ts +++ b/webview/locales/index.ts @@ -7,11 +7,12 @@ import { ptBr } from "./pt-br"; import { ru } from "./ru"; import { zhCn } from "./zh-cn"; import { zhTw } from "./zh-tw"; +import type { LocaleSchema } from "./en"; export type SupportedLocale = "en" | "ja" | "zh-cn" | "ko" | "zh-tw" | "es" | "pt-br" | "ru"; export type LocaleSetting = "auto" | SupportedLocale; -const locales: Record = { +const locales: Record = { en, ja, "zh-cn": zhCn, @@ -35,15 +36,15 @@ export function resolveLocale(setting: LocaleSetting, vscodeLanguage: string): S return "en"; } -export function getStrings(locale: SupportedLocale): typeof en { +export function getStrings(locale: SupportedLocale): LocaleSchema { return locales[locale] ?? locales.en; } // React Context -const LocaleContext = createContext(en); +const LocaleContext = createContext(en); export const LocaleProvider = LocaleContext.Provider; -export function useLocale(): typeof en { +export function useLocale(): LocaleSchema { return useContext(LocaleContext); } diff --git a/packages/platforms/vscode/webview/locales/ja.ts b/webview/locales/ja.ts similarity index 100% rename from packages/platforms/vscode/webview/locales/ja.ts rename to webview/locales/ja.ts diff --git a/packages/platforms/vscode/webview/locales/ko.ts b/webview/locales/ko.ts similarity index 97% rename from packages/platforms/vscode/webview/locales/ko.ts rename to webview/locales/ko.ts index c112eca..15adc53 100644 --- a/packages/platforms/vscode/webview/locales/ko.ts +++ b/webview/locales/ko.ts @@ -145,8 +145,10 @@ export const ko: LocaleSchema = { // Context menu sections "input.section.files": "파일", "input.section.agents": "서브 에이전트", + "input.section.skills": "스킬", "input.section.shell": "셸 모드", // AgentMention "input.noAgents": "사용 가능한 서브 에이전트가 없습니다", + "input.noSkills": "사용 가능한 스킬이 없습니다", }; diff --git a/packages/platforms/vscode/webview/locales/pt-br.ts b/webview/locales/pt-br.ts similarity index 98% rename from packages/platforms/vscode/webview/locales/pt-br.ts rename to webview/locales/pt-br.ts index 34d02c9..272e69a 100644 --- a/packages/platforms/vscode/webview/locales/pt-br.ts +++ b/webview/locales/pt-br.ts @@ -145,8 +145,10 @@ export const ptBr: LocaleSchema = { // Context menu sections "input.section.files": "Arquivos", "input.section.agents": "Sub-agentes", + "input.section.skills": "Habilidades", "input.section.shell": "Modo Shell", // AgentMention "input.noAgents": "Nenhum sub-agente disponível", + "input.noSkills": "Nenhuma habilidade disponível", }; diff --git a/packages/platforms/vscode/webview/locales/ru.ts b/webview/locales/ru.ts similarity index 98% rename from packages/platforms/vscode/webview/locales/ru.ts rename to webview/locales/ru.ts index c2a5f87..a5cae5e 100644 --- a/packages/platforms/vscode/webview/locales/ru.ts +++ b/webview/locales/ru.ts @@ -145,8 +145,10 @@ export const ru: LocaleSchema = { // Context menu sections "input.section.files": "Файлы", "input.section.agents": "Субагенты", + "input.section.skills": "Навыки", "input.section.shell": "Режим Shell", // AgentMention "input.noAgents": "Нет доступных субагентов", + "input.noSkills": "Нет доступных навыков", }; diff --git a/packages/platforms/vscode/webview/locales/zh-cn.ts b/webview/locales/zh-cn.ts similarity index 98% rename from packages/platforms/vscode/webview/locales/zh-cn.ts rename to webview/locales/zh-cn.ts index 1201245..aebdde4 100644 --- a/packages/platforms/vscode/webview/locales/zh-cn.ts +++ b/webview/locales/zh-cn.ts @@ -145,8 +145,10 @@ export const zhCn: LocaleSchema = { // Context menu sections "input.section.files": "文件", "input.section.agents": "子智能体", + "input.section.skills": "技能", "input.section.shell": "Shell 模式", // AgentMention "input.noAgents": "没有可用的子智能体", + "input.noSkills": "没有可用的技能", }; diff --git a/packages/platforms/vscode/webview/locales/zh-tw.ts b/webview/locales/zh-tw.ts similarity index 98% rename from packages/platforms/vscode/webview/locales/zh-tw.ts rename to webview/locales/zh-tw.ts index 218e095..d5bf186 100644 --- a/packages/platforms/vscode/webview/locales/zh-tw.ts +++ b/webview/locales/zh-tw.ts @@ -145,8 +145,10 @@ export const zhTw: LocaleSchema = { // Context menu sections "input.section.files": "檔案", "input.section.agents": "子代理", + "input.section.skills": "技能", "input.section.shell": "Shell 模式", // AgentMention "input.noAgents": "沒有可用的子代理", + "input.noSkills": "沒有可用的技能", }; diff --git a/packages/platforms/vscode/webview/main.tsx b/webview/main.tsx similarity index 100% rename from packages/platforms/vscode/webview/main.tsx rename to webview/main.tsx diff --git a/packages/platforms/vscode/webview/styles.css b/webview/styles.css similarity index 100% rename from packages/platforms/vscode/webview/styles.css rename to webview/styles.css diff --git a/webview/tsconfig.json b/webview/tsconfig.json new file mode 100644 index 0000000..490c538 --- /dev/null +++ b/webview/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.base.json", + "compilerOptions": { + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client", "vitest/globals"] + }, + "include": ["./**/*"], + "exclude": ["node_modules"] +} diff --git a/packages/platforms/vscode/webview/utils/diff.ts b/webview/utils/diff.ts similarity index 100% rename from packages/platforms/vscode/webview/utils/diff.ts rename to webview/utils/diff.ts diff --git a/packages/platforms/vscode/webview/utils/file-icons.ts b/webview/utils/file-icons.ts similarity index 97% rename from packages/platforms/vscode/webview/utils/file-icons.ts rename to webview/utils/file-icons.ts index 3bfa2aa..addd496 100644 --- a/packages/platforms/vscode/webview/utils/file-icons.ts +++ b/webview/utils/file-icons.ts @@ -228,9 +228,9 @@ export function getFileIcon(fileName: string): FC { if (exact) return exact; // 2. 拡張子マッチ(最長一致) - for (const ext of sortedExtensions) { - if (lower.endsWith(ext)) { - return extensionMap[ext]; + for (const fileExtension of sortedExtensions) { + if (lower.endsWith(fileExtension)) { + return extensionMap[fileExtension]; } } diff --git a/packages/platforms/vscode/webview/utils/markdown.ts b/webview/utils/markdown.ts similarity index 100% rename from packages/platforms/vscode/webview/utils/markdown.ts rename to webview/utils/markdown.ts diff --git a/webview/utils/todo.ts b/webview/utils/todo.ts new file mode 100644 index 0000000..a372cbc --- /dev/null +++ b/webview/utils/todo.ts @@ -0,0 +1,23 @@ +import type { TodoItem } from "@shared"; + +function normalizeTodo(item: { content: string; status?: unknown; priority?: unknown }): TodoItem { + return { + content: item.content, + status: typeof item.status === "string" ? item.status : "pending", + priority: typeof item.priority === "string" ? item.priority : "medium", + }; +} + +export function parseTodos(raw: unknown): TodoItem[] | null { + try { + const data = typeof raw === "string" ? JSON.parse(raw) : raw; + const arr = Array.isArray(data) ? data : (data?.todos ?? data?.items ?? null); + if (!Array.isArray(arr) || arr.length === 0) return null; + if (!arr.every((item: unknown) => typeof item === "object" && item !== null && "content" in item)) return null; + return arr.map((item) => normalizeTodo(item as { content: string; status?: unknown; priority?: unknown })); + } catch { + return null; + } +} + +export type { TodoItem }; diff --git a/packages/platforms/vscode/webview/utils/tool-categories.ts b/webview/utils/tool-categories.ts similarity index 100% rename from packages/platforms/vscode/webview/utils/tool-categories.ts rename to webview/utils/tool-categories.ts diff --git a/packages/platforms/vscode/webview/vscode-api.ts b/webview/vscode-api.ts similarity index 76% rename from packages/platforms/vscode/webview/vscode-api.ts rename to webview/vscode-api.ts index 34c9c86..3318d52 100644 --- a/packages/platforms/vscode/webview/vscode-api.ts +++ b/webview/vscode-api.ts @@ -2,8 +2,8 @@ * VSCode Webview API - backward-compatible re-export layer. * * This module re-exports the IBridge singleton from VscodeBridge and - * domain/protocol types from @opencodegui/core for backward compatibility. - * New code should import directly from @opencodegui/core for types and + * domain/protocol types from @shared for backward compatibility. + * New code should import directly from @shared for types and * use the bridge instance from ./bridges/VscodeBridge. */ @@ -16,9 +16,9 @@ export type { ProviderInfo, UIPersistedState, UIToHostMessage, -} from "@opencodegui/core"; +} from "@shared"; -import type { HostToUIMessage, UIToHostMessage } from "@opencodegui/core"; +import type { HostToUIMessage, UIToHostMessage } from "@shared"; /** @deprecated Use HostToUIMessage instead */ export type ExtToWebviewMessage = HostToUIMessage; @@ -26,8 +26,8 @@ export type ExtToWebviewMessage = HostToUIMessage; export type WebviewToExtMessage = UIToHostMessage; // Re-export UIPersistedState as WebviewPersistedState for backward compatibility -import type { UIPersistedState } from "@opencodegui/core"; -/** @deprecated Use UIPersistedState from @opencodegui/core instead */ +import type { UIPersistedState } from "@shared"; +/** @deprecated Use UIPersistedState from @shared instead */ export type WebviewPersistedState = UIPersistedState; // Re-export bridge functions for backward compatibility