diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6958aa0b..fa0f4dbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -131,6 +131,32 @@ jobs: working-directory: packages/vercel-sdk run: npm test + vscode-moss-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + cache-dependency-path: packages/vscode-moss/package-lock.json + - name: Install dependencies + working-directory: packages/vscode-moss + run: npm ci + - name: Typecheck + working-directory: packages/vscode-moss + run: npm run check + - name: Unit tests + working-directory: packages/vscode-moss + run: npm test + - name: Compile extension bundle + working-directory: packages/vscode-moss + run: npm run compile + - name: Package VSIX (publishability check) + working-directory: packages/vscode-moss + run: npm run package:ci + vitepress-plugin-test: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 6b5eed5c..eb746b63 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,7 @@ venv/ *CLAUDE.md *.egg-info -.moss-cache \ No newline at end of file +.moss-cache + +.docs/ +.vscode/settings.json diff --git a/README.md b/README.md index 2dc5ba0f..bba547f0 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,7 @@ const results = await client.query(name, "your query", { topK: 5 }); | [LiveKit](https://github.com/livekit/livekit) | Available | [`apps/livekit-moss-vercel/`](apps/livekit-moss-vercel/) | | [Next.js](https://nextjs.org) | Available | [`apps/next-js/`](apps/next-js/) | | [VitePress](https://vitepress.dev) | Available | [`packages/vitepress-plugin-moss/`](packages/vitepress-plugin-moss/) | +| VS Code / Cursor | Available | [`packages/vscode-moss/`](packages/vscode-moss/) (semantic search sidebar; install from VSIX) | | [Vercel AI SDK](https://sdk.vercel.ai) | Available | [`packages/vercel-sdk/`](packages/vercel-sdk/) | | [CrewAI](https://github.com/crewAIInc/crewAI) | Coming soon | — | diff --git a/ROADMAP.md b/ROADMAP.md index e744b43b..8c8161d4 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -61,7 +61,7 @@ These are well-scoped and ready for contributors. Each one has (or will have) a ### Developer Tools - [ ] **Moss CLI** — manage indexes, run queries, import data, and inspect results from the terminal (`moss index create`, `moss query`, `moss import`) -- [ ] **VS Code extension** — semantic search over your codebase directly from the editor sidebar +- [x] **VS Code extension** — semantic search over your codebase from the editor sidebar ([`packages/vscode-moss/`](packages/vscode-moss/); VSIX install, no Marketplace listing) ### Search Quality diff --git a/packages/vscode-moss/.gitignore b/packages/vscode-moss/.gitignore new file mode 100644 index 00000000..d3e15b1e --- /dev/null +++ b/packages/vscode-moss/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +out/ +*.vsix diff --git a/packages/vscode-moss/.vscode/launch.json b/packages/vscode-moss/.vscode/launch.json new file mode 100644 index 00000000..908b1f00 --- /dev/null +++ b/packages/vscode-moss/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Run Extension (open this folder as workspace)", + "type": "extensionHost", + "request": "launch", + "args": ["--extensionDevelopmentPath=${workspaceFolder}"], + "outFiles": ["${workspaceFolder}/out/**/*.js"], + "preLaunchTask": "npm: compile", + "env": { + "MOSS_PROJECT_ID": "${env:MOSS_PROJECT_ID}", + "MOSS_PROJECT_KEY": "${env:MOSS_PROJECT_KEY}" + } + } + ] +} diff --git a/packages/vscode-moss/.vscode/tasks.json b/packages/vscode-moss/.vscode/tasks.json new file mode 100644 index 00000000..ab3ba025 --- /dev/null +++ b/packages/vscode-moss/.vscode/tasks.json @@ -0,0 +1,31 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "compile", + "problemMatcher": [], + "group": { + "kind": "build", + "isDefault": true + }, + "label": "npm: compile" + }, + { + "type": "npm", + "script": "watch", + "problemMatcher": [], + "isBackground": true, + "presentation": { "reveal": "silent" }, + "group": "build", + "label": "npm: watch" + }, + { + "type": "npm", + "script": "check", + "problemMatcher": "$tsc", + "group": "build", + "label": "npm: check" + } + ] +} diff --git a/packages/vscode-moss/.vscodeignore b/packages/vscode-moss/.vscodeignore new file mode 100644 index 00000000..f5de64da --- /dev/null +++ b/packages/vscode-moss/.vscodeignore @@ -0,0 +1,10 @@ +.vscode/** +.vscode-test/** +src/** +**/*.map +**/*.ts +esbuild.config.mjs +!out/**/*.js +tsconfig.json +.gitignore +**/.env* diff --git a/packages/vscode-moss/INDEXING.md b/packages/vscode-moss/INDEXING.md new file mode 100644 index 00000000..c8c9739e --- /dev/null +++ b/packages/vscode-moss/INDEXING.md @@ -0,0 +1,120 @@ +# Indexing flow in vscode-moss + +This document describes **how workspace indexing works** inside the Moss VS Code extension: entry point, file discovery, chunking, upload, and what happens afterward. For a shorter checklist and code map, see [`WORKFLOW.md`](./WORKFLOW.md). For a Markdown-documentation–oriented pipeline (render → HTML → heading-aware chunks), see the repo’s [**moss-md-indexer** workflow](https://github.com/usemoss/moss/blob/main/packages/moss-md-indexer/INDEXER-WORKFLOW.md). + +## Entry point + +Indexing runs when the user triggers **`Moss: Index Workspace`** (command `moss.indexWorkspace`), including from the status bar item registered in `extension.ts`. The implementation lives in **`runIndexWorkspace`** in [`src/indexWorkspace.ts`](./src/indexWorkspace.ts). + + Preconditions: + +- At least one **workspace folder** must be open; otherwise the command shows an error and returns. +- **Credentials** must resolve via `resolveCredentials` / `resolveCredentialsForWorkspace`: **per-workspace credentials blob** (Secret Storage, keyed by workspace folder URI), then environment pair (`MOSS_PROJECT_ID` + `MOSS_PROJECT_KEY`), then migration from the legacy global key + `MOSS_PROJECT_ID`, then env project ID + legacy/`MOSS_PROJECT_KEY`. If missing, the user sees an error and indexing does not start. + +The work runs inside **`vscode.window.withProgress`** (notification area, **cancellable**). + +## Configuration resolution + +Before any I/O, the extension loads **`getMossConfig`** for the **first workspace folder** (`workspaceFolders[0]`). That yields: + +- **`indexName`** — from `moss.indexName` or auto-generated from the workspace name when empty. +- **`includeGlobs` / `excludeGlobs`** — merged with extra safe excludes (`EXTRA_SAFE_EXCLUDES`, e.g. `**/.svn/**`) so dangerous paths are always filtered. +- **`respectGitignore`** — when true (default), apply each folder’s root `.gitignore` after the glob scan (see Step 1 below). +- **`maxFileSizeBytes`**, **`chunkMaxLines`**, **`chunkOverlapLines`**, **`modelId`**, etc. + +Multi-root workspaces: **all roots are scanned**, but **settings** (globs, index name, chunk options) come from the **primary** folder only, consistent with the extension README. + +## Step 1 — Discover files + +**`findWorkspaceFiles`** uses `vscode.workspace.findFiles` with: + +- **Includes** — from config (default effectively `**/*` if nothing is set). +- **Excludes** — brace-combined when possible, or multiple scans per include pattern. +- **Cap** — at most **`MAX_FILE_SCAN` (80,000)** URIs; if the scan hits the cap, indexing continues with a **warning** so users can narrow `moss.includeGlob` / `moss.excludeGlob`. + +Files are **deduped** and **sorted** by `fsPath` for stable ordering. + +When **`moss.respectGitignore`** is true (default), **`filterUrisByRootGitignore`** drops URIs that match each workspace folder’s **root** `.gitignore` (via the [`ignore`](https://www.npmjs.com/package/ignore) package, same semantics as Git for that file). **Nested** `.gitignore` files are not loaded. Set **`moss.respectGitignore`** to false to index ignored paths (for example build output). + +## Step 2 — Read, filter, and chunk per file + +For each URI (with cancellation checks between files): + +1. **Workspace membership** — Skip if the file is not under any `WorkspaceFolder`. +2. **Binary extension** — Skip paths whose extension is in a fixed denylist (archives, images, binaries, fonts, etc.). +3. **Size** — Skip if `stat.size > maxFileSizeBytes`. +4. **Text** — Read bytes and decode as **UTF-8** with `fatal: true`; skip if decode fails or a `NUL` byte appears (treated as non-text). +5. **Relative path** — `asRelativePath` must be non-empty. +6. **Chunking** — **`chunkFileContent`** ([`chunking.ts`](./src/chunking.ts)) with: + - `languageId` from the file extension where supported (Markdown, JS/TS, Python, Rust, Go, Java, Ruby, PHP, C/C++, C#, etc.). + - **Structure-aware** chunks when the language is wired for Tree-sitter in [`structureChunking.ts`](./src/structureChunking.ts). + - **Line-window fallback** in [`chunkCore.ts`](./src/chunkCore.ts) when structure-aware splitting is not used. + +Each chunk becomes a Moss **`DocumentInfo`**: stable **`id`**, **`text`**, and string **`metadata`** (e.g. `path`, `startLine`, `endLine`; in multi-root, `workspaceFolderIndex` / `workspaceFolderName`). + +**Chunk budget** — The in-memory list **`allDocs`** is capped at **`MAX_MOSS_DOCUMENTS` (60,000)**. When the limit is reached, remaining files are skipped and a **warning** is shown. + +If no documents are produced (everything skipped or empty), indexing stops with a warning and **no** API upload. + +## Step 3 — Upload to Moss + +Progress shows **“Uploading index to Moss…”**. + +1. Construct **`MossClient(projectId, projectKey)`**. +2. **`deleteIndex(indexName)`** — Wrapped in **`tolerateDeleteIndex`**: “not found” style errors are treated as OK; other failures are logged as warnings but do not necessarily abort (see implementation for exact behavior). +3. **`createIndex(indexName, allDocs, { modelId })`** — Full replace of the remote index content for that name. + +On **success**: + +- **`notifySearchIndexStale()`** — Tells sidebar search to **`resetSearchSession()`** so stale `loadIndex` / client state is cleared after a full reindex. +- **`workspaceState`** is updated under **`MOSS_LAST_INDEXED_KEY`** with index name, chunk count, file count, and timestamp (drives the status bar “indexed Xm ago” text). +- **`notifyMossIndexed()`** refreshes the status bar immediately. + +On **`createIndex` failure**, the user sees an error message; workspace last-indexed state is **not** updated for this run. + +## Step 4 — Local search cache warm-up (optional) + +After upload, progress shows **“Preparing local search cache…”** and the code **`await sleep(POST_CREATE_SETTLE_MS)`** (**2.5s**) to let the service settle before downloading. + +Then **`ensureLocalIndexLoaded(client, cfg.indexName, localState)`** runs on the **same** `MossClient` used for upload. The `localState` object is **fresh** for this call only (not shared with the sidebar session). + +- If **`loadIndex`** succeeds, verbose logs note that the local query cache is warmed. +- If it **fails**, indexing still **succeeded**; search falls back to **cloud** `query` until a later successful `loadIndex` (for example from the sidebar). A non-cancellation cancel after upload may skip warm-up and show an informational message. + +Finally, an information message summarizes files indexed and chunk count. + +## Cancellation + +The user can cancel from the progress notification. The implementation checks **`token.isCancellationRequested`** after the scan, during the per-file loop, before upload, before `createIndex`, and before / after the settle delay. Partial work is not uploaded unless `createIndex` already completed. + +## Code reference summary + +| Concern | Location | +|--------|-----------| +| Command registration | `src/extension.ts` | +| Orchestration, scan, upload, warm-up | `src/indexWorkspace.ts` (`runIndexWorkspace`, `findWorkspaceFiles`, `tolerateDeleteIndex`) | +| Credentials and `moss.*` resolution | `src/config.ts` | +| Chunking | `src/chunking.ts`, `src/chunkCore.ts`, `src/structureChunking.ts` | +| Last-indexed persistence (status bar) | `src/lastIndexed.ts`, `src/mossStatusBar.ts` | +| Invalidate sidebar search after reindex | `src/mossQueryState.ts` (`notifySearchIndexStale`) | +| Local index helper | `src/mossQueryState.ts` (`ensureLocalIndexLoaded`) | + +## Diagram (high level) + +```mermaid +flowchart TD + A[Moss: Index Workspace] --> B{Open folder + credentials?} + B -->|no| Z[Show error] + B -->|yes| C[Resolve moss config for workspaceFolders0] + C --> D[findWorkspaceFiles capped at 80k] + D --> E[For each file: filter, UTF-8 read, chunkFileContent] + E --> F{Any documents?} + F -->|no| W[Warning and stop] + F -->|yes| G[deleteIndex tolerate missing] + G --> H[createIndex] + H -->|fail| E2[Error and stop] + H -->|ok| I[notifySearchIndexStale + save last indexed + status bar] + I --> J[Sleep 2.5s] + J --> K[ensureLocalIndexLoaded optional] + K --> L[Success message] +``` diff --git a/packages/vscode-moss/LICENSE b/packages/vscode-moss/LICENSE new file mode 100644 index 00000000..372ad0ad --- /dev/null +++ b/packages/vscode-moss/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2026, Moss Team +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/packages/vscode-moss/README.md b/packages/vscode-moss/README.md new file mode 100644 index 00000000..74a7eafd --- /dev/null +++ b/packages/vscode-moss/README.md @@ -0,0 +1,128 @@ +# vscode-moss + +VS Code extension for **semantic codebase search** with [Moss](https://moss.dev). This package is under active development. + +**Distribution:** install from a **`.vsix`** file only — this extension is **not** published on the VS Code Marketplace. + +## Install from VSIX + +1. Build the VSIX (or use one attached to a release): + + ```bash + cd packages/vscode-moss + npm ci + npm run check && npm run compile + npm run package + ``` + + This produces **`vscode-moss-0.0.1.vsix`** (or whatever version is in `package.json`) in the current directory. Size depends on **`@moss-dev/moss`** and its **`@moss-dev/moss-core`** (N-API) dependency shipped in `node_modules`. + +2. In VS Code or Cursor: **Extensions** → **`…`** (Views and More Actions) → **Install from VSIX…** → choose the `.vsix` file. + +3. Reload the window if prompted, then configure Moss (**Moss: Configure credentials** or settings / env) and use **Moss: Index Workspace** as usual. + +## Search your workspace + +1. Set credentials: **Moss: Configure credentials** (prompts for project ID and project key — stored together per workspace). To remove stored credentials, run **Moss: Clear credentials**. Alternatively set **`MOSS_PROJECT_ID`** and **`MOSS_PROJECT_KEY`** in the environment (credentials are not Moss settings — they live in Secret Storage or env). +2. Run **Moss: Index Workspace** (crawl + chunk + upload to Moss). +3. Open the **Moss** icon in the activity bar → **Search**, or run **Moss: Search** from the Command Palette. Type a query (search runs as you pause typing, ~320ms debounce; **Enter** or **Search** runs immediately); click a result to jump to the file and line range. + +To change Moss options without opening Search, run **Moss: Open Settings** from the Command Palette (`Ctrl+Shift+P` / `Cmd+Shift+P`). + +Indexing and search logs go to **View → Output** → channel **Moss**. Set **`moss.logVerbose`** to `true` for step-by-step indexing and search logs (default is a shorter summary). + +The **status bar** shows **Moss: not indexed** or **Moss: indexed … ago** (when a folder is open). Click it to run **Moss: Index Workspace**. + +### Privacy + +File paths and file contents you index are sent to **Moss** (cloud) for embedding and storage in your project’s index. Queries are also processed by Moss. Do not index secrets or data you are not allowed to send to a third-party service. See [moss.dev](https://moss.dev) for product terms and security expectations. + +### Settings (`moss.*`) + +| Setting | Purpose | +|--------|---------| +| Credentials | **Moss: Configure credentials** (per-workspace Secret Storage) or **`MOSS_PROJECT_ID`** / **`MOSS_PROJECT_KEY`** env — not user settings. | +| `indexName` | Index name (default derived from workspace folder name). | +| `modelId` | Embedding model for `createIndex`. | +| `includeGlob` / `excludeGlob` | Which files to crawl when indexing. | +| `respectGitignore` | When `true` (default), skip paths matched by each workspace folder’s **root** `.gitignore`. | +| `maxFileSizeBytes` | Skip larger files. | +| `topK` | Number of search hits. | +| `alpha` | Hybrid search blend: `1.0` = semantic only, `0.0` = keyword only (default `0.8`). | +| `chunkMaxLines` / `chunkOverlapLines` | Line-based chunking when indexing. | +| `logVerbose` | Extra lines in **Output → Moss**. | + +### Multi-root workspaces + +**Indexing** walks every workspace folder, and chunk metadata records which root a file came from (`workspaceFolderIndex`). **`moss.*` settings used for indexing and sidebar search are read from the first folder only** (`workspaceFolders[0]`): `indexName`, `includeGlob`, `excludeGlob`, chunk options, `topK`, `alpha`, etc. Per-folder `moss.*` overrides on other roots are ignored. Put shared Moss settings in the workspace file or the first root’s `.vscode/settings.json`, or use a single-folder workspace if you need different indexes per root. + +Changing Moss settings that affect **credentials, index name, search, or indexing** (see `extension.ts` — all `moss.*` except **`logVerbose`**) resets the sidebar search session so the next search picks up new configuration. + +## Development + +Indexing pipeline details: see [**WORKFLOW.md**](./WORKFLOW.md) in this package. + +### Automated tests + +From `packages/vscode-moss`: + +```bash +npm ci +npm run check # TypeScript +npm test # Vitest (chunking, paths, config, mossQueryState) +npm run compile +``` + +### Manual QA (before release) + +Use the **Extension Development Host** (F5 — launch config lives under **`packages/vscode-moss/.vscode`**) with real Moss credentials. + +1. **Happy path:** Open a small test folder → configure credentials → **Moss: Index Workspace** → **Moss: Search** for text you know exists → click a result → editor jumps to the right file and range. +2. **Cancel indexing:** Start **Moss: Index Workspace** on a larger tree → cancel from the notification → confirm no crash; **Output → Moss** notes cancellation. +3. **Multi-root:** Open a workspace with two folders → index → search → open a hit from each root (paths resolve via `workspaceFolderIndex`). + +### Troubleshooting (`loadIndex` / local search) + +**Moss: Index Workspace** and sidebar search use **`@moss-dev/moss`** (`createIndex`, `deleteIndex`, `loadIndex`, `query`). + +- The extension always tries **`loadIndex`** first so queries run locally when possible. +- If **`loadIndex`** fails, read the error in **Output → Moss** (Node / native addon constraints, WASM paths, or network/proxy blocking the download). Search still runs **`query`**; the SDK falls back to the **cloud** query API automatically. +- For the rest of that sidebar session, **`loadIndex` is not retried** for the same index (no repeated “downloading index” UI). Run **Moss: Index Workspace** again, change Moss settings, or close and reopen the Moss Search view to reset and retry local load. + +This extension uses **`"type": "module"`** (ESM); **`out/extension.js`** is built as ESM (`NodeNext`). + +### Credentials (F5 / dev) + +Set **`MOSS_PROJECT_ID`** and **`MOSS_PROJECT_KEY`** in the Extension Development Host environment (recommended: `env` in **`packages/vscode-moss/.vscode/launch.json`**) or use your OS environment. Project credentials are not Moss settings keys. + +### Run the extension (monorepo) + +1. Open the **`moss` repository root** in VS Code (or open **`packages/vscode-moss`** only — see below). +2. **Terminal:** `cd packages/vscode-moss && npm install && npm run compile` (or rely on the watch task). +3. **Run and Debug** → **vscode-moss: Run Extension** (defined in **`packages/vscode-moss/.vscode/launch.json`**; `extensionDevelopmentPath` points at this package). +4. In the Extension Development Host, use **Moss: Configure credentials**, **Moss: Index Workspace**, and **Moss: Search** as needed. +5. Open **Output** → channel **Moss** for logs. + +### Run the extension (this folder only) + +Open **`packages/vscode-moss`** as the workspace folder and use **Run Extension (open this folder as workspace)**. + +### Build + +- **`npm run check`** — TypeScript (`tsc --noEmit`). +- **`npm run compile`** — bundles `src/extension.ts` → `out/extension.js` with **esbuild** (Moss packages stay **external** and load from `node_modules`). +- **`npm run watch`** — esbuild watch (no typecheck loop; run **`check`** in another terminal or before commit). + +```bash +npm install +npm run check && npm run compile +npm run watch # optional during development +``` + +### Package VSIX (build only) + +Same as [Install from VSIX](#install-from-vsix) step 1. You can also run **`npm run package`** (`vsce package`), which triggers **`vscode:prepublish`** (check + compile) first. + +Bundling only shrinks **our** entry file; **`@moss-dev/moss`** and **`@moss-dev/moss-core`** remain **external** and ship inside the VSIX via `node_modules`. + +`package.json` still includes **`icon`** and **`galleryBanner`** for consistency if you ever list the extension elsewhere; they are not required for VSIX install. diff --git a/packages/vscode-moss/WORKFLOW.md b/packages/vscode-moss/WORKFLOW.md new file mode 100644 index 00000000..3c4e28e8 --- /dev/null +++ b/packages/vscode-moss/WORKFLOW.md @@ -0,0 +1,28 @@ +# vscode-moss indexing workflow + +This document describes how **vscode-moss** turns workspace files into a Moss index. For a deeper, Markdown-documentation–oriented pipeline (render → HTML → chunking with heading context), see the Moss repo’s [**moss-md-indexer** workflow](https://github.com/usemoss/moss/blob/main/packages/moss-md-indexer/INDEXER-WORKFLOW.md). + +## 1. High-level flow + +1. **Configure** — Resolve Moss credentials (per-workspace Secret Storage blob keyed by folder URI; then env pair; legacy migration). Credentials are **not** `moss.*` settings. **`moss.*` for indexing/search is resolved against the first workspace folder** (`workspaceFolders[0]`); multi-root workspaces still index all roots, but include/exclude, `indexName`, chunk options, and search `topK` / `alpha` come from that folder’s effective settings only (see README). +2. **Discover** — Scan the workspace with `vscode.workspace.findFiles`, merging the primary folder’s `moss.includeGlob`, `moss.excludeGlob`, and extra safe excludes (e.g. `.git`, `node_modules`). Caps apply (`MAX_FILE_SCAN`, `MAX_MOSS_DOCUMENTS`). +3. **Filter** — Skip binary-by-extension files, oversize files, and paths that fail UTF-8 decode. +4. **Chunk** — For each file, read text and call `chunkFileContent` (`chunking.ts`): + - **Structure-aware** — For supported `languageId` values (Markdown, JS/TS, and other Tree-sitter grammars wired in `structureChunking.ts`), emit chunks aligned to structure when possible. + - **Fallback** — Otherwise use overlapping **line windows** (`chunkFileContentLineWindowsOnly` → `chunkLineWindowSegment` in `chunkCore.ts`), with small-file and max-character rules. +5. **Metadata** — Each chunk is a Moss **`DocumentInfo`**: `id`, `text`, and string-keyed `metadata` (`path`, `startLine`, `endLine`, optional `workspaceFolderIndex` / `workspaceFolderName` for multi-root). +6. **Upload** — `deleteIndex` (ignored if missing) then `createIndex` on **`MossClient`** with the chosen `modelId`. +7. **Local warm-up** — After a short settle delay, call `loadIndex` on a fresh client so the downloaded index is ready for fast local `query` (or cloud fallback if load fails). + +## 2. Sidebar search (related) + +When the **Search** webview is created, the extension warms the same index with `loadIndex` using a **session-scoped** client and load state. If `loadIndex` fails, that index name is marked so **the session does not retry** `loadIndex` (queries use cloud fallback until the session resets). The session is cleared when the view is disposed, Moss **credentials** change, relevant **`moss.*`** settings change (index/search/indexing-related, not `logVerbose`), or a full re-index completes (`notifySearchIndexStale`). + +## 3. Code map + +| Stage | Primary files | +|--------|----------------| +| Entry / progress UI | `indexWorkspace.ts` | +| File discovery | `indexWorkspace.ts` (`findWorkspaceFiles`) | +| Chunking | `chunking.ts`, `chunkCore.ts`, `structureChunking.ts` | +| Moss API | `@moss-dev/moss` (`MossClient`) | diff --git a/packages/vscode-moss/esbuild.config.mjs b/packages/vscode-moss/esbuild.config.mjs new file mode 100644 index 00000000..6860ee20 --- /dev/null +++ b/packages/vscode-moss/esbuild.config.mjs @@ -0,0 +1,28 @@ +import * as esbuild from "esbuild"; + +const watch = process.argv.includes("--watch"); + +const buildOptions = { + entryPoints: ["src/extension.ts"], + bundle: true, + outfile: "out/extension.js", + platform: "node", + format: "esm", + target: "es2022", + sourcemap: true, + logLevel: "info", + /** Provided by the extension host; Moss packages pull large native/WASM stacks — keep resolvable from node_modules. */ + external: [ + "vscode", + "@moss-dev/moss", + "@moss-dev/moss-core", + "web-tree-sitter", + ], +}; + +if (watch) { + const ctx = await esbuild.context(buildOptions); + await ctx.watch(); +} else { + await esbuild.build(buildOptions); +} diff --git a/packages/vscode-moss/media/icon.png b/packages/vscode-moss/media/icon.png new file mode 100644 index 00000000..29d56138 Binary files /dev/null and b/packages/vscode-moss/media/icon.png differ diff --git a/packages/vscode-moss/media/moss-icon.svg b/packages/vscode-moss/media/moss-icon.svg new file mode 100644 index 00000000..94617ae4 --- /dev/null +++ b/packages/vscode-moss/media/moss-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/vscode-moss/media/searchView.js b/packages/vscode-moss/media/searchView.js new file mode 100644 index 00000000..b6ed6c8d --- /dev/null +++ b/packages/vscode-moss/media/searchView.js @@ -0,0 +1,391 @@ +/** + * Moss sidebar search webview script. + * Loaded via webview.asWebviewUri — kept out of TS template literals so regex escapes are not mangled. + */ +(function () { + const vscode = acquireVsCodeApi(); + const input = document.getElementById("query"); + const btn = document.getElementById("searchBtn"); + const meta = document.getElementById("meta"); + const indexPrep = document.getElementById("indexPrep"); + const errorBanner = document.getElementById("errorBanner"); + const emptyBlock = document.getElementById("emptyBlock"); + const emptyState = document.getElementById("emptyState"); + const resultList = document.getElementById("resultList"); + const mossSettingsLink = document.getElementById("mossSettingsLink"); + + if ( + !input || + !btn || + !meta || + !errorBanner || + !emptyBlock || + !emptyState || + !resultList || + !mossSettingsLink + ) { + return; + } + + const DEFAULT_EMPTY_HTML = + "Run Moss: Index Workspace to index your files,
then search here."; + + const prior = vscode.getState(); + if (prior && typeof prior.query === "string") { + input.value = prior.query; + } + + let selectedHitIndex = -1; + const SEARCH_DEBOUNCE_MS = 320; + let searchDebounceId = null; + + function persistQuery() { + vscode.setState({ query: input.value }); + } + + function openSettingsClick(e) { + e.preventDefault(); + vscode.postMessage({ type: "openMossSettings" }); + } + mossSettingsLink.addEventListener("click", openSettingsClick); + mossSettingsLink.addEventListener("keydown", (e) => { + if (e.key === "Enter" || e.key === " ") openSettingsClick(e); + }); + + function setLoading(loading) { + // Do not disable the query input while loading: disabling removes focus in the + // webview, so live search would force a click back into the field after each query. + btn.disabled = loading; + btn.textContent = loading ? "Searching…" : "Search"; + } + + function showError(message) { + errorBanner.textContent = message; + errorBanner.classList.add("visible"); + } + + function clearError() { + errorBanner.textContent = ""; + errorBanner.classList.remove("visible"); + } + + function escapeHtml(s) { + return String(s) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); + } + + function escapeRegExp(s) { + return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + + /** Split path into directory (with trailing slash) + basename for display. */ + function splitPath(p) { + const norm = String(p).replace(/\\/g, "/"); + const i = norm.lastIndexOf("/"); + if (i <= 0) { + return { dir: "", base: norm || "" }; + } + return { dir: norm.slice(0, i + 1), base: norm.slice(i + 1) }; + } + + /** + * Wrap query terms (length >= 2) in ; split on regex so we never inject HTML from the snippet. + */ + function highlightSnippet(text, query) { + const raw = String(text); + const q = typeof query === "string" ? query : ""; + const terms = [ + ...new Set( + q + .trim() + .toLowerCase() + .split(/\s+/) + .filter((t) => t.length >= 2) + ), + ].sort((a, b) => b.length - a.length); + if (terms.length === 0) { + return escapeHtml(raw); + } + const pattern = terms.map((t) => escapeRegExp(t)).join("|"); + if (!pattern) { + return escapeHtml(raw); + } + const re = new RegExp("(" + pattern + ")", "gi"); + const parts = raw.split(re); + return parts + .map((part, i) => { + if (i % 2 === 1) { + return '' + escapeHtml(part) + ""; + } + return escapeHtml(part); + }) + .join(""); + } + + function hitRowDomId(hitIndex) { + return "moss-hit-" + hitIndex; + } + + function getResultRows() { + return [...resultList.querySelectorAll(".result-row")]; + } + + function clearResultSelection() { + selectedHitIndex = -1; + resultList.removeAttribute("aria-activedescendant"); + getResultRows().forEach((el) => { + el.classList.remove("result-row--selected"); + el.setAttribute("aria-selected", "false"); + el.tabIndex = -1; + }); + } + + function applyResultSelection(focusSelected) { + const focus = focusSelected !== false; + const rows = getResultRows(); + rows.forEach((el, i) => { + const on = i === selectedHitIndex; + el.classList.toggle("result-row--selected", on); + el.setAttribute("aria-selected", on ? "true" : "false"); + el.tabIndex = on ? 0 : -1; + if (on && focus) { + el.focus(); + el.scrollIntoView({ block: "nearest" }); + } + }); + if (selectedHitIndex >= 0 && rows[selectedHitIndex]) { + const id = rows[selectedHitIndex].id; + if (id) resultList.setAttribute("aria-activedescendant", id); + } else { + resultList.removeAttribute("aria-activedescendant"); + } + } + + function openHitIndex(idx) { + if (typeof idx !== "number" || !Number.isInteger(idx) || idx < 0) return; + vscode.postMessage({ type: "openResult", hitIndex: idx }); + } + + function flushLiveQuery() { + if (searchDebounceId !== null) { + clearTimeout(searchDebounceId); + searchDebounceId = null; + } + const text = input.value.trim(); + clearError(); + persistQuery(); + vscode.postMessage({ type: "query", text }); + } + + function scheduleLiveQuery() { + if (searchDebounceId !== null) clearTimeout(searchDebounceId); + searchDebounceId = setTimeout(() => { + searchDebounceId = null; + flushLiveQuery(); + }, SEARCH_DEBOUNCE_MS); + } + + if (prior && typeof prior.query === "string" && prior.query.trim() !== "") { + scheduleLiveQuery(); + } + + btn.addEventListener("click", () => flushLiveQuery()); + input.addEventListener("input", () => { + clearResultSelection(); + persistQuery(); + scheduleLiveQuery(); + }); + input.addEventListener("focus", () => { + clearResultSelection(); + }); + input.addEventListener("keydown", (e) => { + if (e.key === "Enter") { + flushLiveQuery(); + return; + } + if (e.key === "ArrowDown" && resultList.style.display !== "none") { + const rows = getResultRows(); + if (rows.length === 0) return; + e.preventDefault(); + selectedHitIndex = 0; + applyResultSelection(); + } + }); + + resultList.addEventListener("keydown", (e) => { + const rows = getResultRows(); + if (rows.length === 0) return; + if (e.key === "ArrowDown") { + e.preventDefault(); + if (selectedHitIndex < rows.length - 1) { + selectedHitIndex += 1; + applyResultSelection(); + } + } else if (e.key === "ArrowUp") { + e.preventDefault(); + if (selectedHitIndex > 0) { + selectedHitIndex -= 1; + applyResultSelection(); + } else { + clearResultSelection(); + input.focus(); + } + } else if (e.key === "Enter") { + e.preventDefault(); + const idx = parseInt( + rows[selectedHitIndex]?.getAttribute("data-hit-index") || "", + 10 + ); + openHitIndex(idx); + } else if (e.key === "Escape") { + e.preventDefault(); + clearResultSelection(); + input.focus(); + } + }); + + window.addEventListener("message", (event) => { + const msg = event.data; + if (!msg || typeof msg.type !== "string") return; + + if (msg.type === "loading") { + setLoading(!!msg.loading); + if (msg.loading) { + clearResultSelection(); + meta.textContent = ""; + if (indexPrep) { + indexPrep.textContent = ""; + indexPrep.classList.remove("visible"); + } + resultList.innerHTML = ""; + resultList.removeAttribute("aria-activedescendant"); + resultList.style.display = "none"; + emptyBlock.style.display = "none"; + } + return; + } + + if (msg.type === "localIndexLoading") { + if (!indexPrep) return; + const t = typeof msg.text === "string" ? msg.text : ""; + if (t) { + indexPrep.textContent = t; + indexPrep.classList.add("visible"); + } else { + indexPrep.textContent = ""; + indexPrep.classList.remove("visible"); + } + return; + } + + if (msg.type === "clearError") { + clearError(); + return; + } + + if (msg.type === "clearResults") { + clearResultSelection(); + clearError(); + meta.textContent = ""; + if (indexPrep) { + indexPrep.textContent = ""; + indexPrep.classList.remove("visible"); + } + resultList.innerHTML = ""; + resultList.removeAttribute("aria-activedescendant"); + resultList.style.display = "none"; + emptyBlock.style.display = "block"; + emptyState.innerHTML = DEFAULT_EMPTY_HTML; + return; + } + + if (msg.type === "error") { + clearResultSelection(); + showError(msg.message || "Search failed."); + resultList.style.display = "none"; + resultList.innerHTML = ""; + resultList.removeAttribute("aria-activedescendant"); + emptyBlock.style.display = "block"; + emptyState.innerHTML = + "Could not complete this search. Fix the issue above, then try again."; + return; + } + + if (msg.type === "results") { + clearResultSelection(); + const hits = Array.isArray(msg.hits) ? msg.hits : []; + const queryText = typeof msg.query === "string" ? msg.query : ""; + if (hits.length === 0) { + emptyBlock.style.display = "block"; + emptyState.innerHTML = + "No results. Try different wording or run Moss: Index Workspace."; + resultList.style.display = "none"; + resultList.innerHTML = ""; + resultList.removeAttribute("aria-activedescendant"); + const t = typeof msg.timeMs === "number" ? msg.timeMs + " ms" : ""; + meta.textContent = t ? "0 results · " + t : "0 results"; + return; + } + + emptyBlock.style.display = "none"; + resultList.style.display = "flex"; + resultList.innerHTML = hits + .map((h) => { + const rawPath = h.path || ""; + const { dir, base } = splitPath(rawPath); + const pathHtml = + (dir + ? '' + escapeHtml(dir) + "" + : "") + + '' + + escapeHtml(base || rawPath) + + ""; + const line = escapeHtml(String(h.lineLabel ?? "")); + const score = + typeof h.score === "number" ? h.score.toFixed(3) : ""; + const snippet = highlightSnippet(h.snippet || "", queryText); + const domId = hitRowDomId(h.index); + return ( + '
  • ' + + '
    ' + + pathHtml + + "
    " + + '
    Lines ' + + line + + (score ? " · score " + escapeHtml(score) : "") + + "
    " + + '
    ' + + snippet + + "
    " + + "
  • " + ); + }) + .join(""); + + resultList.querySelectorAll(".result-row").forEach((el) => { + el.addEventListener("click", () => { + const idx = parseInt(el.getAttribute("data-hit-index"), 10); + const rows = getResultRows(); + selectedHitIndex = rows.indexOf(el); + applyResultSelection(false); + openHitIndex(idx); + }); + }); + + const t = typeof msg.timeMs === "number" ? msg.timeMs + " ms" : ""; + meta.textContent = + hits.length + + " result" + + (hits.length === 1 ? "" : "s") + + (t ? " · " + t : ""); + return; + } + }); +})(); diff --git a/packages/vscode-moss/package-lock.json b/packages/vscode-moss/package-lock.json new file mode 100644 index 00000000..d4935f63 --- /dev/null +++ b/packages/vscode-moss/package-lock.json @@ -0,0 +1,6079 @@ +{ + "name": "vscode-moss", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "vscode-moss", + "version": "0.0.1", + "license": "BSD-2-Clause", + "dependencies": { + "@moss-dev/moss": "^1.0.0", + "ignore": "^7.0.5", + "tree-sitter-c": "^0.24.1", + "tree-sitter-c-sharp": "^0.23.1", + "tree-sitter-cpp": "^0.23.4", + "tree-sitter-go": "^0.25.0", + "tree-sitter-java": "^0.23.5", + "tree-sitter-javascript": "^0.25.0", + "tree-sitter-php": "^0.24.2", + "tree-sitter-python": "^0.25.0", + "tree-sitter-ruby": "^0.23.1", + "tree-sitter-rust": "^0.24.0", + "tree-sitter-typescript": "^0.23.2", + "web-tree-sitter": "^0.26.8" + }, + "devDependencies": { + "@types/node": "^22.10.0", + "@types/vscode": "^1.85.0", + "@vscode/vsce": "3.7.1", + "esbuild": "^0.27.2", + "typescript": "^5.7.2", + "vitest": "^3.2.4", + "vscode-uri": "^3.1.0" + }, + "engines": { + "vscode": "^1.85.0" + } + }, + "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.6.3", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.6.3.tgz", + "integrity": "sha512-sTjMtUm+bJpENU/1WlRzHEsgEHppZDZ1EtNyaOODg/sQBtMxxJzGB+MOCM+T2Q5Qe1fKBrdxUmjyRxm0r7Ez9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.4.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.4.1.tgz", + "integrity": "sha512-Bl8f+w37xkXsYh7QRkAKCFGYtWMYuOVO7Lv+BxILrvGz3HbIEF22Pt0ugyj0QPOl6NLrHcnNUQ9yeew98P/5iw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.1.2.tgz", + "integrity": "sha512-DoeSJ9U5KPAIZoHsPywvfEj2MhBniQe0+FSpjLUTdWoIkI999GB5USkW6nNEHnIaLVxROHXvprWA1KzdS1VQ4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.4.1", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.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/@esbuild/aix-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "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/@moss-dev/moss": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@moss-dev/moss/-/moss-1.0.0.tgz", + "integrity": "sha512-vRsRcQQibBCVmJmN4mESiLWqoef/ugrCuE6iU7OAfmtezZyTogOeEZnUGu1s/QbDp2nHXEVgkgFj0VeXZI1CeA==", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "@moss-dev/moss-core": "0.8.7" + } + }, + "node_modules/@moss-dev/moss-core": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@moss-dev/moss-core/-/moss-core-0.8.7.tgz", + "integrity": "sha512-IxmJYNCBHhnjNj8o3H0T7XRCDVhSbwv+WmAc5KLDkAug9Ep74FK4/kpjiR32muZXTbvbktxYgB6iHL7oUMY2xw==", + "license": "Proprietary", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@moss-dev/moss-core-darwin-arm64": "0.8.7", + "@moss-dev/moss-core-linux-arm64-gnu": "0.8.7", + "@moss-dev/moss-core-linux-x64-gnu": "0.8.7", + "@moss-dev/moss-core-win32-x64-msvc": "0.8.7" + } + }, + "node_modules/@moss-dev/moss-core-darwin-arm64": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@moss-dev/moss-core-darwin-arm64/-/moss-core-darwin-arm64-0.8.7.tgz", + "integrity": "sha512-SxRD5vV5HSezJRr1GcIxQKOyX/nJ6RCgQYSDZTPsYbo49M0bRdAATKUpGIW5xHC7YZsZXZY8OiUVcw5lBQW0Lg==", + "cpu": [ + "arm64" + ], + "license": "Proprietary", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@moss-dev/moss-core-linux-arm64-gnu": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@moss-dev/moss-core-linux-arm64-gnu/-/moss-core-linux-arm64-gnu-0.8.7.tgz", + "integrity": "sha512-uRs/V6f0qvbStGSGNd/10cWJQKMPEumpQCAcjdRODiLbh5N+S6TIt2/bUHfc5uMxPFC9Bld7URglNmtfNXCKNA==", + "cpu": [ + "arm64" + ], + "license": "Proprietary", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@moss-dev/moss-core-linux-x64-gnu": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@moss-dev/moss-core-linux-x64-gnu/-/moss-core-linux-x64-gnu-0.8.7.tgz", + "integrity": "sha512-HgQgYN3ivLVNGJbQIBp6N2i+96y7cN/40sqzL0jqh2TzTziygoiSlwIkIqkkDZJ8DnSwJAMMQ9o2l1zPoMskCQ==", + "cpu": [ + "x64" + ], + "license": "Proprietary", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@moss-dev/moss-core-win32-x64-msvc": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/@moss-dev/moss-core-win32-x64-msvc/-/moss-core-win32-x64-msvc-0.8.7.tgz", + "integrity": "sha512-P49hUAuOXpMP1gVM+SMf0DyvXUU8OHLpppUsz7CRWJ4GkNY6JCnC3tHD1dEJQSnHMx9zOnS0hoAV6qzuhWuIrg==", + "cpu": [ + "x64" + ], + "license": "Proprietary", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20" + } + }, + "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/@rollup/rollup-android-arm-eabi": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "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/@textlint/ast-node-types": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.5.2.tgz", + "integrity": "sha512-fCaOxoup5LIyBEo7R1oYWE7V4bSX0KQeHh66twon9e9usaLE3ijgF8QjYsR6joCssdeCHVd0wHm7ppsEyTr6vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.5.2.tgz", + "integrity": "sha512-jAw7jWM8+wU9cG6Uu31jGyD1B+PAVePCvnPKC/oov+2iBPKk3ao30zc/Itmi7FvXo4oPaL9PmzPPQhyniPVgVg==", + "dev": true, + "license": "MIT", + "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" + } + }, + "node_modules/@textlint/linter-formatter/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/@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.5.2", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.5.2.tgz", + "integrity": "sha512-mg6rMQ3+YjwiXCYoQXbyVfDucpTa1q5mhspd/9qHBxUq4uY6W8GU42rmT3GW0V1yOfQ9z/iRrgPtkp71s8JzXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.5.2.tgz", + "integrity": "sha512-YEITdjRiJaQrGLUWxWXl4TEg+d2C7+TNNjbGPHPH7V7CCnXm+S9GTjGAL7Q2WSGJyFEKt88Jvx6XdJffRv4HEA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.5.2", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.5.2.tgz", + "integrity": "sha512-sJOrlVLLXp4/EZtiWKWq9y2fWyZlI8GP+24rnU5avtPWBIMm/1w97yzKrAqYF8czx2MqR391z5akhnfhj2f/AQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.5.2" + } + }, + "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/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.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.17.tgz", + "integrity": "sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==", + "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/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/vscode": { + "version": "1.110.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.110.0.tgz", + "integrity": "sha512-AGuxUEpU4F4mfuQjxPPaQVyuOMhs+VT/xRok1jiHVBubHK7lBRvCuOMZG0LKUwxncrPorJ5qq/uil3IdZBd5lA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.4.tgz", + "integrity": "sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ==", + "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/@vitest/expect": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.4.tgz", + "integrity": "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.4.tgz", + "integrity": "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.2.4", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.4.tgz", + "integrity": "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.4.tgz", + "integrity": "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.2.4", + "pathe": "^2.0.3", + "strip-literal": "^3.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.4.tgz", + "integrity": "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.4.tgz", + "integrity": "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^4.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.4.tgz", + "integrity": "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.2.4", + "loupe": "^3.1.4", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vscode/vsce": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.1.tgz", + "integrity": "sha512-OTm2XdMt2YkpSn2Nx7z2EJtSuhRHsTPYsSK59hr3v8jRArK+2UEoju4Jumn1CmpgoBLGI6ReHLJ/czYltNUW3g==", + "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": "^2.3.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/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.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "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": "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/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/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/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.13", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz", + "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==", + "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/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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": "5.3.3", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", + "integrity": "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "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/check-error": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.3.tgz", + "integrity": "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "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/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/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "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-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/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/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-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/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", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "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/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": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "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.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" + } + }, + "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.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "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/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "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.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "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.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "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.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "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/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==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "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-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==", + "dev": true, + "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/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.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "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/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/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/loupe": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.2.1.tgz", + "integrity": "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==", + "dev": true, + "license": "MIT" + }, + "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/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/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/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/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.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "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.89.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", + "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "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-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "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/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/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==", + "dev": true, + "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.2.7", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.7.tgz", + "integrity": "sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==", + "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/pathval": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.1.tgz", + "integrity": "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "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.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "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/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.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.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "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/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/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/rollup": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", + "fsevents": "~2.3.2" + } + }, + "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/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/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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==", + "dev": true, + "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==", + "dev": true, + "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.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "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": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "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/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/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-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/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/strip-literal/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "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/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/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/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-fs/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/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": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "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/tinypool": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.1.1.tgz", + "integrity": "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz", + "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "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/tree-sitter-c": { + "version": "0.24.1", + "resolved": "https://registry.npmjs.org/tree-sitter-c/-/tree-sitter-c-0.24.1.tgz", + "integrity": "sha512-lkYwWN3SRecpvaeqmFKkuPNR3ZbtnvHU+4XAEEkJdrp3JfSp2pBrhXOtvfsENUneye76g889Y0ddF2DM0gEDpA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.1", + "node-gyp-build": "^4.8.4" + }, + "peerDependencies": { + "tree-sitter": "^0.22.4" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-c-sharp": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/tree-sitter-c-sharp/-/tree-sitter-c-sharp-0.23.1.tgz", + "integrity": "sha512-9zZ4FlcTRWWfRf6f4PgGhG8saPls6qOOt75tDfX7un9vQZJmARjPrAC6yBNCX2T/VKcCjIDbgq0evFaB3iGhQw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-c-sharp/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-c/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-cpp": { + "version": "0.23.4", + "resolved": "https://registry.npmjs.org/tree-sitter-cpp/-/tree-sitter-cpp-0.23.4.tgz", + "integrity": "sha512-qR5qUDyhZ5jJ6V8/umiBxokRbe89bCGmcq/dk94wI4kN86qfdV8k0GHIUEKaqWgcu42wKal5E97LKpLeVW8sKw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.1", + "node-gyp-build": "^4.8.2", + "tree-sitter-c": "^0.23.1" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-cpp/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-cpp/node_modules/tree-sitter-c": { + "version": "0.23.6", + "resolved": "https://registry.npmjs.org/tree-sitter-c/-/tree-sitter-c-0.23.6.tgz", + "integrity": "sha512-0dxXKznVyUA0s6PjNolJNs2yF87O5aL538A/eR6njA5oqX3C3vH4vnx3QdOKwuUdpKEcFdHuiDpRKLLCA/tjvQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.0", + "node-gyp-build": "^4.8.4" + }, + "peerDependencies": { + "tree-sitter": "^0.22.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-go": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/tree-sitter-go/-/tree-sitter-go-0.25.0.tgz", + "integrity": "sha512-APBc/Dq3xz/e35Xpkhb1blu5UgW+2E3RyGWawZSCNcbGwa7jhSQPS8KsUupuzBla8PCo8+lz9W/JDJjmfRa2tw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.1", + "node-gyp-build": "^4.8.4" + }, + "peerDependencies": { + "tree-sitter": "^0.25.0" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-go/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-java": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/tree-sitter-java/-/tree-sitter-java-0.23.5.tgz", + "integrity": "sha512-Yju7oQ0Xx7GcUT01mUglPP+bYfvqjNCGdxqigTnew9nLGoII42PNVP3bHrYeMxswiCRM0yubWmN5qk+zsg0zMA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-java/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-javascript": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.25.0.tgz", + "integrity": "sha512-1fCbmzAskZkxcZzN41sFZ2br2iqTYP3tKls1b/HKGNPQUVOpsUxpmGxdN/wMqAk3jYZnYBR1dd/y/0avMeU7dw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.3.1", + "node-gyp-build": "^4.8.4" + }, + "peerDependencies": { + "tree-sitter": "^0.25.0" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-javascript/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-php": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/tree-sitter-php/-/tree-sitter-php-0.24.2.tgz", + "integrity": "sha512-zwgAePc/HozNaWOOfwRAA+3p8yhuehRw8Fb7vn5qd2XjiIc93uJPryDTMYTSjBRjVIUg/KY6pM3rRzs8dSwKfw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2" + }, + "peerDependencies": { + "tree-sitter": "^0.22.4" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-php/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-python": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/tree-sitter-python/-/tree-sitter-python-0.25.0.tgz", + "integrity": "sha512-eCmJx6zQa35GxaCtQD+wXHOhYqBxEL+bp71W/s3fcDMu06MrtzkVXR437dRrCrbrDbyLuUDJpAgycs7ncngLXw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.5.0", + "node-gyp-build": "^4.8.4" + }, + "peerDependencies": { + "tree-sitter": "^0.25.0" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-python/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-ruby": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/tree-sitter-ruby/-/tree-sitter-ruby-0.23.1.tgz", + "integrity": "sha512-d9/RXgWjR6HanN7wTYhS5bpBQLz1VkH048Vm3CodPGyJVnamXMGb8oEhDypVCBq4QnHui9sTXuJBBP3WtCw5RA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-ruby/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-rust": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/tree-sitter-rust/-/tree-sitter-rust-0.24.0.tgz", + "integrity": "sha512-NWemUDf629Tfc90Y0Z55zuwPCAHkLxWnMf2RznYu4iBkkrQl2o/CHGB7Cr52TyN5F1DAx8FmUnDtCy9iUkXZEQ==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.4" + }, + "peerDependencies": { + "tree-sitter": "^0.22.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-rust/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-typescript": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/tree-sitter-typescript/-/tree-sitter-typescript-0.23.2.tgz", + "integrity": "sha512-e04JUUKxTT53/x3Uq1zIL45DoYKVfHH4CZqwgZhPg5qYROl5nQjV+85ruFzFGZxu+QeFVbRTPDRnqL9UbU4VeA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2", + "tree-sitter-javascript": "^0.23.1" + }, + "peerDependencies": { + "tree-sitter": "^0.21.0" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "node_modules/tree-sitter-typescript/node_modules/node-addon-api": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz", + "integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==", + "license": "MIT", + "engines": { + "node": "^18 || ^20 || >= 21" + } + }, + "node_modules/tree-sitter-typescript/node_modules/tree-sitter-javascript": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/tree-sitter-javascript/-/tree-sitter-javascript-0.23.1.tgz", + "integrity": "sha512-/bnhbrTD9frUYHQTiYnPcxyHORIw157ERBa6dqzaKxvR/x3PC4Yzd+D1pZIMS6zNg2v3a8BZ0oK7jHqsQo9fWA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^8.2.2", + "node-gyp-build": "^4.8.2" + }, + "peerDependencies": { + "tree-sitter": "^0.21.1" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + } + }, + "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": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "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.24.7", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.7.tgz", + "integrity": "sha512-H/nlJ/h0ggGC+uRL3ovD+G0i4bqhvsDOpbDv7At5eFLlj2b41L8QliGbnl2H7SnDiYhENphh1tQFJZf+MyfLsQ==", + "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/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "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": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "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", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.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 + }, + "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 + } + } + }, + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/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/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": "3.2.4", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.4.tgz", + "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "^5.2.2", + "@vitest/expect": "3.2.4", + "@vitest/mocker": "3.2.4", + "@vitest/pretty-format": "^3.2.4", + "@vitest/runner": "3.2.4", + "@vitest/snapshot": "3.2.4", + "@vitest/spy": "3.2.4", + "@vitest/utils": "3.2.4", + "chai": "^5.2.0", + "debug": "^4.4.1", + "expect-type": "^1.2.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "std-env": "^3.9.0", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.14", + "tinypool": "^1.1.1", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", + "vite-node": "3.2.4", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.2.4", + "@vitest/ui": "3.2.4", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "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/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-tree-sitter": { + "version": "0.26.8", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.8.tgz", + "integrity": "sha512-4sUwi7ZyOrIk5KLgYLkc2A/F0LFMQnBhfb+2Cdl7ik4ePJ6JD+fk4ofI2sA5eGawBKBaK4Vntt7Ww5KcEsay4A==", + "license": "MIT" + }, + "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/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "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/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/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/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "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/packages/vscode-moss/package.json b/packages/vscode-moss/package.json new file mode 100644 index 00000000..be61e350 --- /dev/null +++ b/packages/vscode-moss/package.json @@ -0,0 +1,196 @@ +{ + "name": "vscode-moss", + "displayName": "Moss", + "description": "Semantic codebase search powered by Moss — index your workspace and search from the sidebar.", + "version": "0.0.1", + "publisher": "moss-dev", + "license": "BSD-2-Clause", + "repository": { + "type": "git", + "url": "https://github.com/usemoss/moss.git", + "directory": "packages/vscode-moss" + }, + "engines": { + "vscode": "^1.85.0" + }, + "categories": [ + "Other" + ], + "icon": "media/icon.png", + "galleryBanner": { + "color": "#2B1843", + "theme": "dark" + }, + "type": "module", + "main": "./out/extension.js", + "activationEvents": [ + "onView:moss.searchView", + "onCommand:moss.indexWorkspace", + "onCommand:moss.search", + "onCommand:moss.configureCredentials", + "onCommand:moss.clearCredentials", + "onCommand:moss.openSettings" + ], + "contributes": { + "commands": [ + { + "command": "moss.indexWorkspace", + "title": "Moss: Index Workspace" + }, + { + "command": "moss.search", + "title": "Moss: Search" + }, + { + "command": "moss.configureCredentials", + "title": "Moss: Configure credentials" + }, + { + "command": "moss.clearCredentials", + "title": "Moss: Clear credentials" + }, + { + "command": "moss.openSettings", + "title": "Moss: Open Settings" + } + ], + "viewsContainers": { + "activitybar": [ + { + "id": "mossContainer", + "title": "Moss", + "icon": "media/moss-icon.svg" + } + ] + }, + "views": { + "mossContainer": [ + { + "type": "webview", + "id": "moss.searchView", + "name": "Search" + } + ] + }, + "configuration": { + "title": "Moss", + "properties": { + "moss.indexName": { + "type": "string", + "default": "", + "description": "Moss index name for this workspace. Leave empty to auto-generate from the workspace name.", + "scope": "resource" + }, + "moss.modelId": { + "type": "string", + "default": "moss-minilm", + "description": "Embedding model ID used when creating a Moss index." + }, + "moss.includeGlob": { + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + }, + "default": "**/*", + "description": "Glob pattern(s) for files to include when indexing the workspace.", + "scope": "resource" + }, + "moss.excludeGlob": { + "type": [ + "string", + "array" + ], + "items": { + "type": "string" + }, + "default": [ + "**/node_modules/**", + "**/.git/**", + "**/dist/**", + "**/out/**", + "**/.next/**", + "**/build/**" + ], + "description": "Glob pattern(s) for files to exclude when indexing (merged with built-in defaults).", + "scope": "resource" + }, + "moss.respectGitignore": { + "type": "boolean", + "default": true, + "description": "Exclude files that match each workspace folder's root `.gitignore` when discovering files for indexing. Set false to include ignored paths (for example generated output). Nested `.gitignore` files below the root file are not applied.", + "scope": "resource" + }, + "moss.maxFileSizeBytes": { + "type": "number", + "default": 1048576, + "description": "Maximum file size in bytes to index (default 1 MB). Larger files are skipped." + }, + "moss.topK": { + "type": "number", + "default": 10, + "description": "Number of results to return for each search query." + }, + "moss.alpha": { + "type": "number", + "default": 0.8, + "minimum": 0, + "maximum": 1, + "description": "Hybrid search blend: 1.0 = semantic (embedding) only, 0.0 = keyword only; values in between mix both. Default 0.8 is semantic-heavy." + }, + "moss.chunkMaxLines": { + "type": "number", + "default": 100, + "description": "Maximum lines per indexed chunk (each Moss document). Structure-aware indexing splits large logical spans into overlapping windows of at most this size; plain text and unsupported languages use sliding line windows only." + }, + "moss.chunkOverlapLines": { + "type": "number", + "default": 12, + "description": "Lines of overlap between consecutive windows when a span is subdivided (structure-aware split or full-file line-window fallback)." + }, + "moss.logVerbose": { + "type": "boolean", + "default": false, + "description": "When true, the Moss output channel includes extra detail for indexing and search (default is a short summary)." + } + } + } + }, + "scripts": { + "check": "tsc --noEmit -p ./", + "compile": "node esbuild.config.mjs", + "watch": "node esbuild.config.mjs --watch", + "test": "vitest run", + "test:watch": "vitest", + "package": "vsce package", + "package:ci": "vsce package --out /tmp/vscode-moss-ci.vsix", + "vscode:prepublish": "npm run check && npm run compile" + }, + "dependencies": { + "@moss-dev/moss": "^1.0.0", + "ignore": "^7.0.5", + "tree-sitter-c": "^0.24.1", + "tree-sitter-c-sharp": "^0.23.1", + "tree-sitter-cpp": "^0.23.4", + "tree-sitter-go": "^0.25.0", + "tree-sitter-java": "^0.23.5", + "tree-sitter-javascript": "^0.25.0", + "tree-sitter-php": "^0.24.2", + "tree-sitter-python": "^0.25.0", + "tree-sitter-ruby": "^0.23.1", + "tree-sitter-rust": "^0.24.0", + "tree-sitter-typescript": "^0.23.2", + "web-tree-sitter": "^0.26.8" + }, + "devDependencies": { + "@types/node": "^22.10.0", + "@types/vscode": "^1.85.0", + "@vscode/vsce": "3.7.1", + "esbuild": "^0.27.2", + "typescript": "^5.7.2", + "vitest": "^3.2.4", + "vscode-uri": "^3.1.0" + } +} diff --git a/packages/vscode-moss/scripts/probe-grammar.mjs b/packages/vscode-moss/scripts/probe-grammar.mjs new file mode 100644 index 00000000..d6028f3c --- /dev/null +++ b/packages/vscode-moss/scripts/probe-grammar.mjs @@ -0,0 +1,20 @@ +import * as TS from "web-tree-sitter"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = path.join(path.dirname(fileURLToPath(import.meta.url)), ".."); +const nm = path.join(root, "node_modules"); +await TS.Parser.init({ + locateFile: (b) => path.join(nm, "web-tree-sitter", b), +}); +const c = await TS.Language.load( + path.join(nm, "tree-sitter-c", "tree-sitter-c.wasm") +); +const p = new TS.Parser(); +p.setLanguage(c); +const src = "#include \n#include \nint main(){return 0;}\n"; +const t = p.parse(src); +console.log(t.rootNode.type); +for (const ch of t.rootNode.namedChildren) console.log(" ", ch.type); +p.delete(); +t.delete(); diff --git a/packages/vscode-moss/src/chunkCore.ts b/packages/vscode-moss/src/chunkCore.ts new file mode 100644 index 00000000..cde7b906 --- /dev/null +++ b/packages/vscode-moss/src/chunkCore.ts @@ -0,0 +1,128 @@ +import type { DocumentInfo } from "@moss-dev/moss"; +import type { MossMetadata } from "./types.js"; + +/** Upper bound on embedded text length per chunk (shared with line-window chunking entry). */ +export const DEFAULT_MAX_CHARS = 12_000; + +export interface ChunkOptions { + chunkMaxLines: number; + chunkOverlapLines: number; + /** Upper bound on embedded text length per chunk (Phase 0: ~12k). */ + maxCharsPerChunk?: number; + /** If total lines ≤ this, emit a single chunk for the whole file. */ + smallFileMaxLines?: number; + workspaceFolderIndex?: number; + workspaceFolderName?: string; + /** + * Uniquifies doc ids across workspace roots (e.g. multi-root). Omitted for single-folder workspaces. + */ + chunkIdNamespace?: string; +} + +export function normalizeRelativePath(relativePath: string): string { + return relativePath.replace(/\\/g, "/"); +} + +function joinLines( + lines: string[], + startIdx: number, + endIdxExclusive: number +): string { + return lines.slice(startIdx, endIdxExclusive).join("\n"); +} + +export function truncateToMaxChars( + lines: string[], + startIdx: number, + endIdxExclusive: number, + maxChars: number +): { text: string; endIdxExclusive: number } { + let end = endIdxExclusive; + let text = joinLines(lines, startIdx, end); + while (text.length > maxChars && end > startIdx + 1) { + end -= 1; + text = joinLines(lines, startIdx, end); + } + if (text.length > maxChars && end === startIdx + 1) { + const line = lines[startIdx] ?? ""; + text = line.slice(0, maxChars); + } + return { text, endIdxExclusive: end }; +} + +export function buildMetadata( + pathNorm: string, + startLine1: number, + endLine1: number, + options: ChunkOptions +): MossMetadata { + const meta: MossMetadata = { + path: pathNorm, + startLine: String(startLine1), + endLine: String(endLine1), + }; + if (options.workspaceFolderIndex !== undefined) { + meta.workspaceFolderIndex = String(options.workspaceFolderIndex); + } + if (options.workspaceFolderName !== undefined) { + meta.workspaceFolderName = options.workspaceFolderName; + } + return meta; +} + +/** + * Line-window chunking for lines [segmentStartLine1, segmentEndLine1] inclusive (1-based). + */ +export function chunkLineWindowSegment( + pathNorm: string, + lines: string[], + segmentStartLine1: number, + segmentEndLine1: number, + options: ChunkOptions, + idPrefix: string, + metaForRange: (startLine1: number, endLine1: number) => MossMetadata +): DocumentInfo[] { + const total = lines.length; + const segStart = Math.max(1, Math.min(segmentStartLine1, total || 1)); + const segEnd = Math.max(segStart, Math.min(segmentEndLine1, total || 1)); + const segLen = segEnd - segStart + 1; + + const maxLines = Math.max(1, options.chunkMaxLines); + let overlap = Math.max(0, options.chunkOverlapLines); + if (overlap >= maxLines) { + overlap = Math.max(0, maxLines - 1); + } + const maxChars = options.maxCharsPerChunk ?? DEFAULT_MAX_CHARS; + + const docs: DocumentInfo[] = []; + + if (segLen <= 0) return docs; + + let startLine = segStart; + while (startLine <= segEnd) { + const startIdx = startLine - 1; + let endLine = Math.min(segEnd, startLine + maxLines - 1); + let endIdxExclusive = endLine; + + const { text: body, endIdxExclusive: trimmedEnd } = truncateToMaxChars( + lines, + startIdx, + endIdxExclusive, + maxChars + ); + endIdxExclusive = trimmedEnd; + endLine = endIdxExclusive; + + docs.push({ + id: `${idPrefix}${pathNorm}:${startLine}-${endLine}`, + text: body, + metadata: metaForRange(startLine, endLine), + }); + + if (endLine >= segEnd) break; + const nextStart = Math.max(startLine + 1, endLine - overlap + 1); + startLine = nextStart; + } + + return docs; +} diff --git a/packages/vscode-moss/src/chunking.ts b/packages/vscode-moss/src/chunking.ts new file mode 100644 index 00000000..75e1fb9e --- /dev/null +++ b/packages/vscode-moss/src/chunking.ts @@ -0,0 +1,105 @@ +import { + supportsStructureChunking, + tryStructureAwareChunk, +} from "./structureChunking.js"; +import { + buildMetadata, + chunkLineWindowSegment, + DEFAULT_MAX_CHARS, + normalizeRelativePath, + truncateToMaxChars, +} from "./chunkCore.js"; + +import type { DocumentInfo } from "@moss-dev/moss"; +import type { ChunkOptions } from "./chunkCore.js"; + +export type { ChunkOptions }; + +const DEFAULT_SMALL_FILE_LINES = 50; + +/** + * Full-file line-window chunking (fallback when structure-aware path does not apply). + */ +export function chunkFileContentLineWindowsOnly( + relativePath: string, + text: string, + options: ChunkOptions +): DocumentInfo[] { + const pathNorm = normalizeRelativePath(relativePath); + const lines = text.split(/\r?\n/); + const total = lines.length; + + const maxChars = options.maxCharsPerChunk ?? DEFAULT_MAX_CHARS; + const smallMax = options.smallFileMaxLines ?? DEFAULT_SMALL_FILE_LINES; + + const idPrefix = + options.chunkIdNamespace !== undefined && options.chunkIdNamespace !== "" + ? `${options.chunkIdNamespace}:` + : ""; + + if (total === 0) { + return [ + { + id: `${idPrefix}${pathNorm}:1-1`, + text: "", + metadata: buildMetadata(pathNorm, 1, 1, options), + }, + ]; + } + + if (total <= smallMax) { + const { text: body, endIdxExclusive } = truncateToMaxChars( + lines, + 0, + total, + maxChars + ); + const endLine = endIdxExclusive; + return [ + { + id: `${idPrefix}${pathNorm}:1-${endLine}`, + text: body, + metadata: buildMetadata(pathNorm, 1, endLine, options), + }, + ]; + } + + return chunkLineWindowSegment( + pathNorm, + lines, + 1, + total, + options, + idPrefix, + (sl, el) => buildMetadata(pathNorm, sl, el, options) + ); +} + +/** + * Split file text into Moss documents. Uses Markdown / JS / TS structure when applicable, + * otherwise overlapping line windows via {@link chunkFileContentLineWindowsOnly}. + */ +export async function chunkFileContent( + relativePath: string, + text: string, + options: ChunkOptions, + languageId?: string +): Promise { + const lines = text.split(/\r?\n/); + const total = lines.length; + + if (total > 0 && supportsStructureChunking(languageId)) { + const structured = await tryStructureAwareChunk( + relativePath, + text, + lines, + options, + languageId + ); + if (structured && structured.length > 0) { + return structured; + } + } + + return chunkFileContentLineWindowsOnly(relativePath, text, options); +} diff --git a/packages/vscode-moss/src/config.ts b/packages/vscode-moss/src/config.ts new file mode 100644 index 00000000..56afae72 --- /dev/null +++ b/packages/vscode-moss/src/config.ts @@ -0,0 +1,304 @@ +import { createHash } from "node:crypto"; +import * as vscode from "vscode"; + +/** Legacy global SecretStorage key for project key only (pre–workspace blobs). Used for migration + fallback. */ +export const MOSS_LEGACY_GLOBAL_PROJECT_KEY = "moss.projectKey"; + +/** @deprecated Use {@link MOSS_LEGACY_GLOBAL_PROJECT_KEY}. */ +export const MOSS_SECRET_KEY_PROJECT_KEY = MOSS_LEGACY_GLOBAL_PROJECT_KEY; + +const MOSS_CREDENTIALS_SECRET_PREFIX = "moss.credentials.v1"; + +/** When true, Moss output includes extra indexing / spike / search detail (Phase 8). */ +export function getMossLogVerbose(): boolean { + return vscode.workspace.getConfiguration("moss").get("logVerbose") === true; +} + +/** Default hybrid-search blend (semantic-heavy), aligned with Moss SDK defaults. */ +export const DEFAULT_QUERY_ALPHA = 0.8; + +const DEFAULT_MAX_FILE_SIZE_BYTES = 1_048_576; +const MAX_FILE_SIZE_BYTES_CAP = 50 * 1024 * 1024; +const DEFAULT_TOP_K = 10; +const TOP_K_CAP = 100; +const DEFAULT_CHUNK_MAX_LINES = 100; +const CHUNK_MAX_LINES_CAP = 10_000; +const DEFAULT_CHUNK_OVERLAP_LINES = 12; +const CHUNK_OVERLAP_CAP = 10_000; + +function clampPositiveInt( + value: unknown, + fallback: number, + max: number +): number { + const n = typeof value === "number" ? value : Number(value); + if (!Number.isFinite(n)) return fallback; + const i = Math.trunc(n); + if (i < 1) return fallback; + return Math.min(i, max); +} + +function clampNonNegativeInt( + value: unknown, + fallback: number, + max: number +): number { + const n = typeof value === "number" ? value : Number(value); + if (!Number.isFinite(n)) return fallback; + const i = Math.trunc(n); + if (i < 0) return fallback; + return Math.min(i, max); +} + +function clampMaxFileSizeBytes(value: unknown): number { + const n = typeof value === "number" ? value : Number(value); + if (!Number.isFinite(n)) return DEFAULT_MAX_FILE_SIZE_BYTES; + const i = Math.trunc(n); + if (i < 1024) return DEFAULT_MAX_FILE_SIZE_BYTES; + return Math.min(i, MAX_FILE_SIZE_BYTES_CAP); +} + +export interface ResolvedConfig { + projectId: string | undefined; + projectKey: string | undefined; + indexName: string; + modelId: string; + includeGlobs: string[]; + excludeGlobs: string[]; + maxFileSizeBytes: number; + topK: number; + /** Hybrid search: 1.0 = semantic only, 0.0 = keyword only; clamped to [0, 1]. */ + alpha: number; + chunkMaxLines: number; + chunkOverlapLines: number; + /** When true, paths matching the workspace folder root `.gitignore` are excluded from indexing. */ + respectGitignore: boolean; + workspaceFolder: vscode.WorkspaceFolder; +} + +/** Parse `moss.alpha`: finite number in [0, 1], else default. */ +export function resolveQueryAlpha(raw: unknown): number { + const n = typeof raw === "number" ? raw : Number(raw); + if (!Number.isFinite(n)) return DEFAULT_QUERY_ALPHA; + return Math.min(1, Math.max(0, n)); +} + +function toStringArray(value: unknown, fallback: string[]): string[] { + if (Array.isArray(value)) { + return value.filter((x): x is string => typeof x === "string" && x.length > 0); + } + if (typeof value === "string" && value.trim() !== "") { + return [value.trim()]; + } + return fallback; +} + +function sanitizeIndexNameSegment(name: string): string { + const s = name + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, "") + .slice(0, 40); + return s.length > 0 ? s : "workspace"; +} + +/** Default index name when `moss.indexName` is empty: `vscode-moss-`. */ +export function defaultIndexNameForFolder(folder: vscode.WorkspaceFolder): string { + return `vscode-moss-${sanitizeIndexNameSegment(folder.name)}`; +} + +/** + * Stable SecretStorage key for this workspace folder’s Moss credentials JSON blob. + */ +export function workspaceCredentialsSecretKey(folder: vscode.WorkspaceFolder): string { + const digest = createHash("sha256").update(folder.uri.toString()).digest("hex"); + return `${MOSS_CREDENTIALS_SECRET_PREFIX}.${digest}`; +} + +export interface MossCredentialsPayload { + projectId: string; + projectKey: string; +} + +function parseCredentialsBlob(raw: string): MossCredentialsPayload | undefined { + try { + const data: unknown = JSON.parse(raw); + if (typeof data !== "object" || data === null || Array.isArray(data)) return undefined; + const rec = data as Record; + const projectId = + typeof rec.projectId === "string" ? rec.projectId.trim() : ""; + const projectKey = + typeof rec.projectKey === "string" ? rec.projectKey.trim() : ""; + if (!projectId || !projectKey) return undefined; + return { projectId, projectKey }; + } catch { + return undefined; + } +} + +export async function readCredentialsBlob( + secrets: vscode.SecretStorage, + folder: vscode.WorkspaceFolder +): Promise { + const raw = await secrets.get(workspaceCredentialsSecretKey(folder)); + if (!raw) return undefined; + return parseCredentialsBlob(raw); +} + +export async function storeCredentialsForWorkspace( + secrets: vscode.SecretStorage, + folder: vscode.WorkspaceFolder, + creds: MossCredentialsPayload +): Promise { + const payload: MossCredentialsPayload = { + projectId: creds.projectId.trim(), + projectKey: creds.projectKey.trim(), + }; + await secrets.store( + workspaceCredentialsSecretKey(folder), + JSON.stringify(payload) + ); +} + +export async function deleteCredentialsForWorkspace( + secrets: vscode.SecretStorage, + folder: vscode.WorkspaceFolder +): Promise { + await secrets.delete(workspaceCredentialsSecretKey(folder)); +} + +function resolveProjectIdFromEnv(): string | undefined { + return process.env.MOSS_PROJECT_ID?.trim(); +} + +/** + * Fallback when no workspace credentials blob exists: legacy global SecretStorage entry + * (see {@link MOSS_LEGACY_GLOBAL_PROJECT_KEY}) → `MOSS_PROJECT_KEY`. + * Project ID / key are not read from `settings.json` — use the configure command or env. + */ +export async function resolveProjectKey( + secrets: vscode.SecretStorage +): Promise { + const fromLegacy = await secrets.get(MOSS_LEGACY_GLOBAL_PROJECT_KEY); + if (fromLegacy?.trim()) return fromLegacy.trim(); + + const fromEnv = process.env.MOSS_PROJECT_KEY?.trim(); + if (fromEnv) return fromEnv; + + return undefined; +} + +/** + * Moss credentials for one workspace folder. Precedence: + * 1. Workspace credentials blob (SecretStorage, per folder URI) + * 2. Environment pair: both `MOSS_PROJECT_ID` and `MOSS_PROJECT_KEY` + * 3. Migration: legacy global project-key secret + `MOSS_PROJECT_ID` → persisted as workspace blob + * 4. Assemble `MOSS_PROJECT_ID` (env) + {@link resolveProjectKey} (legacy secret or `MOSS_PROJECT_KEY`) + */ +export async function resolveCredentialsForWorkspace( + secrets: vscode.SecretStorage, + folder: vscode.WorkspaceFolder +): Promise { + const fromBlob = await readCredentialsBlob(secrets, folder); + if (fromBlob) return fromBlob; + + const envId = process.env.MOSS_PROJECT_ID?.trim(); + const envKey = process.env.MOSS_PROJECT_KEY?.trim(); + if (envId && envKey) { + return { projectId: envId, projectKey: envKey }; + } + + const projectId = resolveProjectIdFromEnv(); + const legacyGlobalKey = await secrets.get(MOSS_LEGACY_GLOBAL_PROJECT_KEY); + if (projectId && legacyGlobalKey?.trim()) { + const migrated: MossCredentialsPayload = { + projectId, + projectKey: legacyGlobalKey.trim(), + }; + await storeCredentialsForWorkspace(secrets, folder, migrated); + return migrated; + } + + if (!projectId) return undefined; + + const projectKey = await resolveProjectKey(secrets); + if (!projectKey) return undefined; + + return { projectId, projectKey }; +} + +/** + * Credentials for the first workspace folder (sidebar / search / index entry points). + */ +export async function resolveCredentials( + context: vscode.ExtensionContext +): Promise { + const folder = vscode.workspace.workspaceFolders?.[0]; + if (!folder) return undefined; + return resolveCredentialsForWorkspace(context.secrets, folder); +} + +/** + * Moss settings + credentials for one workspace folder (`moss.*` scoped to that folder's URI). + */ +export async function getMossConfig( + secrets: vscode.SecretStorage, + folder: vscode.WorkspaceFolder +): Promise { + const cfg = vscode.workspace.getConfiguration("moss", folder.uri); + + const creds = await resolveCredentialsForWorkspace(secrets, folder); + + const configuredIndex = cfg.get("indexName")?.trim(); + const indexName = + configuredIndex && configuredIndex.length > 0 + ? configuredIndex + : defaultIndexNameForFolder(folder); + + const modelId = cfg.get("modelId")?.trim() || "moss-minilm"; + + const includeGlobs = toStringArray(cfg.get("includeGlob"), ["**/*"]); + const defaultExcludes = [ + "**/node_modules/**", + "**/.git/**", + "**/dist/**", + "**/out/**", + "**/.next/**", + "**/build/**", + ]; + const excludeGlobs = toStringArray(cfg.get("excludeGlob"), defaultExcludes); + + const maxFileSizeBytes = clampMaxFileSizeBytes(cfg.get("maxFileSizeBytes")); + const topK = clampPositiveInt(cfg.get("topK"), DEFAULT_TOP_K, TOP_K_CAP); + const alpha = resolveQueryAlpha(cfg.get("alpha")); + + const chunkMaxLines = clampPositiveInt( + cfg.get("chunkMaxLines"), + DEFAULT_CHUNK_MAX_LINES, + CHUNK_MAX_LINES_CAP + ); + const chunkOverlapLines = clampNonNegativeInt( + cfg.get("chunkOverlapLines"), + DEFAULT_CHUNK_OVERLAP_LINES, + CHUNK_OVERLAP_CAP + ); + + const respectGitignoreRaw = cfg.get("respectGitignore"); + const respectGitignore = respectGitignoreRaw !== false; + + return { + projectId: creds?.projectId, + projectKey: creds?.projectKey, + indexName, + modelId, + includeGlobs, + excludeGlobs, + maxFileSizeBytes, + topK, + alpha, + chunkMaxLines, + chunkOverlapLines, + respectGitignore, + workspaceFolder: folder, + }; +} diff --git a/packages/vscode-moss/src/extension.ts b/packages/vscode-moss/src/extension.ts new file mode 100644 index 00000000..d713a95b --- /dev/null +++ b/packages/vscode-moss/src/extension.ts @@ -0,0 +1,204 @@ +import * as vscode from "vscode"; +import { + deleteCredentialsForWorkspace, + readCredentialsBlob, + storeCredentialsForWorkspace, +} from "./config.js"; +import { runIndexWorkspace } from "./indexWorkspace.js"; +import { registerSearchIndexStaleHandler } from "./mossQueryState.js"; +import { registerMossStatusBar } from "./mossStatusBar.js"; +import { MossSearchViewProvider } from "./searchViewProvider.js"; + +/** + * Focus the Settings UI on Moss options. Cursor (and some VS Code builds) ignore the + * **string** query passed to `openSettings2`; the supported shape is `{ query: string }`. + * See https://github.com/microsoft/vscode/issues/226071 + * Fallback: `vscode://settings/` reveals a contributed setting (same scheme in Cursor). + */ +async function revealMossSettings(): Promise { + try { + await vscode.commands.executeCommand("workbench.action.openSettings2", { + query: "moss.", + }); + return; + } catch { + /* fall through */ + } + try { + await vscode.commands.executeCommand( + "workbench.action.openSettings2", + "moss." + ); + return; + } catch { + /* fall through */ + } + try { + await vscode.commands.executeCommand( + "workbench.action.openSettings", + "moss." + ); + return; + } catch { + /* fall through */ + } + const opened = await vscode.env.openExternal( + vscode.Uri.parse("vscode://settings/moss.indexName") + ); + if (!opened) { + await vscode.commands.executeCommand("workbench.action.openSettings"); + } +} + +// ── Activation ─────────────────────────────────────────────────────── + +export function activate(context: vscode.ExtensionContext): void { + const log = vscode.window.createOutputChannel("Moss"); + + registerMossStatusBar(context); + + // Sidebar search view + const searchProvider = new MossSearchViewProvider( + context.extensionUri, + context, + log + ); + context.subscriptions.push( + registerSearchIndexStaleHandler(() => searchProvider.resetSearchSession()) + ); + + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration((e) => { + const mossKeysAffectingSession = [ + "moss.indexName", + "moss.topK", + "moss.alpha", + "moss.modelId", + "moss.includeGlob", + "moss.excludeGlob", + "moss.respectGitignore", + "moss.maxFileSizeBytes", + "moss.chunkMaxLines", + "moss.chunkOverlapLines", + ] as const; + if (mossKeysAffectingSession.some((k) => e.affectsConfiguration(k))) { + searchProvider.resetSearchSession(); + } + }) + ); + + context.subscriptions.push( + vscode.window.registerWebviewViewProvider( + MossSearchViewProvider.viewId, + searchProvider + ) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("moss.indexWorkspace", async () => { + await runIndexWorkspace(context, log); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("moss.openSettings", () => { + void revealMossSettings(); + }) + ); + + // moss.search — focus the sidebar search view + context.subscriptions.push( + vscode.commands.registerCommand("moss.search", async () => { + await vscode.commands.executeCommand( + "workbench.view.extension.mossContainer" + ); + await vscode.commands.executeCommand("moss.searchView.focus"); + }) + ); + + // moss.configureCredentials — prompt project ID then key (one pair per workspace blob) + context.subscriptions.push( + vscode.commands.registerCommand("moss.configureCredentials", async () => { + const folders = vscode.workspace.workspaceFolders; + if (!folders?.length) { + void vscode.window.showWarningMessage( + "Moss: Open a folder or workspace before configuring credentials." + ); + return; + } + const primary = folders[0]!; + + const currentId = + (await readCredentialsBlob(context.secrets, primary))?.projectId ?? + process.env.MOSS_PROJECT_ID?.trim() ?? + ""; + + const projectId = await vscode.window.showInputBox({ + title: "Moss — project credentials", + prompt: "Project ID", + value: currentId, + ignoreFocusOut: true, + placeHolder: "Your Moss project ID", + }); + if (projectId === undefined) return; + + const trimmedId = projectId.trim(); + if (!trimmedId) { + void vscode.window.showWarningMessage( + "Moss: Project ID is required." + ); + return; + } + + const projectKeyInput = await vscode.window.showInputBox({ + title: "Moss — project credentials", + prompt: "Project key", + password: true, + ignoreFocusOut: true, + placeHolder: "Your Moss project key", + }); + if (projectKeyInput === undefined) return; + + const trimmedKey = projectKeyInput.trim(); + if (!trimmedKey) { + void vscode.window.showWarningMessage( + "Moss: Project key is required. Run “Moss: Clear credentials” to remove stored credentials." + ); + return; + } + + await storeCredentialsForWorkspace(context.secrets, primary, { + projectId: trimmedId, + projectKey: trimmedKey, + }); + + searchProvider.resetSearchSession(); + + void vscode.window.showInformationMessage( + "Moss: Credentials saved for this workspace (secure storage)." + ); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand("moss.clearCredentials", async () => { + const folders = vscode.workspace.workspaceFolders; + if (!folders?.length) { + void vscode.window.showWarningMessage( + "Moss: Open a folder or workspace first." + ); + return; + } + const primary = folders[0]!; + await deleteCredentialsForWorkspace(context.secrets, primary); + searchProvider.resetSearchSession(); + void vscode.window.showInformationMessage( + "Moss: Workspace credentials removed from secure storage." + ); + }) + ); + + context.subscriptions.push(log); +} + +export function deactivate(): void {} diff --git a/packages/vscode-moss/src/formatError.ts b/packages/vscode-moss/src/formatError.ts new file mode 100644 index 00000000..03aa44a3 --- /dev/null +++ b/packages/vscode-moss/src/formatError.ts @@ -0,0 +1,4 @@ +/** Stable string for logging and user-facing error messages. */ +export function formatError(e: unknown): string { + return e instanceof Error ? e.message : String(e); +} diff --git a/packages/vscode-moss/src/gitignoreFilter.ts b/packages/vscode-moss/src/gitignoreFilter.ts new file mode 100644 index 00000000..c31cecf1 --- /dev/null +++ b/packages/vscode-moss/src/gitignoreFilter.ts @@ -0,0 +1,46 @@ +import ignore from "ignore"; +import * as vscode from "vscode"; + +/** + * Drop URIs whose path matches the **workspace-folder root** `.gitignore`, + * using the same matching rules as Git for that file (via the `ignore` package). + * Nested `.gitignore` files in subdirectories are not read (same patterns often + * appear in the root file in monorepos). + */ +export async function filterUrisByRootGitignore( + uris: vscode.Uri[], + folders: readonly vscode.WorkspaceFolder[] +): Promise { + if (uris.length === 0) return uris; + + const igByFolderUri = new Map>(); + await Promise.all( + folders.map(async (folder) => { + let ig = ignore(); + try { + const giUri = vscode.Uri.joinPath(folder.uri, ".gitignore"); + const bytes = await vscode.workspace.fs.readFile(giUri); + let text = new TextDecoder("utf-8").decode(bytes); + if (text.charCodeAt(0) === 0xfeff) { + text = text.slice(1); + } + ig = ignore().add(text); + } catch { + // Missing or unreadable `.gitignore` → no extra excludes. + } + igByFolderUri.set(folder.uri.toString(), ig); + }) + ); + + return uris.filter((uri) => { + const folder = vscode.workspace.getWorkspaceFolder(uri); + if (!folder) return true; + const ig = igByFolderUri.get(folder.uri.toString()); + if (!ig) return true; + + const rel = vscode.workspace.asRelativePath(uri, false); + if (!rel) return true; + const posix = rel.replace(/\\/g, "/"); + return !ig.ignores(posix); + }); +} diff --git a/packages/vscode-moss/src/indexWorkspace.ts b/packages/vscode-moss/src/indexWorkspace.ts new file mode 100644 index 00000000..16414263 --- /dev/null +++ b/packages/vscode-moss/src/indexWorkspace.ts @@ -0,0 +1,539 @@ +import * as vscode from "vscode"; +import path from "node:path"; +import { MossClient } from "@moss-dev/moss"; +import { getMossConfig, resolveCredentials } from "./config.js"; +import { chunkFileContent } from "./chunking.js"; +import { formatError } from "./formatError.js"; +import { + MOSS_LAST_INDEXED_KEY, + type LastIndexedState, +} from "./lastIndexed.js"; +import { filterUrisByRootGitignore } from "./gitignoreFilter.js"; +import { mossLog } from "./mossLog.js"; +import { ensureLocalIndexLoaded, notifySearchIndexStale } from "./mossQueryState.js"; +import { notifyMossIndexed } from "./mossStatusBar.js"; +import type { DocumentInfo, JobProgress } from "@moss-dev/moss"; + +const MAX_FILE_SCAN = 80_000; +const MAX_MOSS_DOCUMENTS = 60_000; +const POST_CREATE_SETTLE_MS = 2500; + +/** Always applied on top of `moss.excludeGlob` (Phase 5 merge with safe defaults). */ +const EXTRA_SAFE_EXCLUDES = [ + "**/.svn/**", + "**/.hg/**", + "**/__pycache__/**", +]; + +/** VS Code–style language id for structure-aware chunking (Markdown, JS/TS, and other Tree-sitter grammars). */ +function languageIdFromPath(fsPath: string): string | undefined { + switch (path.extname(fsPath).toLowerCase()) { + case ".md": + case ".mdx": + return "markdown"; + case ".ts": + case ".mts": + case ".cts": + return "typescript"; + case ".tsx": + return "typescriptreact"; + case ".js": + case ".mjs": + case ".cjs": + return "javascript"; + case ".jsx": + return "javascriptreact"; + case ".py": + case ".pyi": + case ".pyw": + return "python"; + case ".rs": + return "rust"; + case ".go": + return "go"; + case ".java": + return "java"; + case ".rb": + case ".rake": + case ".ru": + return "ruby"; + case ".php": + return "php"; + case ".c": + case ".h": + return "c"; + case ".cpp": + case ".cc": + case ".cxx": + case ".hpp": + case ".hh": + case ".hxx": + case ".inl": + case ".cu": + return "cpp"; + case ".cs": + return "csharp"; + default: + return undefined; + } +} + +const BINARY_EXT = new Set( + [ + ".zip", + ".tar", + ".gz", + ".tgz", + ".rar", + ".7z", + ".bz2", + ".xz", + ".png", + ".jpg", + ".jpeg", + ".gif", + ".webp", + ".ico", + ".bmp", + ".tif", + ".tiff", + ".heic", + ".pdf", + ".exe", + ".dll", + ".so", + ".dylib", + ".wasm", + ".mp3", + ".mp4", + ".mov", + ".avi", + ".mkv", + ".webm", + ".wmv", + ".bin", + ".sqlite", + ".sqlite3", + ".db", + ".woff", + ".woff2", + ".ttf", + ".eot", + ".otf", + ".class", + ".jar", + ".pyc", + ".pyo", + ".o", + ".a", + ".lib", + ".obj", + ".ilk", + ".pdb", + ".dmg", + ".iso", + ".img", + ].map((e) => e.toLowerCase()) +); + +function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +function uniqueSorted(values: string[]): string[] { + return [...new Set(values.filter(Boolean))].sort((a, b) => a.localeCompare(b)); +} + +function toBraceGlob(patterns: string[]): string { + const u = uniqueSorted(patterns); + if (u.length === 0) return "**/*"; + if (u.length === 1) return u[0]!; + return `{${u.join(",")}}`; +} + +function canBraceCombine(patterns: string[]): boolean { + return patterns.every((p) => !/[{}]/.test(p) && !p.includes(",")); +} + +async function tolerateDeleteIndex( + client: MossClient, + indexName: string, + log: vscode.OutputChannel +): Promise { + try { + await client.deleteIndex(indexName); + mossLog( + log, + `Moss: Deleted existing index "${indexName}" (if it existed).`, + "verbose" + ); + } catch (err: unknown) { + const msg = err instanceof Error ? err.message : String(err); + if (/not found|does not exist/i.test(msg)) { + mossLog( + log, + `Moss: No existing index "${indexName}" to delete (ok).`, + "verbose" + ); + } else { + mossLog(log, `Moss: deleteIndex warning: ${msg}`); + } + } +} + +function isBinaryExt(fsPath: string): boolean { + return BINARY_EXT.has(path.extname(fsPath).toLowerCase()); +} + +async function findWorkspaceFiles( + includeGlobs: string[], + excludeGlobs: string[], + maxFiles: number, + token: vscode.CancellationToken +): Promise<{ uris: vscode.Uri[]; scanTruncated: boolean }> { + const includes = uniqueSorted(includeGlobs.length > 0 ? includeGlobs : ["**/*"]); + const excludePat = + excludeGlobs.length > 0 ? toBraceGlob(uniqueSorted(excludeGlobs)) : null; + + const dedupe = new Set(); + const out: vscode.Uri[] = []; + + const addBatch = (batch: readonly vscode.Uri[]) => { + for (const u of batch) { + const k = u.toString(); + if (dedupe.has(k)) continue; + dedupe.add(k); + out.push(u); + } + }; + + if (includes.length === 1) { + const batch = await vscode.workspace.findFiles( + includes[0]!, + excludePat, + maxFiles + 1, + token + ); + addBatch(batch); + } else if (canBraceCombine(includes)) { + const batch = await vscode.workspace.findFiles( + `{${includes.join(",")}}`, + excludePat, + maxFiles + 1, + token + ); + addBatch(batch); + } else { + for (const inc of includes) { + if (token.isCancellationRequested) break; + const batch = await vscode.workspace.findFiles( + inc, + excludePat, + maxFiles + 1 - out.length, + token + ); + addBatch(batch); + if (out.length > maxFiles) break; + } + } + + const scanTruncated = out.length > maxFiles; + return { uris: out.slice(0, maxFiles), scanTruncated }; +} + +async function readUtf8Text(uri: vscode.Uri): Promise { + try { + const bytes = await vscode.workspace.fs.readFile(uri); + if (bytes.includes(0)) return undefined; + const dec = new TextDecoder("utf-8", { fatal: true }); + return dec.decode(bytes); + } catch { + return undefined; + } +} + +/** + * Full workspace reindex: discover files, chunk, REST deleteIndex + createIndex, optional loadIndex. + */ +export async function runIndexWorkspace( + context: vscode.ExtensionContext, + log: vscode.OutputChannel +): Promise { + const folders = vscode.workspace.workspaceFolders; + if (!folders?.length) { + void vscode.window.showErrorMessage( + "Moss: Open a folder or workspace before indexing." + ); + return; + } + + const creds = await resolveCredentials(context); + if (!creds) { + void vscode.window.showErrorMessage( + "Moss: Missing credentials. Run “Moss: Configure credentials” or set MOSS_PROJECT_ID / MOSS_PROJECT_KEY." + ); + return; + } + + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + title: "Moss: Indexing workspace", + cancellable: true, + }, + async (progress, token) => { + mossLog(log, "Moss: Index workspace — starting…"); + + const primary = folders[0]!; + const cfg = await getMossConfig(context.secrets, primary); + + const excludeGlobs = uniqueSorted([ + ...EXTRA_SAFE_EXCLUDES, + ...cfg.excludeGlobs, + ]); + + progress.report({ message: "Scanning files…" }); + mossLog(log, "Moss: Scanning workspace for files…"); + let { uris, scanTruncated } = await findWorkspaceFiles( + cfg.includeGlobs, + excludeGlobs, + MAX_FILE_SCAN, + token + ); + + if (token.isCancellationRequested) { + mossLog(log, "Moss: Indexing cancelled (after scan)."); + return; + } + + if (cfg.respectGitignore) { + const before = uris.length; + uris = await filterUrisByRootGitignore(uris, folders); + const dropped = before - uris.length; + if (dropped > 0) { + mossLog( + log, + `Moss: Skipped ${dropped} file(s) matched by root .gitignore (moss.respectGitignore).`, + "verbose" + ); + } + } + + if (scanTruncated) { + const msg = `File scan stopped at ${MAX_FILE_SCAN} files. Narrow moss.includeGlob or add moss.excludeGlob to index a smaller set.`; + mossLog(log, msg); + void vscode.window.showWarningMessage(`Moss: ${msg}`); + } + + mossLog(log, `Moss: Found ${uris.length} file(s) to consider.`, "verbose"); + mossLog( + log, + `Moss: Reading and chunking ${uris.length} file(s) — progress is shown in the notification…` + ); + + uris.sort((a, b) => a.fsPath.localeCompare(b.fsPath)); + + const allDocs: DocumentInfo[] = []; + let filesIndexed = 0; + let skippedSize = 0; + let skippedBinary = 0; + let skippedDecode = 0; + let decodeLogged = false; + + const total = uris.length; + for (let i = 0; i < uris.length; i++) { + if (token.isCancellationRequested) { + mossLog(log, "Moss: Indexing cancelled while reading files."); + return; + } + + const uri = uris[i]!; + progress.report({ + message: `Reading files (${i + 1}/${total})…`, + increment: total > 0 ? 100 / total : 0, + }); + + const folder = vscode.workspace.getWorkspaceFolder(uri); + if (!folder) continue; + + const folderIndex = folders.indexOf(folder); + if (folderIndex < 0) continue; + + if (isBinaryExt(uri.fsPath)) { + skippedBinary += 1; + continue; + } + + let stat: vscode.FileStat; + try { + stat = await vscode.workspace.fs.stat(uri); + } catch { + continue; + } + + if (stat.size > cfg.maxFileSizeBytes) { + skippedSize += 1; + continue; + } + + const text = await readUtf8Text(uri); + + if (text === undefined) { + skippedDecode += 1; + if (!decodeLogged) { + mossLog( + log, + "Moss: One or more files were skipped (invalid UTF-8 or binary content).", + "verbose" + ); + decodeLogged = true; + } + continue; + } + + const relativePath = vscode.workspace.asRelativePath(uri, false); + if (relativePath === "") continue; + + const chunks = await chunkFileContent( + relativePath, + text, + { + chunkMaxLines: cfg.chunkMaxLines, + chunkOverlapLines: cfg.chunkOverlapLines, + workspaceFolderIndex: folderIndex, + workspaceFolderName: folder.name, + chunkIdNamespace: + folders.length > 1 ? String(folderIndex) : undefined, + }, + languageIdFromPath(uri.fsPath) + ); + + allDocs.push(...chunks); + filesIndexed += 1; + + if (allDocs.length >= MAX_MOSS_DOCUMENTS) { + mossLog( + log, + `Moss: Chunk limit reached (${MAX_MOSS_DOCUMENTS}); remaining files are skipped.` + ); + void vscode.window.showWarningMessage( + `Moss: Index truncated at ${MAX_MOSS_DOCUMENTS} chunks. Narrow include patterns or raise the limit in code.` + ); + break; + } + } + + if (token.isCancellationRequested) { + mossLog(log, "Moss: Indexing cancelled before upload."); + return; + } + + if (allDocs.length === 0) { + const msg = + "No indexable documents were produced (empty workspace, filters, or unsupported files)."; + mossLog(log, msg); + void vscode.window.showWarningMessage(`Moss: ${msg}`); + return; + } + + progress.report({ message: "Uploading index to Moss…", increment: 0 }); + mossLog( + log, + `Moss: Uploading ${allDocs.length} chunk(s) to Moss (createIndex)…` + ); + if (allDocs.length >= 5_000) { + mossLog( + log, + "Moss: Large index — upload and server-side embedding can take many minutes; progress updates appear below.", + "verbose" + ); + } + + const client = new MossClient(creds.projectId, creds.projectKey); + + const reportCreateProgress = (p: JobProgress) => { + const phase = + p.currentPhase != null ? ` · ${p.currentPhase}` : ""; + progress.report({ + message: `Uploading index to Moss… ${p.status} ${p.progress}%${phase}`, + increment: 0, + }); + mossLog( + log, + `Moss: createIndex progress — ${p.status} ${p.progress}%${phase} (job ${p.jobId})`, + "verbose" + ); + }; + + try { + await tolerateDeleteIndex(client, cfg.indexName, log); + if (token.isCancellationRequested) { + mossLog(log, "Moss: Indexing cancelled before createIndex."); + return; + } + + progress.report({ + message: "Uploading index to Moss… starting", + increment: 0, + }); + + await client.createIndex(cfg.indexName, allDocs, { + modelId: cfg.modelId, + onProgress: reportCreateProgress, + }); + notifySearchIndexStale(); + mossLog( + log, + `Moss: createIndex finished — ${allDocs.length} chunks from ${filesIndexed} file(s), index “${cfg.indexName}”.` + ); + } catch (e: unknown) { + const msg = formatError(e); + mossLog(log, `Moss: createIndex failed: ${msg}`); + void vscode.window.showErrorMessage(`Moss: Indexing failed: ${msg}`); + return; + } + + await context.workspaceState.update(MOSS_LAST_INDEXED_KEY, { + indexName: cfg.indexName, + docCount: allDocs.length, + fileCount: filesIndexed, + timestamp: Date.now(), + } satisfies LastIndexedState); + + notifyMossIndexed(); + + mossLog( + log, + `Moss: Skipped while scanning — ${skippedSize} over size cap, ${skippedBinary} binary/ext, ${skippedDecode} decode/binary.`, + "verbose" + ); + + progress.report({ message: "Preparing local search cache…" }); + await sleep(POST_CREATE_SETTLE_MS); + if (token.isCancellationRequested) { + void vscode.window.showInformationMessage( + "Moss: Index uploaded. Local cache warm-up was cancelled." + ); + return; + } + try { + const localState: { loadedIndexName?: string } = {}; + await ensureLocalIndexLoaded(client, cfg.indexName, localState); + mossLog( + log, + "Moss: loadIndex completed (local query cache warmed).", + "verbose" + ); + } catch (e: unknown) { + mossLog( + log, + `Moss: loadIndex after indexing failed (search will use cloud fallback): ${formatError(e)}` + ); + } + + void vscode.window.showInformationMessage( + `Moss: Indexed ${filesIndexed} file(s) → ${allDocs.length} chunk(s) (“${cfg.indexName}”).` + ); + } + ); +} diff --git a/packages/vscode-moss/src/lastIndexed.ts b/packages/vscode-moss/src/lastIndexed.ts new file mode 100644 index 00000000..8735f09d --- /dev/null +++ b/packages/vscode-moss/src/lastIndexed.ts @@ -0,0 +1,9 @@ +/** `workspaceState` key written after a successful **Moss: Index Workspace**. */ +export const MOSS_LAST_INDEXED_KEY = "moss.lastIndexed"; + +export interface LastIndexedState { + indexName: string; + docCount: number; + fileCount: number; + timestamp: number; +} diff --git a/packages/vscode-moss/src/mossLog.ts b/packages/vscode-moss/src/mossLog.ts new file mode 100644 index 00000000..fbd350a2 --- /dev/null +++ b/packages/vscode-moss/src/mossLog.ts @@ -0,0 +1,17 @@ +import type * as vscode from "vscode"; +import { getMossLogVerbose } from "./config.js"; + +type LogSink = Pick; + +/** + * Append a line to the Moss output channel. Use **`verbose`** for optional detail when + * **`moss.logVerbose`** is enabled (Phase 8). + */ +export function mossLog( + sink: LogSink, + line: string, + level: "always" | "verbose" = "always" +): void { + if (level === "verbose" && !getMossLogVerbose()) return; + sink.appendLine(line); +} diff --git a/packages/vscode-moss/src/mossQueryState.ts b/packages/vscode-moss/src/mossQueryState.ts new file mode 100644 index 00000000..4aeeb8f9 --- /dev/null +++ b/packages/vscode-moss/src/mossQueryState.ts @@ -0,0 +1,61 @@ +import type { MossClient } from "@moss-dev/moss"; + +/** Tracks which index `loadIndex` last completed for a given `MossClient` session. */ +export interface LocalIndexLoadState { + loadedIndexName?: string; + /** + * When `loadIndex` fails for this index name, further attempts in the same session are skipped + * (avoids repeating download UI and work; `query` still uses cloud fallback). Cleared on success + * or when the session is reset. + */ + localLoadFailedIndex?: string; +} + +export async function ensureLocalIndexLoaded( + client: MossClient, + indexName: string, + state: LocalIndexLoadState +): Promise { + if (state.loadedIndexName === indexName) return; + if (state.localLoadFailedIndex === indexName) return; + try { + await client.loadIndex(indexName); + state.loadedIndexName = indexName; + state.localLoadFailedIndex = undefined; + } catch (e: unknown) { + state.localLoadFailedIndex = indexName; + throw e; + } +} + +export function clearLocalIndexLoadState(state: LocalIndexLoadState): void { + state.loadedIndexName = undefined; + state.localLoadFailedIndex = undefined; +} + +const searchIndexStaleHandlers = new Set<() => void>(); + +/** + * Register a callback when a full re-index finishes so listeners can reset search state. + * Returns a disposable; prefer pushing it onto `ExtensionContext.subscriptions`. + */ +export function registerSearchIndexStaleHandler( + handler: () => void +): { dispose: () => void } { + searchIndexStaleHandlers.add(handler); + return { + dispose: () => { + searchIndexStaleHandlers.delete(handler); + }, + }; +} + +export function notifySearchIndexStale(): void { + for (const h of searchIndexStaleHandlers) { + try { + h(); + } catch { + /* isolate handler failures */ + } + } +} diff --git a/packages/vscode-moss/src/mossStatusBar.ts b/packages/vscode-moss/src/mossStatusBar.ts new file mode 100644 index 00000000..1da42a05 --- /dev/null +++ b/packages/vscode-moss/src/mossStatusBar.ts @@ -0,0 +1,77 @@ +import * as vscode from "vscode"; +import { + MOSS_LAST_INDEXED_KEY, + type LastIndexedState, +} from "./lastIndexed.js"; + +const TICK_MS = 60_000; + +let refreshStatus: (() => void) | undefined; + +function formatIndexedAgo(timestamp: number): string { + const sec = Math.floor((Date.now() - timestamp) / 1000); + if (sec < 10) return "just now"; + if (sec < 60) return `${sec}s ago`; + const min = Math.floor(sec / 60); + if (min < 60) return `${min}m ago`; + const h = Math.floor(min / 60); + if (h < 48) return `${h}h ago`; + const d = Math.floor(h / 24); + return `${d}d ago`; +} + +/** + * Registers the status bar item (click → **Moss: Index Workspace**) and periodic refresh. + */ +export function registerMossStatusBar(context: vscode.ExtensionContext): void { + const item = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Right, + 100 + ); + item.command = "moss.indexWorkspace"; + + const update = (): void => { + const folders = vscode.workspace.workspaceFolders; + if (!folders?.length) { + item.text = "$(search) Moss"; + item.tooltip = + "Moss semantic search — open a folder, then click to run Moss: Index Workspace."; + item.show(); + return; + } + + const state = context.workspaceState.get( + MOSS_LAST_INDEXED_KEY + ); + if (!state?.timestamp) { + item.text = "$(search) Moss: not indexed"; + item.tooltip = + "No Moss index for this workspace yet.\nClick to run Moss: Index Workspace."; + item.show(); + return; + } + + item.text = `$(search) Moss: indexed ${formatIndexedAgo(state.timestamp)}`; + item.tooltip = [ + `Last index: “${state.indexName}”`, + `${state.docCount} chunks · ${state.fileCount} files`, + "Click to run Moss: Index Workspace.", + ].join("\n"); + item.show(); + }; + + refreshStatus = update; + update(); + + const interval = setInterval(update, TICK_MS); + context.subscriptions.push( + { dispose: () => clearInterval(interval) }, + item, + vscode.workspace.onDidChangeWorkspaceFolders(() => update()) + ); +} + +/** Call after a successful index so “Xm ago” updates immediately. */ +export function notifyMossIndexed(): void { + refreshStatus?.(); +} diff --git a/packages/vscode-moss/src/paths.ts b/packages/vscode-moss/src/paths.ts new file mode 100644 index 00000000..1dc820d0 --- /dev/null +++ b/packages/vscode-moss/src/paths.ts @@ -0,0 +1,52 @@ +import * as vscode from "vscode"; +import type { MossMetadata } from "./types.js"; + +function parsePositiveInt(s: string | undefined, fallback: number): number { + if (s === undefined || s === "") return fallback; + const n = parseInt(s, 10); + return Number.isFinite(n) && n > 0 ? n : fallback; +} + +/** 0-based folder index; missing or invalid → 0. */ +function parseWorkspaceFolderIndex(s: string | undefined): number { + if (s === undefined || s === "") return 0; + const n = parseInt(s, 10); + if (!Number.isFinite(n) || n < 0) return 0; + return n; +} + +/** + * Resolve workspace-relative `metadata.path` to a file URI using `workspaceFolderIndex` + * (0-based; default 0). Returns `undefined` if the folder index is out of range or path looks unsafe. + */ +export function metadataToUri( + workspaceFolders: readonly vscode.WorkspaceFolder[] | undefined, + metadata: MossMetadata +): vscode.Uri | undefined { + if (!workspaceFolders?.length) return undefined; + + const idx = parseWorkspaceFolderIndex(metadata.workspaceFolderIndex); + if (idx >= workspaceFolders.length) return undefined; + + const rel = metadata.path?.replace(/\\/g, "/") ?? ""; + if (rel === "" || rel.startsWith("/")) return undefined; + + const segments = rel.split("/").filter((p) => p.length > 0); + if (segments.some((p) => p === "..")) return undefined; + + const root = workspaceFolders[idx]!.uri; + return segments.length === 0 ? root : vscode.Uri.joinPath(root, ...segments); +} + +/** + * Map 1-based inclusive line metadata to a VS Code `Range` (0-based lines). + */ +export function metadataToRange(metadata: MossMetadata): vscode.Range { + const startLine = parsePositiveInt(metadata.startLine, 1); + let endLine = parsePositiveInt(metadata.endLine, startLine); + if (endLine < startLine) endLine = startLine; + + const start = startLine - 1; + const end = endLine - 1; + return new vscode.Range(start, 0, end, Number.MAX_SAFE_INTEGER); +} diff --git a/packages/vscode-moss/src/runMossQuery.ts b/packages/vscode-moss/src/runMossQuery.ts new file mode 100644 index 00000000..8a815c95 --- /dev/null +++ b/packages/vscode-moss/src/runMossQuery.ts @@ -0,0 +1,190 @@ +import type { MossClient, QueryResultDocumentInfo } from "@moss-dev/moss"; +import * as vscode from "vscode"; +import { getMossConfig, resolveCredentials } from "./config.js"; +import { formatError } from "./formatError.js"; +import { ensureLocalIndexLoaded, type LocalIndexLoadState } from "./mossQueryState.js"; +import { mossLog } from "./mossLog.js"; + +export type SearchErrorCode = + | "NO_WORKSPACE" + | "NO_CREDENTIALS" + | "INDEX_NOT_FOUND" + | "QUERY_FAILED" + | "CANCELLED"; + +export interface SearchFailure { + code: SearchErrorCode; + message: string; +} + +function lineLabel(meta: Record): string { + const start = meta.startLine?.trim() ?? ""; + const end = meta.endLine?.trim() ?? ""; + if (start && end && start !== end) return `${start}–${end}`; + if (start) return start; + return "?"; +} + +export interface RunMossQueryHooks { + /** Called immediately before a blocking `loadIndex` (first local search or after cache invalidation). */ + onAwaitingLocalIndexDownload?: () => void; + /** Called after `loadIndex` finishes or throws (before `query` runs). */ + onLocalIndexDownloadFinished?: () => void; +} + +export type RunMossQueryOptions = RunMossQueryHooks & { + token?: vscode.CancellationToken; + /** + * When set, skips `resolveCredentials` (caller already validated credentials). + */ + credentials?: { projectId: string; projectKey: string }; +}; + +export interface MossQuerySession { + client: MossClient; + localIndexState: LocalIndexLoadState; +} + +/** + * Semantic search against the configured workspace index. + * Uses `session` for the Moss client and local `loadIndex` state (sidebar search lifetime). + */ +function cancelledFailure(): SearchFailure { + return { code: "CANCELLED", message: "" }; +} + +export async function runMossQuery( + context: vscode.ExtensionContext, + queryText: string, + log: vscode.OutputChannel, + session: MossQuerySession, + options?: RunMossQueryOptions +): Promise< + | { ok: true; hits: QueryResultDocumentInfo[]; timeMs?: number } + | { ok: false; error: SearchFailure } +> { + const token = options?.token; + + const folders = vscode.workspace.workspaceFolders; + if (!folders?.length) { + return { + ok: false, + error: { + code: "NO_WORKSPACE", + message: "Open a folder or workspace before searching.", + }, + }; + } + + if (token?.isCancellationRequested) { + return { ok: false, error: cancelledFailure() }; + } + + const creds = + options?.credentials ?? (await resolveCredentials(context)); + if (!creds) { + return { + ok: false, + error: { + code: "NO_CREDENTIALS", + message: + "Missing Moss credentials. Run “Moss: Configure credentials” or set MOSS_PROJECT_ID / MOSS_PROJECT_KEY.", + }, + }; + } + + if (token?.isCancellationRequested) { + return { ok: false, error: cancelledFailure() }; + } + + const primary = folders[0]!; + const cfg = await getMossConfig(context.secrets, primary); + const sdk = session.client; + + if (token?.isCancellationRequested) { + return { ok: false, error: cancelledFailure() }; + } + + const state = session.localIndexState; + const willAttemptLocalLoad = + state.loadedIndexName !== cfg.indexName && + state.localLoadFailedIndex !== cfg.indexName; + + if (willAttemptLocalLoad) { + options?.onAwaitingLocalIndexDownload?.(); + } + try { + await ensureLocalIndexLoaded(sdk, cfg.indexName, state); + } catch (e: unknown) { + mossLog( + log, + `Moss: Search — loadIndex failed; continuing with cloud query. ${formatError(e)}`, + "verbose" + ); + } finally { + if (willAttemptLocalLoad) { + options?.onLocalIndexDownloadFinished?.(); + } + } + + if (token?.isCancellationRequested) { + return { ok: false, error: cancelledFailure() }; + } + + try { + const result = await sdk.query(cfg.indexName, queryText, { + topK: cfg.topK, + alpha: cfg.alpha, + }); + + const hits: QueryResultDocumentInfo[] = result.docs.map((d) => ({ + ...d, + metadata: { ...(d.metadata ?? {}) }, + })); + + return { ok: true, hits, timeMs: result.timeTakenInMs }; + } catch (e: unknown) { + const msg = formatError(e); + const lower = msg.toLowerCase(); + if ( + /not found|does not exist|no such index|unknown index|index.*missing/i.test( + lower + ) + ) { + return { + ok: false, + error: { + code: "INDEX_NOT_FOUND", + message: `Index “${cfg.indexName}” was not found. Run “Moss: Index Workspace” first.`, + }, + }; + } + return { + ok: false, + error: { code: "QUERY_FAILED", message: msg }, + }; + } +} + +export function hitToRowDto(hit: QueryResultDocumentInfo): { + path: string; + lineLabel: string; + score: number; + snippet: string; +} { + const meta = hit.metadata ?? {}; + const path = meta.path?.replace(/\\/g, "/") ?? hit.id; + const snippet = truncateSnippet(hit.text, 280); + return { + path, + lineLabel: lineLabel(meta), + score: hit.score, + snippet, + }; +} + +function truncateSnippet(text: string, maxLen: number): string { + const t = text.replace(/\s+/g, " ").trim(); + if (t.length <= maxLen) return t; + return `${t.slice(0, maxLen - 1)}…`; +} diff --git a/packages/vscode-moss/src/searchViewProvider.ts b/packages/vscode-moss/src/searchViewProvider.ts new file mode 100644 index 00000000..4eb837dc --- /dev/null +++ b/packages/vscode-moss/src/searchViewProvider.ts @@ -0,0 +1,483 @@ +import { MossClient, type QueryResultDocumentInfo } from "@moss-dev/moss"; +import { randomBytes } from "node:crypto"; +import * as vscode from "vscode"; +import { getMossConfig, resolveCredentials } from "./config.js"; +import { ensureLocalIndexLoaded, clearLocalIndexLoadState, type LocalIndexLoadState } from "./mossQueryState.js"; +import { mossLog } from "./mossLog.js"; +import { hitToRowDto, runMossQuery } from "./runMossQuery.js"; +import { metadataToRange, metadataToUri } from "./paths.js"; + +export class MossSearchViewProvider implements vscode.WebviewViewProvider { + public static readonly viewId = "moss.searchView"; + + private _view?: vscode.WebviewView; + private _lastHits: QueryResultDocumentInfo[] = []; + private _querySeq = 0; + private _session?: { + projectId: string; + projectKey: string; + client: MossClient; + }; + private _localIndexState: LocalIndexLoadState = {}; + private _webviewMessageDisposable?: vscode.Disposable; + private _queryCts?: vscode.CancellationTokenSource; + + constructor( + private readonly _extensionUri: vscode.Uri, + private readonly _context: vscode.ExtensionContext, + private readonly _log: vscode.OutputChannel + ) {} + + /** Drop Moss client + local `loadIndex` state (sidebar closed, credentials changed, or index rebuilt). */ + public resetSearchSession(): void { + this._disposeQueryCancellation(); + this._session = undefined; + clearLocalIndexLoadState(this._localIndexState); + } + + private _disposeQueryCancellation(): void { + this._queryCts?.cancel(); + this._queryCts?.dispose(); + this._queryCts = undefined; + } + + private _clientFor(projectId: string, projectKey: string): MossClient { + if ( + this._session?.projectId === projectId && + this._session?.projectKey === projectKey + ) { + return this._session.client; + } + this._session = { + projectId, + projectKey, + client: new MossClient(projectId, projectKey), + }; + clearLocalIndexLoadState(this._localIndexState); + return this._session.client; + } + + private async _warmLocalIndex(token: vscode.CancellationToken): Promise { + if (token.isCancellationRequested) return; + const folders = vscode.workspace.workspaceFolders; + if (!folders?.length) return; + const creds = await resolveCredentials(this._context); + if (!creds) return; + const cfg = await getMossConfig(this._context.secrets, folders[0]!); + if (token.isCancellationRequested) return; + try { + const client = this._clientFor(creds.projectId, creds.projectKey); + await ensureLocalIndexLoaded(client, cfg.indexName, this._localIndexState); + mossLog(this._log, "Moss: Sidebar index warm-up finished.", "verbose"); + } catch (e: unknown) { + if (token.isCancellationRequested) return; + const msg = e instanceof Error ? e.message : String(e); + mossLog( + this._log, + `Moss: Sidebar index warm-up failed; local loadIndex skipped for this session (cloud fallback). ${msg}`, + "verbose" + ); + } + } + + public resolveWebviewView( + webviewView: vscode.WebviewView, + _context: vscode.WebviewViewResolveContext, + _token: vscode.CancellationToken + ): void { + this._view = webviewView; + + webviewView.webview.options = { + enableScripts: true, + localResourceRoots: [this._extensionUri], + }; + + webviewView.webview.html = this._getHtml(webviewView.webview); + + const warmCts = new vscode.CancellationTokenSource(); + webviewView.onDidDispose(() => { + this._webviewMessageDisposable?.dispose(); + this._webviewMessageDisposable = undefined; + this._disposeQueryCancellation(); + this._view = undefined; + warmCts.cancel(); + warmCts.dispose(); + this.resetSearchSession(); + }); + + this._webviewMessageDisposable?.dispose(); + this._webviewMessageDisposable = webviewView.webview.onDidReceiveMessage( + (message) => { + switch (message.type) { + case "query": + if (typeof message.text === "string") { + void this._handleQuery(message.text.trim()); + } + break; + case "openResult": + if (typeof message.hitIndex === "number") { + void this._openHitAtIndex(message.hitIndex); + } + break; + case "openMossSettings": + void vscode.commands.executeCommand("moss.openSettings"); + break; + default: + break; + } + } + ); + + void this._warmLocalIndex(warmCts.token); + } + + private async _handleQuery(text: string): Promise { + const webview = this._view?.webview; + if (!webview) return; + + if (text === "") { + this._disposeQueryCancellation(); + this._querySeq += 1; + if (this._view?.webview === webview) { + webview.postMessage({ type: "clearResults" }); + } + return; + } + + this._disposeQueryCancellation(); + this._queryCts = new vscode.CancellationTokenSource(); + const queryToken = this._queryCts.token; + + const seq = ++this._querySeq; + + const post = (message: unknown): void => { + if (seq !== this._querySeq) return; + if (this._view?.webview !== webview) return; + webview.postMessage(message); + }; + + post({ type: "loading", loading: true }); + post({ type: "clearError" }); + + const creds = await resolveCredentials(this._context); + if (!creds) { + if (seq !== this._querySeq) return; + post({ type: "loading", loading: false }); + post({ + type: "error", + code: "NO_CREDENTIALS", + message: + "Missing Moss credentials. Run “Moss: Configure credentials” or set MOSS_PROJECT_ID / MOSS_PROJECT_KEY.", + }); + return; + } + + const client = this._clientFor(creds.projectId, creds.projectKey); + const result = await runMossQuery( + this._context, + text, + this._log, + { client, localIndexState: this._localIndexState }, + { + token: queryToken, + credentials: creds, + onAwaitingLocalIndexDownload: () => { + post({ + type: "localIndexLoading", + text: "Downloading index for local search — first time can take a minute…", + }); + }, + onLocalIndexDownloadFinished: () => { + post({ type: "localIndexLoading", text: "" }); + }, + } + ); + + if (!result.ok && result.error.code === "CANCELLED") { + return; + } + + if (seq !== this._querySeq) return; + + post({ type: "loading", loading: false }); + + if (!result.ok) { + post({ + type: "error", + code: result.error.code, + message: result.error.message, + }); + return; + } + + this._lastHits = result.hits; + post({ + type: "results", + query: text, + hits: result.hits.map((h, index) => ({ + index, + ...hitToRowDto(h), + })), + timeMs: result.timeMs, + }); + } + + private async _openHitAtIndex(hitIndex: number): Promise { + if (hitIndex < 0 || hitIndex >= this._lastHits.length) return; + const hit = this._lastHits[hitIndex]!; + await openSearchHit(hit); + } + + private _getHtml(webview: vscode.Webview): string { + const nonce = getNonce(); + const scriptUri = webview.asWebviewUri( + vscode.Uri.joinPath(this._extensionUri, "media", "searchView.js") + ); + const csp = [ + "default-src 'none'", + `style-src 'nonce-${nonce}' ${webview.cspSource}`, + `script-src 'nonce-${nonce}' ${webview.cspSource}`, + ].join("; "); + + return /* html */ ` + + + + + + + + + +
    +
    + +
    +
    +

    + Run Moss: Index Workspace to index your files,
    + then search here. +

    +

    + Open Moss settings +

    +
    + +
    + + +`; + } +} + +async function openSearchHit(hit: QueryResultDocumentInfo): Promise { + const folders = vscode.workspace.workspaceFolders; + const meta = hit.metadata ?? {}; + const uri = metadataToUri(folders, meta); + if (!uri) { + void vscode.window.showWarningMessage( + "Moss: Could not resolve file location for this result." + ); + return; + } + + try { + const doc = await vscode.workspace.openTextDocument(uri); + const editor = await vscode.window.showTextDocument(doc, { preview: true }); + const range = metadataToRange(meta); + const start = range.start; + editor.selection = new vscode.Selection(start, start); + editor.revealRange( + range, + vscode.TextEditorRevealType.InCenterIfOutsideViewport + ); + } catch (e: unknown) { + const msg = e instanceof Error ? e.message : String(e); + void vscode.window.showErrorMessage(`Moss: Could not open file: ${msg}`); + } +} + +function getNonce(): string { + const chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + const bytes = randomBytes(32); + let result = ""; + for (let i = 0; i < 32; i++) { + result += chars[bytes[i]! % chars.length]!; + } + return result; +} diff --git a/packages/vscode-moss/src/structureChunking.ts b/packages/vscode-moss/src/structureChunking.ts new file mode 100644 index 00000000..7f8df7b7 --- /dev/null +++ b/packages/vscode-moss/src/structureChunking.ts @@ -0,0 +1,512 @@ +/** + * Structure-aware splitting: Markdown (headings) and tree-sitter top-level spans + * (JS/TS, Python, Rust, Go, Java, Ruby, PHP, C/C++, C#), then packing into Moss + * documents with line-window subdivision when a span is too large. + */ +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import type { Language, Node as TsNode } from "web-tree-sitter"; +import * as TreeSitter from "web-tree-sitter"; +import type { ChunkOptions } from "./chunkCore.js"; +import { + buildMetadata, + chunkLineWindowSegment, + normalizeRelativePath, +} from "./chunkCore.js"; +import type { DocumentInfo } from "@moss-dev/moss"; +import type { MossMetadata } from "./types.js"; + +/** 1-based inclusive line range in the source file. */ +export interface LineRange1 { + startLine: number; + endLine: number; + /** Optional metadata for Moss (string values only). */ + extraMeta?: Record; +} + +interface GrammarProfile { + /** npm package folder under node_modules */ + wasmPackage: string; + wasmFile: string; + rootTypes: ReadonlySet; + importTypes: ReadonlySet; + strategyImports: string; + strategyTop: string; +} + +function moduleDir(): string { + return path.dirname(fileURLToPath(import.meta.url)); +} + +function nodeModulesRoot(): string { + const dir = moduleDir(); + return path.join(dir, "..", "node_modules"); +} + +let parserInit: Promise | undefined; +const languageCache = new Map(); + +const GRAMMAR_BY_LANGUAGE_ID = new Map(); + +function registerGrammar(languageIds: string[], profile: GrammarProfile): void { + for (const id of languageIds) { + GRAMMAR_BY_LANGUAGE_ID.set(id.toLowerCase(), profile); + } +} + +registerGrammar( + ["typescript"], + { + wasmPackage: "tree-sitter-typescript", + wasmFile: "tree-sitter-typescript.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(["import_statement"]), + strategyImports: "ts_imports", + strategyTop: "ts_top_level", + } +); + +registerGrammar( + ["typescriptreact", "jsx"], + { + wasmPackage: "tree-sitter-typescript", + wasmFile: "tree-sitter-tsx.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(["import_statement"]), + strategyImports: "ts_imports", + strategyTop: "ts_top_level", + } +); + +registerGrammar( + ["javascript"], + { + wasmPackage: "tree-sitter-javascript", + wasmFile: "tree-sitter-javascript.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(["import_statement"]), + strategyImports: "ts_imports", + strategyTop: "ts_top_level", + } +); + +registerGrammar( + ["javascriptreact"], + { + wasmPackage: "tree-sitter-typescript", + wasmFile: "tree-sitter-tsx.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(["import_statement"]), + strategyImports: "ts_imports", + strategyTop: "ts_top_level", + } +); + +registerGrammar( + ["python"], + { + wasmPackage: "tree-sitter-python", + wasmFile: "tree-sitter-python.wasm", + rootTypes: new Set(["module"]), + importTypes: new Set([ + "import_statement", + "import_from_statement", + "future_import_statement", + ]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["rust"], + { + wasmPackage: "tree-sitter-rust", + wasmFile: "tree-sitter-rust.wasm", + rootTypes: new Set(["source_file"]), + importTypes: new Set(["use_declaration", "extern_crate_declaration"]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["go", "golang"], + { + wasmPackage: "tree-sitter-go", + wasmFile: "tree-sitter-go.wasm", + rootTypes: new Set(["source_file"]), + importTypes: new Set(["package_clause", "import_declaration"]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["java"], + { + wasmPackage: "tree-sitter-java", + wasmFile: "tree-sitter-java.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(["package_declaration", "import_declaration"]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["ruby"], + { + wasmPackage: "tree-sitter-ruby", + wasmFile: "tree-sitter-ruby.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["php"], + { + wasmPackage: "tree-sitter-php", + wasmFile: "tree-sitter-php.wasm", + rootTypes: new Set(["program"]), + importTypes: new Set(["php_tag", "namespace_use_declaration"]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["c"], + { + wasmPackage: "tree-sitter-c", + wasmFile: "tree-sitter-c.wasm", + rootTypes: new Set(["translation_unit"]), + importTypes: new Set([ + "preproc_include", + "preproc_def", + "preproc_function_def", + "preproc_call", + ]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["cpp", "cuda-cpp"], + { + wasmPackage: "tree-sitter-cpp", + wasmFile: "tree-sitter-cpp.wasm", + rootTypes: new Set(["translation_unit"]), + importTypes: new Set([ + "preproc_include", + "preproc_def", + "preproc_function_def", + "preproc_call", + ]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +registerGrammar( + ["csharp", "c#"], + { + wasmPackage: "tree-sitter-c-sharp", + wasmFile: "tree-sitter-c_sharp.wasm", + rootTypes: new Set(["compilation_unit"]), + importTypes: new Set(["using_directive", "extern_alias_directive"]), + strategyImports: "toplevel_imports", + strategyTop: "toplevel", + } +); + +async function ensureParser(): Promise { + if (!parserInit) { + const nm = nodeModulesRoot(); + parserInit = TreeSitter.Parser.init({ + locateFile: (base: string) => path.join(nm, "web-tree-sitter", base), + }).catch((err: unknown) => { + parserInit = undefined; + return Promise.reject(err); + }); + } + await parserInit; +} + +async function loadWasmLanguage( + wasmPackage: string, + wasmFile: string +): Promise { + const cacheKey = `${wasmPackage}/${wasmFile}`; + let lang = languageCache.get(cacheKey); + if (!lang) { + await ensureParser(); + const nm = nodeModulesRoot(); + lang = await TreeSitter.Language.load( + path.join(nm, wasmPackage, wasmFile) + ); + languageCache.set(cacheKey, lang); + } + return lang; +} + +function isAtxHeadingLine(line: string): boolean { + return /^(#{1,6})\s+/.test(line.trimStart()); +} + +/** + * Split Markdown on ATX headings (# …). Lines before the first heading are one section. + */ +export function markdownStructuralRanges(lines: string[]): LineRange1[] { + if (lines.length === 0) return []; + const ranges: LineRange1[] = []; + let secStart = 1; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]!; + if (i > 0 && isAtxHeadingLine(line)) { + const prevEnd = i; + if (secStart <= prevEnd) { + ranges.push({ + startLine: secStart, + endLine: prevEnd, + extraMeta: { chunkStrategy: "markdown" }, + }); + } + secStart = i + 1; + } + } + if (secStart <= lines.length) { + ranges.push({ + startLine: secStart, + endLine: lines.length, + extraMeta: { chunkStrategy: "markdown" }, + }); + } + return ranges; +} + +function nodeToLineRange1(node: TsNode, strategy: string): LineRange1 { + return { + startLine: node.startPosition.row + 1, + endLine: node.endPosition.row + 1, + extraMeta: { chunkStrategy: strategy }, + }; +} + +function resolveBodyRoot( + root: TsNode, + rootTypes: ReadonlySet +): TsNode | undefined { + if (rootTypes.has(root.type)) return root; + for (const c of root.namedChildren) { + if (rootTypes.has(c.type)) return c; + } + return undefined; +} + +function collectBodyTopLevelRanges( + body: TsNode, + importTypes: ReadonlySet, + strategyImports: string, + strategyTop: string +): LineRange1[] { + const ranges: LineRange1[] = []; + const children = body.namedChildren; + let i = 0; + while (i < children.length) { + const n = children[i]!; + if (importTypes.has(n.type)) { + let j = i; + while ( + j + 1 < children.length && + importTypes.has(children[j + 1]!.type) + ) { + j += 1; + } + const last = children[j]!; + ranges.push({ + startLine: n.startPosition.row + 1, + endLine: last.endPosition.row + 1, + extraMeta: { chunkStrategy: strategyImports }, + }); + i = j + 1; + continue; + } + ranges.push(nodeToLineRange1(n, strategyTop)); + i += 1; + } + return ranges; +} + +export async function treeSitterStructuralRanges( + text: string, + languageId: string +): Promise { + try { + const id = languageId.toLowerCase(); + const profile = GRAMMAR_BY_LANGUAGE_ID.get(id); + if (!profile) return undefined; + + const lang = await loadWasmLanguage(profile.wasmPackage, profile.wasmFile); + const parser = new TreeSitter.Parser(); + parser.setLanguage(lang); + const tree = parser.parse(text); + parser.delete(); + if (!tree) return undefined; + + const root = tree.rootNode; + const body = resolveBodyRoot(root, profile.rootTypes); + if (!body) { + tree.delete(); + return undefined; + } + + const ranges = collectBodyTopLevelRanges( + body, + profile.importTypes, + profile.strategyImports, + profile.strategyTop + ); + tree.delete(); + return ranges.length > 0 ? ranges : undefined; + } catch { + return undefined; + } +} + +function mergeMeta( + base: ChunkOptions, + pathNorm: string, + startLine: number, + endLine: number, + extra?: Record +): MossMetadata { + const m = buildMetadata(pathNorm, startLine, endLine, base); + if (extra) { + for (const [k, v] of Object.entries(extra)) { + m[k] = v; + } + } + return m; +} + +function sortRanges(ranges: LineRange1[]): LineRange1[] { + return [...ranges].sort((a, b) => a.startLine - b.startLine); +} + +/** + * Fill gaps between structural ranges with 1-based gap ranges (inclusive). + */ +function gapRanges( + sorted: LineRange1[], + totalLines: number +): LineRange1[] { + const gaps: LineRange1[] = []; + let cursor = 1; + for (const r of sorted) { + if (cursor < r.startLine) { + gaps.push({ + startLine: cursor, + endLine: r.startLine - 1, + extraMeta: { chunkStrategy: "line_window" }, + }); + } + cursor = Math.max(cursor, r.endLine + 1); + } + if (cursor <= totalLines) { + gaps.push({ + startLine: cursor, + endLine: totalLines, + extraMeta: { chunkStrategy: "line_window" }, + }); + } + return gaps.filter((g) => g.startLine <= g.endLine); +} + +/** + * Turn structural + gap ranges into Moss documents, subdividing large spans with line windows. + */ +export function packStructuralRanges( + pathNorm: string, + lines: string[], + structural: LineRange1[], + options: ChunkOptions +): DocumentInfo[] { + const total = lines.length; + if (total === 0) return []; + + const sorted = sortRanges(structural); + const gaps = gapRanges(sorted, total); + const combined = sortRanges([...sorted, ...gaps]); + + const idPrefix = + options.chunkIdNamespace !== undefined && options.chunkIdNamespace !== "" + ? `${options.chunkIdNamespace}:` + : ""; + + const out: DocumentInfo[] = []; + + for (const r of combined) { + const sub = chunkLineWindowSegment( + pathNorm, + lines, + r.startLine, + r.endLine, + options, + idPrefix, + r.extraMeta + ? (sl, el) => mergeMeta(options, pathNorm, sl, el, r.extraMeta) + : (sl, el) => buildMetadata(pathNorm, sl, el, options) + ); + out.push(...sub); + } + + return out; +} + +const STRUCTURE_TREE_SITTER_IDS = [ + ...new Set(GRAMMAR_BY_LANGUAGE_ID.keys()), +].sort((a, b) => a.localeCompare(b)); + +/** + * Structure-aware chunking when `languageId` is supported; returns `undefined` to use full-file line windows. + */ +export async function tryStructureAwareChunk( + relativePath: string, + text: string, + lines: string[], + options: ChunkOptions, + languageId: string | undefined +): Promise { + const id = languageId?.toLowerCase(); + const pathNorm = normalizeRelativePath(relativePath); + + if (id === "markdown" || id === "mdx") { + const ranges = markdownStructuralRanges(lines); + if (ranges.length <= 1) return undefined; + return packStructuralRanges(pathNorm, lines, ranges, options); + } + + if (id && GRAMMAR_BY_LANGUAGE_ID.has(id)) { + const ranges = await treeSitterStructuralRanges(text, id); + if (!ranges || ranges.length <= 1) return undefined; + return packStructuralRanges(pathNorm, lines, ranges, options); + } + + return undefined; +} + +/** Languages that may use Markdown or tree-sitter structural chunking. */ +export function supportsStructureChunking(languageId: string | undefined): boolean { + if (!languageId) return false; + const id = languageId.toLowerCase(); + return ( + id === "markdown" || + id === "mdx" || + STRUCTURE_TREE_SITTER_IDS.includes(id) + ); +} diff --git a/packages/vscode-moss/src/types.ts b/packages/vscode-moss/src/types.ts new file mode 100644 index 00000000..de78c7fe --- /dev/null +++ b/packages/vscode-moss/src/types.ts @@ -0,0 +1,15 @@ +export type { DocumentInfo, QueryResultDocumentInfo } from "@moss-dev/moss"; + +/** + * Moss REST/SDK documents use string-only metadata values. + */ +export type MossMetadata = Record; + +/** Chunk metadata we store for workspace indexing (all values are strings in Moss). */ +export interface ChunkMetadata { + path: string; + startLine: string; + endLine: string; + workspaceFolderIndex?: string; + workspaceFolderName?: string; +} diff --git a/packages/vscode-moss/test/chunking.test.ts b/packages/vscode-moss/test/chunking.test.ts new file mode 100644 index 00000000..bee2b888 --- /dev/null +++ b/packages/vscode-moss/test/chunking.test.ts @@ -0,0 +1,98 @@ +import { describe, expect, it } from "vitest"; +import { chunkFileContent } from "../src/chunking.js"; + +describe("chunkFileContent", () => { + const baseOpts = { + chunkMaxLines: 10, + chunkOverlapLines: 2, + maxCharsPerChunk: 500, + smallFileMaxLines: 50, + }; + + it("returns one empty chunk for empty text", async () => { + const docs = await chunkFileContent("a.ts", "", baseOpts); + expect(docs).toHaveLength(1); + expect(docs[0]!.id).toBe("a.ts:1-1"); + expect(docs[0]!.text).toBe(""); + expect(docs[0]!.metadata.startLine).toBe("1"); + expect(docs[0]!.metadata.endLine).toBe("1"); + }); + + it("uses single chunk for small files (≤ smallFileMaxLines)", async () => { + const lines = Array.from({ length: 20 }, (_, i) => `line ${i + 1}`); + const text = lines.join("\n"); + const docs = await chunkFileContent("src/small.ts", text, baseOpts); + expect(docs).toHaveLength(1); + expect(docs[0]!.id).toBe("src/small.ts:1-20"); + expect(docs[0]!.metadata.path).toBe("src/small.ts"); + expect(docs[0]!.text.length).toBeLessThanOrEqual(500); + }); + + it("windows-style path is normalized in id and metadata", async () => { + const docs = await chunkFileContent("src\\win.ts", "one", baseOpts); + expect(docs[0]!.id.startsWith("src/win.ts:")).toBe(true); + expect(docs[0]!.metadata.path).toBe("src/win.ts"); + }); + + it("splits large files into overlapping windows when language is not structure-aware", async () => { + const lines = Array.from({ length: 30 }, (_, i) => `L${i + 1}`); + const text = lines.join("\n"); + const docs = await chunkFileContent("big.txt", text, { + ...baseOpts, + smallFileMaxLines: 5, + }); + expect(docs.length).toBeGreaterThan(1); + const first = docs[0]!; + expect(first.metadata.startLine).toBe("1"); + expect(Number(first.metadata.endLine)).toBeLessThanOrEqual(10); + for (const d of docs) { + expect(d.text.length).toBeLessThanOrEqual(500); + expect(d.id).toMatch(/^big\.txt:\d+-\d+$/); + } + }); + + it("prefixes ids with chunkIdNamespace for multi-root", async () => { + const docs = await chunkFileContent( + "x.ts", + "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk", + { + ...baseOpts, + smallFileMaxLines: 3, + chunkIdNamespace: "1", + } + ); + expect(docs.every((d) => d.id.startsWith("1:"))).toBe(true); + }); + + it("includes workspace metadata when provided", async () => { + const docs = await chunkFileContent("f.ts", "x", { + ...baseOpts, + workspaceFolderIndex: 2, + workspaceFolderName: "backend", + }); + expect(docs[0]!.metadata.workspaceFolderIndex).toBe("2"); + expect(docs[0]!.metadata.workspaceFolderName).toBe("backend"); + }); + + it("clamps overlap when overlap >= chunkMaxLines", async () => { + const lines = Array.from({ length: 25 }, (_, i) => `x${i}`); + const text = lines.join("\n"); + const docs = await chunkFileContent("o.ts", text, { + chunkMaxLines: 5, + chunkOverlapLines: 99, + smallFileMaxLines: 5, + maxCharsPerChunk: 10_000, + }); + expect(docs.length).toBeGreaterThan(0); + }); + + it("splits markdown on headings when languageId is markdown", async () => { + const md = "# A\nline\n\n## B\nmore\n"; + const docs = await chunkFileContent("doc.md", md, baseOpts, "markdown"); + expect(docs.length).toBeGreaterThanOrEqual(2); + const strategies = docs.map((d) => d.metadata.chunkStrategy); + expect(strategies.every((s) => s === "markdown" || s === "line_window")).toBe( + true + ); + }); +}); diff --git a/packages/vscode-moss/test/config.test.ts b/packages/vscode-moss/test/config.test.ts new file mode 100644 index 00000000..345c23d6 --- /dev/null +++ b/packages/vscode-moss/test/config.test.ts @@ -0,0 +1,292 @@ +import { afterEach, describe, expect, it } from "vitest"; +import type { SecretStorage } from "vscode"; +import { + DEFAULT_QUERY_ALPHA, + MOSS_LEGACY_GLOBAL_PROJECT_KEY, + defaultIndexNameForFolder, + getMossConfig, + getMossLogVerbose, + resolveCredentialsForWorkspace, + resolveProjectKey, + resolveQueryAlpha, + workspaceCredentialsSecretKey, +} from "../src/config.js"; +import { + resetMossTestConfig, + setMossTestConfig, + Uri, + type WorkspaceFolder, +} from "./vscode-stub.js"; + +function memorySecrets(initial: Record = {}): SecretStorage { + const m = new Map(Object.entries(initial)); + return { + get: async (k) => m.get(k), + store: async (k, v) => { + m.set(k, v); + }, + delete: async (k) => { + m.delete(k); + }, + onDidChange: () => ({ dispose: () => {} }), + }; +} + +/** Seed workspace blob so getMossConfig resolves credentials without env. */ +function secretsWithWorkspaceCreds( + folder: WorkspaceFolder, + projectId: string, + projectKey: string +): SecretStorage { + const key = workspaceCredentialsSecretKey(folder); + return memorySecrets({ + [key]: JSON.stringify({ projectId, projectKey }), + }); +} + +describe("defaultIndexNameForFolder", () => { + it("sanitizes folder name into index segment", () => { + const f: WorkspaceFolder = { + uri: Uri.file("/x"), + name: "My Cool App!!!", + index: 0, + }; + expect(defaultIndexNameForFolder(f)).toBe("vscode-moss-my-cool-app"); + }); + + it("falls back when name sanitizes to empty", () => { + const f: WorkspaceFolder = { + uri: Uri.file("/x"), + name: "@@@", + index: 0, + }; + expect(defaultIndexNameForFolder(f)).toBe("vscode-moss-workspace"); + }); +}); + +describe("getMossLogVerbose", () => { + afterEach(() => { + resetMossTestConfig(); + }); + + it("is false by default", () => { + expect(getMossLogVerbose()).toBe(false); + }); + + it("is true when moss.logVerbose set", () => { + setMossTestConfig(undefined, { logVerbose: true }); + expect(getMossLogVerbose()).toBe(true); + }); +}); + +describe("resolveProjectKey", () => { + const prevKey = process.env.MOSS_PROJECT_KEY; + + afterEach(() => { + resetMossTestConfig(); + if (prevKey === undefined) delete process.env.MOSS_PROJECT_KEY; + else process.env.MOSS_PROJECT_KEY = prevKey; + }); + + it("prefers legacy global SecretStorage over MOSS_PROJECT_KEY", async () => { + process.env.MOSS_PROJECT_KEY = "env-key"; + const secrets = memorySecrets({ + [MOSS_LEGACY_GLOBAL_PROJECT_KEY]: "secret-key", + }); + expect(await resolveProjectKey(secrets)).toBe("secret-key"); + }); + + it("uses MOSS_PROJECT_KEY when no legacy secret", async () => { + process.env.MOSS_PROJECT_KEY = "env-only"; + const secrets = memorySecrets(); + expect(await resolveProjectKey(secrets)).toBe("env-only"); + }); + + it("returns undefined when nothing set", async () => { + delete process.env.MOSS_PROJECT_KEY; + const secrets = memorySecrets(); + expect(await resolveProjectKey(secrets)).toBeUndefined(); + }); +}); + +describe("resolveCredentialsForWorkspace", () => { + const prevId = process.env.MOSS_PROJECT_ID; + const prevKey = process.env.MOSS_PROJECT_KEY; + + afterEach(() => { + resetMossTestConfig(); + if (prevId === undefined) delete process.env.MOSS_PROJECT_ID; + else process.env.MOSS_PROJECT_ID = prevId; + if (prevKey === undefined) delete process.env.MOSS_PROJECT_KEY; + else process.env.MOSS_PROJECT_KEY = prevKey; + }); + + it("prefers workspace blob over legacy secret and env", async () => { + process.env.MOSS_PROJECT_ID = "env-pid"; + process.env.MOSS_PROJECT_KEY = "env-pkey"; + const ws = Uri.file("/alpha"); + const folder: WorkspaceFolder = { uri: ws, name: "alpha", index: 0 }; + const blobKey = workspaceCredentialsSecretKey(folder); + const secrets = memorySecrets({ + [blobKey]: JSON.stringify({ + projectId: "blob-pid", + projectKey: "blob-pkey", + }), + [MOSS_LEGACY_GLOBAL_PROJECT_KEY]: "legacy-key", + }); + const r = await resolveCredentialsForWorkspace(secrets, folder); + expect(r).toEqual({ projectId: "blob-pid", projectKey: "blob-pkey" }); + }); + + it("migrates legacy global key + MOSS_PROJECT_ID into workspace blob", async () => { + delete process.env.MOSS_PROJECT_KEY; + process.env.MOSS_PROJECT_ID = "m-pid"; + const ws = Uri.file("/migrate"); + const folder: WorkspaceFolder = { uri: ws, name: "migrate", index: 0 }; + const blobKey = workspaceCredentialsSecretKey(folder); + const secrets = memorySecrets({ + [MOSS_LEGACY_GLOBAL_PROJECT_KEY]: "legacy-k", + }); + const r = await resolveCredentialsForWorkspace(secrets, folder); + expect(r).toEqual({ projectId: "m-pid", projectKey: "legacy-k" }); + const stored = await secrets.get(blobKey); + expect(stored).toBe( + JSON.stringify({ projectId: "m-pid", projectKey: "legacy-k" }) + ); + }); + + it("uses env pair when no blob", async () => { + process.env.MOSS_PROJECT_ID = "eid"; + process.env.MOSS_PROJECT_KEY = "ekey"; + const ws = Uri.file("/envonly"); + const folder: WorkspaceFolder = { uri: ws, name: "envonly", index: 0 }; + const secrets = memorySecrets(); + const r = await resolveCredentialsForWorkspace(secrets, folder); + expect(r).toEqual({ projectId: "eid", projectKey: "ekey" }); + }); + + it("isolates credentials by workspace folder URI", async () => { + delete process.env.MOSS_PROJECT_ID; + delete process.env.MOSS_PROJECT_KEY; + const wsA = Uri.file("/proj-a"); + const wsB = Uri.file("/proj-b"); + const folderA: WorkspaceFolder = { uri: wsA, name: "a", index: 0 }; + const folderB: WorkspaceFolder = { uri: wsB, name: "b", index: 1 }; + const secrets = memorySecrets({ + [workspaceCredentialsSecretKey(folderA)]: JSON.stringify({ + projectId: "ida", + projectKey: "ka", + }), + [workspaceCredentialsSecretKey(folderB)]: JSON.stringify({ + projectId: "idb", + projectKey: "kb", + }), + }); + expect(await resolveCredentialsForWorkspace(secrets, folderA)).toEqual({ + projectId: "ida", + projectKey: "ka", + }); + expect(await resolveCredentialsForWorkspace(secrets, folderB)).toEqual({ + projectId: "idb", + projectKey: "kb", + }); + }); +}); + +describe("resolveQueryAlpha", () => { + it("defaults when missing or non-finite", () => { + expect(resolveQueryAlpha(undefined)).toBe(DEFAULT_QUERY_ALPHA); + expect(resolveQueryAlpha("x")).toBe(DEFAULT_QUERY_ALPHA); + expect(resolveQueryAlpha(Number.NaN)).toBe(DEFAULT_QUERY_ALPHA); + }); + + it("clamps to 0..1", () => { + expect(resolveQueryAlpha(-0.5)).toBe(0); + expect(resolveQueryAlpha(1.5)).toBe(1); + expect(resolveQueryAlpha(0)).toBe(0); + expect(resolveQueryAlpha(1)).toBe(1); + }); + + it("passes through in-range values", () => { + expect(resolveQueryAlpha(0.5)).toBe(0.5); + expect(resolveQueryAlpha(0.8)).toBe(0.8); + }); +}); + +describe("getMossConfig", () => { + afterEach(() => { + resetMossTestConfig(); + }); + + it("uses configured index name when set", async () => { + const ws = Uri.file("/repo"); + setMossTestConfig(ws.toString(), { + indexName: "my-custom-index", + }); + const folder: WorkspaceFolder = { uri: ws, name: "repo", index: 0 }; + const secrets = secretsWithWorkspaceCreds(folder, "pid", "pk"); + const c = await getMossConfig(secrets, folder); + expect(c.indexName).toBe("my-custom-index"); + expect(c.topK).toBe(10); + expect(c.alpha).toBe(DEFAULT_QUERY_ALPHA); + }); + + it("uses configured alpha when set", async () => { + const ws = Uri.file("/repo"); + setMossTestConfig(ws.toString(), { + alpha: 0.35, + }); + const folder: WorkspaceFolder = { uri: ws, name: "repo", index: 0 }; + const secrets = secretsWithWorkspaceCreds(folder, "pid", "pk"); + const c = await getMossConfig(secrets, folder); + expect(c.alpha).toBe(0.35); + }); + + it("defaults index name from folder when indexName empty", async () => { + const ws = Uri.file("/repo"); + setMossTestConfig(ws.toString(), { + indexName: "", + }); + const folder: WorkspaceFolder = { uri: ws, name: "alpha-beta", index: 0 }; + const secrets = secretsWithWorkspaceCreds(folder, "p", "k"); + const c = await getMossConfig(secrets, folder); + expect(c.indexName).toBe("vscode-moss-alpha-beta"); + }); + + it("defaults respectGitignore to true when unset", async () => { + const ws = Uri.file("/repo"); + setMossTestConfig(ws.toString(), {}); + const folder: WorkspaceFolder = { uri: ws, name: "r", index: 0 }; + const secrets = secretsWithWorkspaceCreds(folder, "p", "k"); + const c = await getMossConfig(secrets, folder); + expect(c.respectGitignore).toBe(true); + }); + + it("respectGitignore false when configured", async () => { + const ws = Uri.file("/repo"); + setMossTestConfig(ws.toString(), { + respectGitignore: false, + }); + const folder: WorkspaceFolder = { uri: ws, name: "r", index: 0 }; + const secrets = secretsWithWorkspaceCreds(folder, "p", "k"); + const c = await getMossConfig(secrets, folder); + expect(c.respectGitignore).toBe(false); + }); + + it("clamps invalid numeric settings to safe defaults or caps", async () => { + const ws = Uri.file("/repo"); + setMossTestConfig(ws.toString(), { + maxFileSizeBytes: -1, + topK: 9999, + chunkMaxLines: 0, + chunkOverlapLines: -5, + }); + const folder: WorkspaceFolder = { uri: ws, name: "r", index: 0 }; + const secrets = secretsWithWorkspaceCreds(folder, "p", "k"); + const c = await getMossConfig(secrets, folder); + expect(c.maxFileSizeBytes).toBe(1_048_576); + expect(c.topK).toBe(100); + expect(c.chunkMaxLines).toBe(100); + expect(c.chunkOverlapLines).toBe(12); + }); +}); diff --git a/packages/vscode-moss/test/mossQueryState.test.ts b/packages/vscode-moss/test/mossQueryState.test.ts new file mode 100644 index 00000000..8c2116a4 --- /dev/null +++ b/packages/vscode-moss/test/mossQueryState.test.ts @@ -0,0 +1,98 @@ +import { describe, expect, it, vi } from "vitest"; +import { + clearLocalIndexLoadState, + ensureLocalIndexLoaded, + notifySearchIndexStale, + registerSearchIndexStaleHandler, + type LocalIndexLoadState, +} from "../src/mossQueryState.js"; + +describe("ensureLocalIndexLoaded", () => { + it("loads once and records loaded index", async () => { + const loadIndex = vi.fn().mockResolvedValue(undefined); + const client = { loadIndex } as { loadIndex: (n: string) => Promise }; + const state: LocalIndexLoadState = {}; + await ensureLocalIndexLoaded(client as never, "idx-a", state); + expect(loadIndex).toHaveBeenCalledTimes(1); + expect(loadIndex).toHaveBeenCalledWith("idx-a"); + expect(state.loadedIndexName).toBe("idx-a"); + await ensureLocalIndexLoaded(client as never, "idx-a", state); + expect(loadIndex).toHaveBeenCalledTimes(1); + }); + + it("sets localLoadFailedIndex and skips further load attempts for that index", async () => { + const loadIndex = vi + .fn() + .mockRejectedValueOnce(new Error("network")) + .mockResolvedValue(undefined); + const client = { loadIndex } as { loadIndex: (n: string) => Promise }; + const state: LocalIndexLoadState = {}; + await expect( + ensureLocalIndexLoaded(client as never, "idx-b", state) + ).rejects.toThrow("network"); + expect(state.localLoadFailedIndex).toBe("idx-b"); + expect(state.loadedIndexName).toBeUndefined(); + await ensureLocalIndexLoaded(client as never, "idx-b", state); + expect(loadIndex).toHaveBeenCalledTimes(1); + }); + + it("still loads another index after a different index failed", async () => { + const loadIndex = vi + .fn() + .mockRejectedValueOnce(new Error("fail-a")) + .mockResolvedValue(undefined); + const client = { loadIndex } as { loadIndex: (n: string) => Promise }; + const state: LocalIndexLoadState = {}; + await expect( + ensureLocalIndexLoaded(client as never, "idx-a", state) + ).rejects.toThrow("fail-a"); + await ensureLocalIndexLoaded(client as never, "idx-b", state); + expect(loadIndex).toHaveBeenCalledTimes(2); + expect(state.loadedIndexName).toBe("idx-b"); + }); + + it("retries same index after clearLocalIndexLoadState", async () => { + const loadIndex = vi + .fn() + .mockRejectedValueOnce(new Error("x")) + .mockResolvedValue(undefined); + const client = { loadIndex } as { loadIndex: (n: string) => Promise }; + const state: LocalIndexLoadState = {}; + await expect( + ensureLocalIndexLoaded(client as never, "idx", state) + ).rejects.toThrow("x"); + clearLocalIndexLoadState(state); + await ensureLocalIndexLoaded(client as never, "idx", state); + expect(loadIndex).toHaveBeenCalledTimes(2); + expect(state.loadedIndexName).toBe("idx"); + }); +}); + +describe("clearLocalIndexLoadState", () => { + it("clears loaded and failure fields", () => { + const state: LocalIndexLoadState = { + loadedIndexName: "x", + localLoadFailedIndex: "x", + }; + clearLocalIndexLoadState(state); + expect(state.loadedIndexName).toBeUndefined(); + expect(state.localLoadFailedIndex).toBeUndefined(); + }); +}); + +describe("registerSearchIndexStaleHandler", () => { + it("notifies all registered handlers and supports dispose", () => { + const a = vi.fn(); + const b = vi.fn(); + const da = registerSearchIndexStaleHandler(a); + const db = registerSearchIndexStaleHandler(b); + notifySearchIndexStale(); + expect(a).toHaveBeenCalledTimes(1); + expect(b).toHaveBeenCalledTimes(1); + da.dispose(); + notifySearchIndexStale(); + expect(a).toHaveBeenCalledTimes(1); + expect(b).toHaveBeenCalledTimes(2); + db.dispose(); + }); +}); diff --git a/packages/vscode-moss/test/paths.test.ts b/packages/vscode-moss/test/paths.test.ts new file mode 100644 index 00000000..bb4f9321 --- /dev/null +++ b/packages/vscode-moss/test/paths.test.ts @@ -0,0 +1,117 @@ +import { describe, expect, it } from "vitest"; +import { Uri, type WorkspaceFolder } from "./vscode-stub.js"; +import { metadataToRange, metadataToUri } from "../src/paths.js"; + +function folder(fsPath: string, name = "ws"): WorkspaceFolder { + return { uri: Uri.file(fsPath), name, index: 0 }; +} + +describe("metadataToUri", () => { + it("joins path segments under workspace root", () => { + const roots = [folder("/projects/repo")]; + const u = metadataToUri(roots, { + path: "src/lib/foo.ts", + startLine: "1", + endLine: "5", + }); + expect(u).toBeDefined(); + expect(u!.fsPath.replace(/\\/g, "/")).toContain("src/lib/foo.ts"); + }); + + it("normalizes backslashes in metadata path", () => { + const roots = [folder("/ws")]; + const u = metadataToUri(roots, { + path: "pkg\\mod.go", + startLine: "1", + endLine: "1", + }); + expect(u).toBeDefined(); + expect(u!.fsPath.replace(/\\/g, "/")).toMatch(/pkg\/mod\.go$/); + }); + + it("uses workspaceFolderIndex for multi-root", () => { + const roots = [folder("/a", "A"), folder("/b", "B")]; + const u = metadataToUri(roots, { + path: "file.txt", + startLine: "1", + endLine: "1", + workspaceFolderIndex: "1", + }); + expect(u).toBeDefined(); + const expected = Uri.joinPath(roots[1]!.uri, "file.txt").toString(); + expect(u!.toString()).toBe(expected); + }); + + it("returns undefined for parent traversal", () => { + const roots = [folder("/ws")]; + expect( + metadataToUri(roots, { + path: "../etc/passwd", + startLine: "1", + endLine: "1", + }) + ).toBeUndefined(); + }); + + it("returns undefined for absolute-looking path", () => { + const roots = [folder("/ws")]; + expect( + metadataToUri(roots, { + path: "/abs/file.ts", + startLine: "1", + endLine: "1", + }) + ).toBeUndefined(); + }); + + it("returns undefined when folder index out of range", () => { + const roots = [folder("/only")]; + expect( + metadataToUri(roots, { + path: "x.ts", + startLine: "1", + endLine: "1", + workspaceFolderIndex: "9", + }) + ).toBeUndefined(); + }); + + it("returns undefined without workspace folders", () => { + expect( + metadataToUri(undefined, { + path: "a.ts", + startLine: "1", + endLine: "1", + }) + ).toBeUndefined(); + }); +}); + +describe("metadataToRange", () => { + it("maps 1-based inclusive lines to 0-based Range", () => { + const r = metadataToRange({ + path: "x", + startLine: "3", + endLine: "5", + }); + expect(r.start.line).toBe(2); + expect(r.end.line).toBe(4); + expect(r.start.character).toBe(0); + expect(r.end.character).toBe(Number.MAX_SAFE_INTEGER); + }); + + it("defaults missing startLine to line 1", () => { + const r = metadataToRange({ path: "x", startLine: "", endLine: "2" }); + expect(r.start.line).toBe(0); + }); + + it("repairs end before start", () => { + const r = metadataToRange({ + path: "x", + startLine: "10", + endLine: "3", + }); + expect(r.start.line).toBe(9); + expect(r.end.line).toBe(9); + }); +}); diff --git a/packages/vscode-moss/test/structureChunking.test.ts b/packages/vscode-moss/test/structureChunking.test.ts new file mode 100644 index 00000000..11ae8473 --- /dev/null +++ b/packages/vscode-moss/test/structureChunking.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, it } from "vitest"; +import { + markdownStructuralRanges, + packStructuralRanges, + treeSitterStructuralRanges, +} from "../src/structureChunking.js"; +import type { ChunkOptions } from "../src/chunkCore.js"; + +describe("markdownStructuralRanges", () => { + it("returns one range when there is no heading", () => { + const r = markdownStructuralRanges(["a", "b"]); + expect(r).toHaveLength(1); + expect(r[0]!.startLine).toBe(1); + expect(r[0]!.endLine).toBe(2); + }); + + it("splits on ATX headings after the first line", () => { + const r = markdownStructuralRanges(["intro", "## H", "body"]); + expect(r).toHaveLength(2); + expect(r[0]!.startLine).toBe(1); + expect(r[0]!.endLine).toBe(1); + expect(r[1]!.startLine).toBe(2); + expect(r[1]!.endLine).toBe(3); + }); +}); + +describe("packStructuralRanges", () => { + const opts: ChunkOptions = { + chunkMaxLines: 5, + chunkOverlapLines: 1, + maxCharsPerChunk: 200, + smallFileMaxLines: 50, + }; + + it("fills gaps between sections with line_window strategy", () => { + const lines = ["a", "b", "", "c", "d", "e"]; + const structural = [ + { startLine: 1, endLine: 2, extraMeta: { chunkStrategy: "markdown" } }, + { startLine: 4, endLine: 6, extraMeta: { chunkStrategy: "markdown" } }, + ]; + const docs = packStructuralRanges("x.md", lines, structural, opts); + const gapChunk = docs.find((d) => d.metadata.chunkStrategy === "line_window"); + expect(gapChunk).toBeDefined(); + expect(gapChunk!.text.trim()).toBe(""); + }); +}); + +describe("treeSitterStructuralRanges", () => { + it("returns multiple ranges for two top-level functions in TypeScript", async () => { + const src = `export function a() { + return 1; +} +export function b() { + return 2; +} +`; + const ranges = await treeSitterStructuralRanges(src, "typescript"); + expect(ranges).toBeDefined(); + expect(ranges!.length).toBeGreaterThanOrEqual(2); + }); + + it("groups consecutive imports", async () => { + const src = `import x from "a"; +import y from "b"; +export const z = 1; +`; + const ranges = await treeSitterStructuralRanges(src, "typescript"); + expect(ranges).toBeDefined(); + const importRanges = ranges!.filter( + (r) => r.extraMeta?.chunkStrategy === "ts_imports" + ); + expect(importRanges.length).toBe(1); + expect(importRanges[0]!.startLine).toBe(1); + expect(importRanges[0]!.endLine).toBeGreaterThanOrEqual(2); + }); + + it("returns multiple ranges for two top-level defs in Python", async () => { + const src = `import os + +def a(): + return 1 + +def b(): + return 2 +`; + const ranges = await treeSitterStructuralRanges(src, "python"); + expect(ranges).toBeDefined(); + expect(ranges!.length).toBeGreaterThanOrEqual(2); + }); + + it("returns multiple ranges for two functions in Rust", async () => { + const src = `use std::io; + +fn a() -> i32 { 1 } + +fn b() -> i32 { 2 } +`; + const ranges = await treeSitterStructuralRanges(src, "rust"); + expect(ranges).toBeDefined(); + expect(ranges!.length).toBeGreaterThanOrEqual(2); + }); +}); diff --git a/packages/vscode-moss/test/vscode-stub.ts b/packages/vscode-moss/test/vscode-stub.ts new file mode 100644 index 00000000..f9f82201 --- /dev/null +++ b/packages/vscode-moss/test/vscode-stub.ts @@ -0,0 +1,68 @@ +/** + * Minimal `vscode` surface for unit tests (Vitest resolves `vscode` here via alias). + * Supports `paths.ts`, `config.ts`, and any module that only needs Uri / Range / workspace config. + */ +import { URI, Utils } from "vscode-uri"; + +export class Position { + constructor( + public readonly line: number, + public readonly character: number + ) {} +} + +export class Range { + public readonly start: Position; + public readonly end: Position; + constructor(startLine: number, startChar: number, endLine: number, endChar: number) { + this.start = new Position(startLine, startChar); + this.end = new Position(endLine, endChar); + } +} + +export const Uri = { + file: (fsPath: string): URI => URI.file(fsPath), + joinPath: (base: URI, ...pathSegments: string[]): URI => + Utils.joinPath(base, ...pathSegments), +}; + +const mossConfigByScope = new Map>(); + +export function resetMossTestConfig(): void { + mossConfigByScope.clear(); +} + +/** Keys match `get("indexName")` etc. on the `moss` configuration section (no credential keys). */ +export function setMossTestConfig( + resourceUri: string | undefined, + values: Record +): void { + const key = resourceUri ?? "__global"; + const prev = mossConfigByScope.get(key) ?? {}; + mossConfigByScope.set(key, { ...prev, ...values }); +} + +function mergedMossConfig(resource?: { toString(): string }): Record { + const g = mossConfigByScope.get("__global") ?? {}; + if (!resource) return { ...g }; + const s = mossConfigByScope.get(resource.toString()) ?? {}; + return { ...g, ...s }; +} + +export const workspace = { + getConfiguration(section: string, resource?: { toString(): string }) { + if (section !== "moss") { + return { get: () => undefined }; + } + const data = mergedMossConfig(resource); + return { + get: (key: string) => data[key] as T, + }; + }, +}; + +export interface WorkspaceFolder { + readonly uri: URI; + readonly name: string; + readonly index: number; +} diff --git a/packages/vscode-moss/tsconfig.json b/packages/vscode-moss/tsconfig.json new file mode 100644 index 00000000..b1ee69c6 --- /dev/null +++ b/packages/vscode-moss/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "ES2022", + "strict": true, + "lib": ["ES2022"], + "skipLibCheck": true, + "noEmit": true + }, + "include": ["src/**/*.ts"] +} diff --git a/packages/vscode-moss/vitest.config.ts b/packages/vscode-moss/vitest.config.ts new file mode 100644 index 00000000..c7ec446a --- /dev/null +++ b/packages/vscode-moss/vitest.config.ts @@ -0,0 +1,17 @@ +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { defineConfig } from "vitest/config"; + +const root = path.dirname(fileURLToPath(import.meta.url)); + +export default defineConfig({ + test: { + environment: "node", + include: ["test/**/*.test.ts"], + }, + resolve: { + alias: { + vscode: path.resolve(root, "test/vscode-stub.ts"), + }, + }, +});