diff --git a/README.md b/README.md
index 2d3334a..32eb1ad 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-

+
Launch Android apps at warp speed
diff --git a/docs/docs/getting-started/installation.md b/docs/docs/getting-started/installation.md
index e40290b..7982083 100644
--- a/docs/docs/getting-started/installation.md
+++ b/docs/docs/getting-started/installation.md
@@ -442,6 +442,12 @@ See the [Kotlin installation section](#installing-kotlin-required-for-hot-reload
## Recommended Tools
+### JetStart Kotlin & Compose Snippets (Recommended)
+
+Speed up your development with our custom VS Code extension. It provides package-aware snippets and automatic imports for Kotlin and Compose.
+
+[**Install JetStart Extension**](./vscode-extension.md)
+
### Kotlin Language Server for VS Code
If you are developing your Android client using VS Code, we highly recommend installing the **Kotlin Language Server** extension for syntax highlighting, code completion, and diagnostics.
diff --git a/docs/docs/getting-started/vscode-extension.md b/docs/docs/getting-started/vscode-extension.md
new file mode 100644
index 0000000..4512059
--- /dev/null
+++ b/docs/docs/getting-started/vscode-extension.md
@@ -0,0 +1,119 @@
+---
+sidebar_position: 6
+title: VS Code Extension
+description: Speed up your development with the JetStart Kotlin & Compose Snippets extension
+---
+
+# JetStart VS Code Extension
+
+The **JetStart Kotlin & Compose Snippets** extension is designed to give Android developers a fast, React-like scaffolding experience directly in VS Code. It provides robust, package-aware, and import-aware snippets for Kotlin and Jetpack Compose.
+
+## Features
+
+- **π Smart Snippets**: Quick templates for Classes, ViewModels, Composables, Room Entities, and more.
+- **π¦ Package Awareness**: Automatically detects and inserts the correct `package` declaration based on your folder structure.
+- **π₯ Auto-Imports**: Automatically adds required imports to the top of the file when you use a snippet.
+- **π Compose Import Helper**: Quick suggestions for missing Compose and AndroidX imports.
+
+---
+
+## Installation
+
+Since the extension is currently in beta, you can install it directly by downloading the `.vsix` package.
+
+### 1. Download the Extension
+Download the latest version of the JetStart extension:
+
+
+ π₯ Download JetStart VS Code Extension (.vsix)
+
+
+### 2. Install in VS Code
+1. Open **Visual Studio Code**.
+2. Go to the **Extensions** view (`Ctrl+Shift+X`).
+3. Click the **More Actions** (...) menu in the top-right corner of the Extensions bar.
+4. Select **Install from VSIX...**
+5. Locate and select the `jetstart-kotlin-snippets.vsix` file you just downloaded.
+6. Restart VS Code if prompted.
+
+---
+
+## Common Snippets
+
+Type these prefixes in any `.kt` file to trigger the snippets:
+
+| Prefix | What you get |
+|--------|-------------|
+| `ktc` | Class with auto-detected package name |
+| `ktdc` | Data class |
+| `ktsc` | Sealed class (Success/Error/Loading) |
+| `ktec` | Enum class |
+| `ktvm` | ViewModel + StateFlow + coroutine scope |
+| `kthiltvm` | Hilt ViewModel + @Inject |
+| `ktrep` | Repository class |
+| `ktent` | Room @Entity |
+| `ktdao` | Room @Dao |
+| `ktdb` | Room Database singleton |
+| `ktcf` | @Composable function |
+| `ktcfs` | @Composable + remember state |
+| `ktprev` | @Preview composable |
+| `ktscaffold` | Full Scaffold + TopAppBar + FAB |
+| `ktlazycol` | LazyColumn with items |
+| `ktlazyr` | LazyRow with items |
+| `ktlazysgrid` | LazyVerticalStaggeredGrid |
+| `ktcard` | Material3 Card |
+| `ktrow` / `ktcol` | Row / Column |
+| `ktalertd` | AlertDialog |
+| `ktbottomsheet` | ModalBottomSheet |
+| `kttab` | TopAppBar |
+| `ktnav` | NavHost setup |
+| `ktstate` | `var x by remember { mutableStateOf(...) }` |
+| `ktsflow` | MutableStateFlow + StateFlow pair |
+| `ktcollect` | collectAsState() |
+| `ktlaunch` / `ktsideef` / `ktdisposable` / `ktderived` | Effects |
+| `ktcoro` / `ktio` / `ktasync` | Coroutines |
+| `ktfun` / `ktsfun` / `ktef` / `ktlambda` | Functions |
+| `ktwhen` / `ktwhenresult` | when expressions |
+
+## Auto-features
+
+- **Smart Package Insertion**: Open a new empty `.kt` file and the package name is auto-inserted based on the directory structure.
+- **Instant Auto-Imports**: Type an identifier like `mutableStateOf` and the import suggestion appears immediately.
+- **Deep Support**: Works for 150+ Compose/Kotlin identifiers across Room, Hilt, Navigation, Coroutines, and more.
+
+---
+
+## How it Works (and Automation)
+
+A common question is: **Why use a manual import map instead of an official source?**
+
+Unlike Android Studio, which builds a heavy local index of all your dependencies (often consuming significant RAM), JetStart's VS Code extension is designed for **instant, zero-latency feedback**.
+
+1. **The "Official" Way**: Standard IDEs use the Language Server Protocol (LSP) to scan your Gradle dependencies. While powerful, this can be slow and often fails in complex environments.
+2. **The JetStart Way**: We use a curated high-performance map of over 150 common Compose and Kotlin identifiers. This gives you *instant* suggestions the moment you type, without waiting for a background indexer.
+
+### Automating Updates
+To keep this map up-to-date without manual effort, we are working on a **Sync Runner** script that will:
+- Automatically scan the `build.gradle` classpath.
+- Extract public identifiers from AndroidX and Kotlin libraries.
+- Regenerate the mapping files for the extension.
+
+This ensures you always have the latest Material3 and Compose symbols without the performance cost of a full IDE indexer.
+
+---
+
+## Recommended Configuration
+
+For the best experience, we recommend using this extension alongside other Kotlin tools for full IDE features like go-to-definition and linting.
+
+### Complementary Extensions
+
+JetStart's extension works perfectly alongside the following popular Kotlin extensions:
+
+- **[Kotlin Language Server](https://github.com/Kotlin/kotlin-lsp)**: Provides the core IDE engine (diagnostics, formatting, etc.).
+- **[Kotlin on VSCode (sethjones)](https://marketplace.visualstudio.com/items?itemName=sethjones.kotlin-on-vscode)**: A popular extension pack that bundles essential Kotlin tools.
+
+**Why use JetStart's extension?**
+While the extensions above provide great language support, JetStart's extension is uniquely focused on **Android/Compose speed**:
+- **Instant Imports**: No waiting for the Language Server to index; imports are added instantly.
+- **Android-First Snippets**: Tailored templates for M3 Scaffold, ViewModels, and Room that aren't available in generic Kotlin packs.
diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts
index b648117..de20c12 100644
--- a/docs/docusaurus.config.ts
+++ b/docs/docusaurus.config.ts
@@ -3,8 +3,8 @@ import type {Config} from '@docusaurus/types';
import type * as Preset from '@docusaurus/preset-classic';
const config: Config = {
- title: 'JetStart',
- tagline: 'Build Android apps faster than ever with instant hot reload.',
+ title: 'JetStart | Instant Hot Reload for Android & Jetpack Compose',
+ tagline: 'The fastest way to develop Android apps with sub-100ms hot reload in any emulator.',
favicon: 'img/logos/logo.png',
// Set the production url of your site here
@@ -87,7 +87,7 @@ const config: Config = {
],
themeConfig: {
- image: 'img/jetstart-social-card.png',
+ image: 'img/socials/jetstart-social-card.png',
navbar: {
title: 'JetStart',
logo: {
diff --git a/docs/sidebars.ts b/docs/sidebars.ts
index 79e58a2..ec908f9 100644
--- a/docs/sidebars.ts
+++ b/docs/sidebars.ts
@@ -11,6 +11,7 @@ const sidebars: SidebarsConfig = {
'getting-started/installation',
'getting-started/quick-start',
'getting-started/system-requirements',
+ 'getting-started/vscode-extension',
'getting-started/troubleshooting-setup',
],
},
diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css
index 7b00d2f..de5ab3c 100644
--- a/docs/src/css/custom.css
+++ b/docs/src/css/custom.css
@@ -50,6 +50,9 @@
--ifm-menu-color: #FFFFFF;
}
+a{
+ text-decoration: none !important;
+}
/* Specific override for Docusaurus dark footer style */
.footer--dark {
--ifm-footer-background-color: #222222;
diff --git a/docs/static/downloads/jetstart-kotlin-snippets.vsix b/docs/static/downloads/jetstart-kotlin-snippets.vsix
new file mode 100644
index 0000000..3a8ffcd
Binary files /dev/null and b/docs/static/downloads/jetstart-kotlin-snippets.vsix differ
diff --git a/docs/static/img/logos/logo.png b/docs/static/img/logos/logo.png
index 2741be7..adcac0f 100644
Binary files a/docs/static/img/logos/logo.png and b/docs/static/img/logos/logo.png differ
diff --git a/docs/static/img/socials/jetstart-social-card.png b/docs/static/img/socials/jetstart-social-card.png
new file mode 100644
index 0000000..48b87e3
Binary files /dev/null and b/docs/static/img/socials/jetstart-social-card.png differ
diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts
index 83e501c..2513644 100644
--- a/packages/cli/src/commands/build.ts
+++ b/packages/cli/src/commands/build.ts
@@ -126,7 +126,16 @@ function runGradle(gradle: string, args: string[], cwd: string): Promise<{ code:
return new Promise((resolve) => {
console.log();
log('[Gradle] ' + path.basename(gradle) + ' ' + args.join(' '));
- const proc = spawn(gradle, args, { cwd, shell: true, env: process.env });
+
+ const isWin = process.platform === 'win32';
+ const spawnCmd = isWin ? 'cmd.exe' : gradle;
+ const spawnArgs = isWin ? ['/c', gradle, ...args] : args;
+
+ const proc = spawn(spawnCmd, spawnArgs, {
+ cwd,
+ shell: false,
+ env: process.env
+ });
proc.stdout.on('data', (d: Buffer) => process.stdout.write(d));
proc.stderr.on('data', (d: Buffer) => process.stderr.write(d));
proc.on('close', (code) => resolve({ code: code ?? 1 }));
diff --git a/packages/cli/src/commands/clean.ts b/packages/cli/src/commands/clean.ts
index 68a2537..7aa0c6b 100644
--- a/packages/cli/src/commands/clean.ts
+++ b/packages/cli/src/commands/clean.ts
@@ -111,14 +111,20 @@ export async function cleanCommand(options: CleanOptions = {}) {
// Graceful Gradle daemon stop
const daemonSpinner = startSpinner('Stopping Gradle daemons gracefully...');
const gradle = findGradle(projectPath);
- if (gradle) {
- try {
- spawnSync(gradle, ['--stop'], {
- cwd: projectPath, shell: true,
- encoding: 'utf8', timeout: 12000,
- });
- } catch { /* ignore */ }
- }
+ if (gradle) {
+ try {
+ const isWin = process.platform === 'win32';
+ const spawnCmd = isWin ? 'cmd.exe' : gradle;
+ const spawnArgs = isWin ? ['/c', gradle, '--stop'] : ['--stop'];
+
+ spawnSync(spawnCmd, spawnArgs, {
+ cwd: projectPath,
+ shell: false,
+ encoding: 'utf8',
+ timeout: 12000,
+ });
+ } catch { /* ignore */ }
+ }
stopSpinner(daemonSpinner, true, 'Gradle daemons stopped');
// Kill ALL java.exe (Gradle + VS Code language servers)
diff --git a/packages/cli/src/utils/template.ts b/packages/cli/src/utils/template.ts
index 1481e1c..4bc1ada 100644
--- a/packages/cli/src/utils/template.ts
+++ b/packages/cli/src/utils/template.ts
@@ -167,12 +167,15 @@ async function generateGradleWrapper(projectPath: string): Promise
{
return new Promise((resolve) => {
const gradleCmd = process.platform === 'win32' ? 'gradle.bat' : 'gradle';
- const gradleProcess = spawn(gradleCmd, ['wrapper', '--gradle-version', '8.2'], {
+ const spawnArgs = process.platform === 'win32'
+ ? ['/c', gradleCmd, 'wrapper', '--gradle-version', '8.2']
+ : ['wrapper', '--gradle-version', '8.2'];
+ const spawnCmd = process.platform === 'win32' ? 'cmd.exe' : gradleCmd;
+
+ const gradleProcess = spawn(spawnCmd, spawnArgs, {
cwd: projectPath,
- // On Windows, .bat files need a shell. On other platforms, we can run 'gradle' directly.
- // We use shell: true only on Windows to avoid the security warning on other platforms
- // and ensure .bat files execute.
- shell: process.platform === 'win32',
+ // Avoid shell: true to prevent [DEP0190] warning on newer Node versions
+ shell: false,
});
// Timeout after 30 seconds
diff --git a/packages/cli/template/base/gradle.properties b/packages/cli/template/base/gradle.properties
index 7765f9a..ea78917 100644
--- a/packages/cli/template/base/gradle.properties
+++ b/packages/cli/template/base/gradle.properties
@@ -1,11 +1,14 @@
# Gradle configuration
-org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
+org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -Dhttps.protocols=TLSv1.2,TLSv1.3
org.gradle.daemon=true
org.gradle.daemon.idletimeout=300000
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true
+# Force TLS 1.2/1.3 for environments with older JDKs or restrictive proxies
+systemProp.https.protocols=TLSv1.2,TLSv1.3
+
# Android
android.useAndroidX=true
android.enableJetifier=false
diff --git a/packages/extension/.vscodeignore b/packages/extension/.vscodeignore
new file mode 100644
index 0000000..6d0dddc
--- /dev/null
+++ b/packages/extension/.vscodeignore
@@ -0,0 +1,8 @@
+.vscode/**
+.vscode-test/**
+src/**
+.gitignore
+tsconfig.json
+**/*.map
+node_modules/**
+!node_modules/.bin
diff --git a/packages/extension/LICENSE b/packages/extension/LICENSE
new file mode 100644
index 0000000..9af7885
--- /dev/null
+++ b/packages/extension/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 JetStart
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/packages/extension/README.md b/packages/extension/README.md
new file mode 100644
index 0000000..90e381c
--- /dev/null
+++ b/packages/extension/README.md
@@ -0,0 +1,49 @@
+# JetStart Kotlin & Compose Snippets
+
+Robust, package-aware, and import-aware snippets for Kotlin and Jetpack Compose. Built specifically for Android developers looking for a fast, React-like scaffold experience.
+
+
+
+
+## Features
+
+- **π Instant Scaffolding**: Generate ViewModels, Repositories, Room Entities, and Composables in seconds.
+- **π¦ Package Aware**: Automatically detects the correct package name based on your project structure.
+- **β¨ Smart Imports**: Adds necessary imports to the top of the file automaticallyβno more manual importing!
+- **π¨ Compose Optimized**: Includes Material3-ready snippets and common UI patterns.
+
+## Available Snippets
+
+### Classes & Core
+- `ktc` β Kotlin Class
+- `ktdc` β Data Class
+- `ktsc` β Sealed Class
+- `ktec` β Enum Class
+- `ktobj` β Object
+- `ktint` β Interface
+
+### Android Architecture
+- `ktvm` β ViewModel with StateFlow
+- `ktrep` β Repository with Coroutines
+- `kthiltvm` β Hilt-injected ViewModel
+
+### Jetpack Compose
+- `ktcf` β Composable Function
+- `ktcfs` β Composable with local state
+- `ktprev` β Composable Preview
+- `ktscaffold` β Material3 Scaffold
+- `ktlazycol` / `ktlazyr` β Lazy List layouts
+- `ktcard`, `ktrow`, `ktcol` β Common UI components
+
+### Room Database
+- `ktent` β Room Entity
+- `ktdao` β Room DAO
+- `ktdb` β Room Database
+
+## Commands
+
+- **JetStart: Insert Package Declaration**: Manually insert the detected package line into a Kotlin file.
+
+## License
+
+MIT
diff --git a/packages/extension/images/logo.png b/packages/extension/images/logo.png
new file mode 100644
index 0000000..adcac0f
Binary files /dev/null and b/packages/extension/images/logo.png differ
diff --git a/packages/extension/images/social-card.png b/packages/extension/images/social-card.png
new file mode 100644
index 0000000..48b87e3
Binary files /dev/null and b/packages/extension/images/social-card.png differ
diff --git a/packages/extension/package-lock.json b/packages/extension/package-lock.json
new file mode 100644
index 0000000..cde0d29
--- /dev/null
+++ b/packages/extension/package-lock.json
@@ -0,0 +1,2481 @@
+{
+ "name": "jetstart-kotlin-snippets",
+ "version": "2.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "jetstart-kotlin-snippets",
+ "version": "2.0.1",
+ "license": "MIT",
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "@types/vscode": "^1.85.0",
+ "@vscode/vsce": "^2.22.0",
+ "typescript": "^5.3.0"
+ },
+ "engines": {
+ "vscode": "^1.85.0"
+ }
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.6.1.tgz",
+ "integrity": "sha512-Ylmp8yngH7YRLV5mA1aF4CNS6WsJTPbVXaA0Tb1x1Gv/J3BM3hE4Q7nDaf7dRfU00FcxDBBudTjqlpH74ZSsgw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@azure/msal-common": "16.4.0"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@azure/msal-common": {
+ "version": "16.4.0",
+ "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.4.0.tgz",
+ "integrity": "sha512-twXt09PYtj1PffNNIAzQlrBd0DS91cdA6i1gAfzJ6BnPM4xNk5k9q/5xna7jLIjU3Jnp0slKYtucshGM8OGNAw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/@azure/msal-node": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.1.1.tgz",
+ "integrity": "sha512-71grXU6+5hl+3CL3joOxlj/AW6rmhthuTlG0fRqsTrhPArQBpZuUFzCIlKOGdcafLUa/i1hBdV78ZxJdlvRA+g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@azure/msal-common": "16.4.0",
+ "jsonwebtoken": "^9.0.0",
+ "uuid": "^8.3.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "20.19.37",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.37.tgz",
+ "integrity": "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "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/@vscode/vsce": {
+ "version": "2.32.0",
+ "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.32.0.tgz",
+ "integrity": "sha512-3EFJfsgrSftIqt3EtdRcAygy/OJ3hstyI1cDmIgkU9CFZW5C+3djr6mfosndCUqcVYuyjmxOK1xmFp/Bq7+NIg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@azure/identity": "^4.1.0",
+ "@vscode/vsce-sign": "^2.0.0",
+ "azure-devops-node-api": "^12.5.0",
+ "chalk": "^2.4.2",
+ "cheerio": "^1.0.0-rc.9",
+ "cockatiel": "^3.1.2",
+ "commander": "^6.2.1",
+ "form-data": "^4.0.0",
+ "glob": "^7.0.6",
+ "hosted-git-info": "^4.0.2",
+ "jsonc-parser": "^3.2.0",
+ "leven": "^3.1.0",
+ "markdown-it": "^12.3.2",
+ "mime": "^1.3.4",
+ "minimatch": "^3.0.3",
+ "parse-semver": "^1.1.1",
+ "read": "^1.0.7",
+ "semver": "^7.5.2",
+ "tmp": "^0.2.1",
+ "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": ">= 16"
+ },
+ "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/ansi-styles": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/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/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/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/buffer": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+ "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.1.13"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "run-applescript": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/call-bound": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+ "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cheerio": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz",
+ "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cheerio-select": "^2.1.0",
+ "dom-serializer": "^2.0.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.2.2",
+ "encoding-sniffer": "^0.2.1",
+ "htmlparser2": "^10.1.0",
+ "parse5": "^7.3.0",
+ "parse5-htmlparser2-tree-adapter": "^7.1.0",
+ "parse5-parser-stream": "^7.1.2",
+ "undici": "^7.19.0",
+ "whatwg-mimetype": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=20.18.1"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/cheerio?sponsor=1"
+ }
+ },
+ "node_modules/cheerio-select": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz",
+ "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-select": "^5.1.0",
+ "css-what": "^6.1.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+ "dev": true,
+ "license": "ISC",
+ "optional": true
+ },
+ "node_modules/cockatiel": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz",
+ "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "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": "6.2.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
+ "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "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/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-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/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/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-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/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.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/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/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.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "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": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "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": "ISC",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "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/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "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/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "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"
+ },
+ "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-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-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/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/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": "3.0.3",
+ "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
+ "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "uc.micro": "^1.0.1"
+ }
+ },
+ "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/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/markdown-it": {
+ "version": "12.3.2",
+ "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz",
+ "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1",
+ "entities": "~2.1.0",
+ "linkify-it": "^3.0.1",
+ "mdurl": "^1.0.1",
+ "uc.micro": "^1.0.5"
+ },
+ "bin": {
+ "markdown-it": "bin/markdown-it.js"
+ }
+ },
+ "node_modules/markdown-it/node_modules/entities": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
+ "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "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": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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/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/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/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",
+ "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/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-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "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/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/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/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/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/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/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/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/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/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/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/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/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/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/tar-fs": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+ "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "chownr": "^1.1.1",
+ "mkdirp-classic": "^0.5.2",
+ "pump": "^3.0.0",
+ "tar-stream": "^2.1.4"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+ "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "bl": "^4.0.3",
+ "end-of-stream": "^1.4.1",
+ "fs-constants": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/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/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/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": "1.0.6",
+ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==",
+ "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.6",
+ "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.6.tgz",
+ "integrity": "sha512-Xi4agocCbRzt0yYMZGMA6ApD7gvtUFaxm4ZmeacWI4cZxaF6C+8I8QfofC20NAePiB/IcvZmzkJ7XPa471AEtA==",
+ "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/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/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/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"
+ },
+ "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/extension/package.json b/packages/extension/package.json
new file mode 100644
index 0000000..372b328
--- /dev/null
+++ b/packages/extension/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "jetstart-kotlin-snippets",
+ "displayName": "JetStart Kotlin & Compose Snippets",
+ "description": "Robust snippets for Kotlin and Jetpack Compose β package-aware, import-aware, built for Android developers.",
+ "version": "2.0.5",
+ "publisher": "jetstart",
+ "engines": {
+ "vscode": "^1.85.0"
+ },
+ "categories": [
+ "Snippets",
+ "Programming Languages",
+ "Other"
+ ],
+ "keywords": [
+ "kotlin",
+ "jetpack compose",
+ "android",
+ "snippets",
+ "material3",
+ "jetstart"
+ ],
+ "activationEvents": [
+ "onLanguage:kotlin"
+ ],
+ "main": "./dist/extension.js",
+ "icon": "images/logo.png",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/dev-phantom/jetstart.git",
+ "directory": "packages/extension"
+ },
+ "contributes": {
+ "commands": [
+ {
+ "command": "jetstartSnippets.insertPackage",
+ "title": "JetStart: Insert Package Declaration",
+ "category": "JetStart"
+ }
+ ],
+ "keybindings": [
+ {
+ "command": "jetstartSnippets.insertPackage",
+ "key": "ctrl+shift+p ctrl+shift+k",
+ "when": "editorLangId == kotlin"
+ }
+ ]
+ },
+ "scripts": {
+ "vscode:prepublish": "npm run compile",
+ "compile": "tsc -p ./",
+ "watch": "tsc -watch -p ./",
+ "package": "vsce package --no-dependencies",
+ "build": "npm run compile"
+ },
+ "devDependencies": {
+ "@types/node": "^20.0.0",
+ "@types/vscode": "^1.85.0",
+ "@vscode/vsce": "^2.22.0",
+ "typescript": "^5.3.0"
+ },
+ "license": "MIT"
+}
diff --git a/packages/extension/src/extension.ts b/packages/extension/src/extension.ts
new file mode 100644
index 0000000..f0faaad
--- /dev/null
+++ b/packages/extension/src/extension.ts
@@ -0,0 +1,115 @@
+import * as vscode from 'vscode';
+import { SNIPPETS } from './snippets/definitions';
+import { ImportCompletionProvider } from './importProvider';
+import { classNameFromFile, getPackageInfo } from './packageDetector';
+import { getImportEdits } from './importUtils';
+
+export function activate(context: vscode.ExtensionContext) {
+ // Snippet completion provider
+
+
+ // Registers every snippet prefix as a CompletionItem in .kt files.
+ const snippetProvider = vscode.languages.registerCompletionItemProvider(
+ { language: 'kotlin', scheme: 'file' },
+ {
+ provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
+ const lineText = document.lineAt(position).text;
+ const linePrefix = lineText.slice(0, position.character);
+
+ // Don't trigger inside import/package lines
+ if (/^\s*(import|package)\s/.test(linePrefix)) { return []; }
+
+ const className = classNameFromFile(document);
+ const ctx = { className };
+
+ return SNIPPETS.map(def => {
+ const item = new vscode.CompletionItem(
+ def.prefix,
+ vscode.CompletionItemKind.Snippet,
+ );
+ item.label = def.label;
+ item.detail = def.detail;
+ item.documentation = new vscode.MarkdownString(def.documentation);
+ item.insertText = new vscode.SnippetString(def.body(ctx));
+ item.filterText = def.prefix;
+ item.sortText = '0' + def.prefix; // always sort to top
+
+ // Add imports to the top of the file
+ if (def.imports) {
+ item.additionalTextEdits = getImportEdits(document, def.imports);
+ }
+
+ return item;
+ });
+ },
+ },
+ // Trigger on any character β lets you type 'kt' and see suggestions
+ );
+
+ // Import auto-complete provider
+ const importProvider = vscode.languages.registerCompletionItemProvider(
+ { language: 'kotlin', scheme: 'file' },
+ new ImportCompletionProvider(),
+ '.', // also trigger on dot for Icons.Default etc.
+ );
+
+ // Command: Insert Package Declaration
+ const insertPkgCmd = vscode.commands.registerCommand(
+ 'jetstartSnippets.insertPackage',
+ async () => {
+ const editor = vscode.window.activeTextEditor;
+ if (!editor || editor.document.languageId !== 'kotlin') {
+ vscode.window.showWarningMessage('JetStart: Open a Kotlin file first.');
+ return;
+ }
+
+ const { hasPackage, packageName } = getPackageInfo(editor.document);
+
+ if (hasPackage) {
+ vscode.window.showInformationMessage('JetStart: Package already declared.');
+ return;
+ }
+
+ const pkg = packageName
+ ?? await vscode.window.showInputBox({
+ prompt: 'Enter package name (e.g. com.example.app.ui)',
+ placeHolder: 'com.example.app.ui',
+ });
+
+ if (!pkg) { return; }
+
+ await editor.edit((eb: vscode.TextEditorEdit) => {
+ eb.insert(new vscode.Position(0, 0), `package ${pkg}\n\n`);
+ });
+ },
+ );
+
+ // Auto-insert package on new .kt file
+ // When a brand-new empty .kt file is opened, auto-insert the package line.
+ const onOpen = vscode.workspace.onDidOpenTextDocument(async (doc) => {
+ if (doc.languageId !== 'kotlin') { return; }
+ if (doc.getText().trim().length > 0) { return; } // not empty
+
+ const { hasPackage, packageName } = getPackageInfo(doc);
+ if (hasPackage || !packageName) { return; }
+
+ // Wait a tick for the editor to attach
+ await new Promise(r => setTimeout(r, 80));
+ const editor = vscode.window.visibleTextEditors.find(
+ (e: vscode.TextEditor) => e.document.uri.toString() === doc.uri.toString(),
+ );
+ if (!editor) { return; }
+
+ // Insert as snippet so user can tab through if needed
+ await editor.insertSnippet(
+ new vscode.SnippetString(`package ${packageName}\n\n$0`),
+ new vscode.Position(0, 0),
+ );
+ });
+
+ context.subscriptions.push(snippetProvider, importProvider, insertPkgCmd, onOpen);
+
+ console.log('JetStart Kotlin & Compose Snippets activated β
');
+}
+
+export function deactivate() {}
diff --git a/packages/extension/src/importProvider.ts b/packages/extension/src/importProvider.ts
new file mode 100644
index 0000000..4218190
--- /dev/null
+++ b/packages/extension/src/importProvider.ts
@@ -0,0 +1,287 @@
+
+import * as vscode from 'vscode';
+import { findImportInsertLine } from './importUtils';
+
+// Map of identifier β fully qualified import
+export const IMPORT_MAP: Record = {
+ // Compose Runtime
+ mutableStateOf: ['androidx.compose.runtime.mutableStateOf'],
+ mutableIntStateOf: ['androidx.compose.runtime.mutableIntStateOf'],
+ mutableLongStateOf: ['androidx.compose.runtime.mutableLongStateOf'],
+ mutableFloatStateOf: ['androidx.compose.runtime.mutableFloatStateOf'],
+ remember: ['androidx.compose.runtime.remember'],
+ rememberSaveable: ['androidx.compose.runtime.saveable.rememberSaveable'],
+ derivedStateOf: ['androidx.compose.runtime.derivedStateOf'],
+ produceState: ['androidx.compose.runtime.produceState'],
+ snapshotFlow: ['androidx.compose.runtime.snapshotFlow'],
+ LaunchedEffect: ['androidx.compose.runtime.LaunchedEffect'],
+ SideEffect: ['androidx.compose.runtime.SideEffect'],
+ DisposableEffect: ['androidx.compose.runtime.DisposableEffect'],
+ collectAsState: ['androidx.compose.runtime.collectAsState'],
+ rememberCoroutineScope: ['androidx.compose.runtime.rememberCoroutineScope'],
+
+ // Compose Material3
+ Scaffold: ['androidx.compose.material3.Scaffold'],
+ TopAppBar: ['androidx.compose.material3.TopAppBar'],
+ Text: ['androidx.compose.material3.Text'],
+ Button: ['androidx.compose.material3.Button'],
+ TextButton: ['androidx.compose.material3.TextButton'],
+ OutlinedButton: ['androidx.compose.material3.OutlinedButton'],
+ FilledTonalButton: ['androidx.compose.material3.FilledTonalButton'],
+ ElevatedButton: ['androidx.compose.material3.ElevatedButton'],
+ IconButton: ['androidx.compose.material3.IconButton'],
+ FloatingActionButton: ['androidx.compose.material3.FloatingActionButton'],
+ ExtendedFloatingActionButton: ['androidx.compose.material3.ExtendedFloatingActionButton'],
+ Card: ['androidx.compose.material3.Card'],
+ ElevatedCard: ['androidx.compose.material3.ElevatedCard'],
+ OutlinedCard: ['androidx.compose.material3.OutlinedCard'],
+ AlertDialog: ['androidx.compose.material3.AlertDialog'],
+ ModalBottomSheet: ['androidx.compose.material3.ModalBottomSheet'],
+ rememberModalBottomSheetState: ['androidx.compose.material3.rememberModalBottomSheetState'],
+ NavigationBar: ['androidx.compose.material3.NavigationBar'],
+ NavigationBarItem: ['androidx.compose.material3.NavigationBarItem'],
+ OutlinedTextField: ['androidx.compose.material3.OutlinedTextField'],
+ TextField: ['androidx.compose.material3.TextField'],
+ SearchBar: ['androidx.compose.material3.SearchBar'],
+ Surface: ['androidx.compose.material3.Surface'],
+ MaterialTheme: ['androidx.compose.material3.MaterialTheme'],
+ Divider: ['androidx.compose.material3.HorizontalDivider'],
+ HorizontalDivider: ['androidx.compose.material3.HorizontalDivider'],
+ VerticalDivider: ['androidx.compose.material3.VerticalDivider'],
+ Switch: ['androidx.compose.material3.Switch'],
+ Checkbox: ['androidx.compose.material3.Checkbox'],
+ RadioButton: ['androidx.compose.material3.RadioButton'],
+ Slider: ['androidx.compose.material3.Slider'],
+ CircularProgressIndicator: ['androidx.compose.material3.CircularProgressIndicator'],
+ LinearProgressIndicator: ['androidx.compose.material3.LinearProgressIndicator'],
+ AssistChip: ['androidx.compose.material3.AssistChip'],
+ FilterChip: ['androidx.compose.material3.FilterChip'],
+ SuggestionChip: ['androidx.compose.material3.SuggestionChip'],
+ DropdownMenu: ['androidx.compose.material3.DropdownMenu'],
+ DropdownMenuItem: ['androidx.compose.material3.DropdownMenuItem'],
+ Icon: ['androidx.compose.material3.Icon'],
+ Badge: ['androidx.compose.material3.Badge'],
+ BadgedBox: ['androidx.compose.material3.BadgedBox'],
+ Snackbar: ['androidx.compose.material3.Snackbar'],
+ SnackbarHost: ['androidx.compose.material3.SnackbarHost'],
+ rememberSnackbarHostState: ['androidx.compose.material3.rememberSnackbarHostState'],
+ ExperimentalMaterial3Api: ['androidx.compose.material3.ExperimentalMaterial3Api'],
+ CardDefaults: ['androidx.compose.material3.CardDefaults'],
+ TextFieldDefaults: ['androidx.compose.material3.TextFieldDefaults'],
+ TopAppBarDefaults: ['androidx.compose.material3.TopAppBarDefaults'],
+
+ // Compose Foundation Layout
+ Column: ['androidx.compose.foundation.layout.Column'],
+ Row: ['androidx.compose.foundation.layout.Row'],
+ Box: ['androidx.compose.foundation.layout.Box'],
+ Spacer: ['androidx.compose.foundation.layout.Spacer'],
+ fillMaxSize: ['androidx.compose.foundation.layout.fillMaxSize'],
+ fillMaxWidth: ['androidx.compose.foundation.layout.fillMaxWidth'],
+ fillMaxHeight: ['androidx.compose.foundation.layout.fillMaxHeight'],
+ padding: ['androidx.compose.foundation.layout.padding'],
+ PaddingValues: ['androidx.compose.foundation.layout.PaddingValues'],
+ Arrangement: ['androidx.compose.foundation.layout.Arrangement'],
+ WindowInsets: ['androidx.compose.foundation.layout.WindowInsets'],
+ size: ['androidx.compose.foundation.layout.size'],
+ width: ['androidx.compose.foundation.layout.width'],
+ height: ['androidx.compose.foundation.layout.height'],
+ wrapContentSize: ['androidx.compose.foundation.layout.wrapContentSize'],
+ offset: ['androidx.compose.foundation.layout.offset'],
+
+ // Compose Foundation Scrolling
+ verticalScroll: ['androidx.compose.foundation.verticalScroll'],
+ horizontalScroll: ['androidx.compose.foundation.horizontalScroll'],
+ rememberScrollState: ['androidx.compose.foundation.rememberScrollState'],
+
+ // Compose Foundation Lazy
+ LazyColumn: ['androidx.compose.foundation.lazy.LazyColumn'],
+ LazyRow: ['androidx.compose.foundation.lazy.LazyRow'],
+ LazyVerticalGrid: ['androidx.compose.foundation.lazy.grid.LazyVerticalGrid'],
+ LazyHorizontalGrid: ['androidx.compose.foundation.lazy.grid.LazyHorizontalGrid'],
+ GridCells: ['androidx.compose.foundation.lazy.grid.GridCells'],
+ items: ['androidx.compose.foundation.lazy.items', 'androidx.compose.foundation.lazy.grid.items'],
+ LazyVerticalStaggeredGrid: ['androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid'],
+ StaggeredGridCells: ['androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells'],
+
+ // Compose Pager
+ HorizontalPager: ['androidx.compose.foundation.pager.HorizontalPager'],
+ VerticalPager: ['androidx.compose.foundation.pager.VerticalPager'],
+ rememberPagerState: ['androidx.compose.foundation.pager.rememberPagerState'],
+
+ // Compose UI
+ Modifier: ['androidx.compose.ui.Modifier'],
+ Alignment: ['androidx.compose.ui.Alignment'],
+ Color: ['androidx.compose.ui.graphics.Color'],
+ dp: ['androidx.compose.ui.unit.dp'],
+ sp: ['androidx.compose.ui.unit.sp'],
+ TextStyle: ['androidx.compose.ui.text.TextStyle'],
+ FontWeight: ['androidx.compose.ui.text.font.FontWeight'],
+ TextOverflow: ['androidx.compose.ui.text.style.TextOverflow'],
+ TextAlign: ['androidx.compose.ui.text.style.TextAlign'],
+ KeyboardOptions: ['androidx.compose.foundation.text.KeyboardOptions'],
+ KeyboardActions: ['androidx.compose.foundation.text.KeyboardActions'],
+ KeyboardType: ['androidx.compose.ui.text.input.KeyboardType'],
+ ImeAction: ['androidx.compose.ui.text.input.ImeAction'],
+ PasswordVisualTransformation: ['androidx.compose.ui.text.input.PasswordVisualTransformation'],
+ LocalContext: ['androidx.compose.ui.platform.LocalContext'],
+ LocalFocusManager: ['androidx.compose.ui.platform.LocalFocusManager'],
+ LocalSoftwareKeyboardController: ['androidx.compose.ui.platform.LocalSoftwareKeyboardController'],
+ ContentScale: ['androidx.compose.ui.layout.ContentScale'],
+
+ // Icons
+ Icons: ['androidx.compose.material.icons.Icons'],
+ 'Icons.Default': ['androidx.compose.material.icons.Icons'],
+ 'Icons.Outlined': ['androidx.compose.material.icons.Icons', 'androidx.compose.material.icons.outlined.*'],
+ 'Icons.Rounded': ['androidx.compose.material.icons.Icons', 'androidx.compose.material.icons.rounded.*'],
+ 'Icons.Filled': ['androidx.compose.material.icons.Icons', 'androidx.compose.material.icons.filled.*'],
+
+ // Animation
+ AnimatedVisibility: ['androidx.compose.animation.AnimatedVisibility'],
+ animateContentSize: ['androidx.compose.animation.animateContentSize'],
+ Crossfade: ['androidx.compose.animation.Crossfade'],
+ AnimatedContent: ['androidx.compose.animation.AnimatedContent'],
+ animateFloatAsState: ['androidx.compose.animation.core.animateFloatAsState'],
+ animateDpAsState: ['androidx.compose.animation.core.animateDpAsState'],
+ animateColorAsState: ['androidx.compose.animation.core.animateColorAsState'],
+ tween: ['androidx.compose.animation.core.tween'],
+ spring: ['androidx.compose.animation.core.spring'],
+
+ // Navigation
+ NavController: ['androidx.navigation.NavController'],
+ NavHost: ['androidx.navigation.compose.NavHost'],
+ composable: ['androidx.navigation.compose.composable'],
+ rememberNavController: ['androidx.navigation.compose.rememberNavController'],
+ NavBackStackEntry: ['androidx.navigation.NavBackStackEntry'],
+
+ // ViewModel / Lifecycle
+ ViewModel: ['androidx.lifecycle.ViewModel'],
+ viewModel: ['androidx.lifecycle.viewmodel.compose.viewModel'],
+ viewModelScope: ['androidx.lifecycle.viewModelScope'],
+ AndroidViewModel: ['androidx.lifecycle.AndroidViewModel'],
+ LiveData: ['androidx.lifecycle.LiveData'],
+ MutableLiveData: ['androidx.lifecycle.MutableLiveData'],
+ observeAsState: ['androidx.compose.runtime.livedata.observeAsState'],
+ Lifecycle: ['androidx.lifecycle.Lifecycle'],
+ LifecycleEventObserver: ['androidx.lifecycle.LifecycleEventObserver'],
+ repeatOnLifecycle: ['androidx.lifecycle.repeatOnLifecycle'],
+ collectAsStateWithLifecycle: ['androidx.lifecycle.compose.collectAsStateWithLifecycle'],
+
+ // Coroutines / Flow
+ StateFlow: ['kotlinx.coroutines.flow.StateFlow'],
+ MutableStateFlow: ['kotlinx.coroutines.flow.MutableStateFlow'],
+ Flow: ['kotlinx.coroutines.flow.Flow'],
+ SharedFlow: ['kotlinx.coroutines.flow.SharedFlow'],
+ MutableSharedFlow: ['kotlinx.coroutines.flow.MutableSharedFlow'],
+ asStateFlow: ['kotlinx.coroutines.flow.asStateFlow'],
+ asSharedFlow: ['kotlinx.coroutines.flow.asSharedFlow'],
+ combine: ['kotlinx.coroutines.flow.combine'],
+ map: ['kotlinx.coroutines.flow.map'],
+ filter: ['kotlinx.coroutines.flow.filter'],
+ stateIn: ['kotlinx.coroutines.flow.stateIn'],
+ SharingStarted: ['kotlinx.coroutines.flow.SharingStarted'],
+ Dispatchers: ['kotlinx.coroutines.Dispatchers'],
+ withContext: ['kotlinx.coroutines.withContext'],
+ launch: ['kotlinx.coroutines.launch'],
+ async: ['kotlinx.coroutines.async'],
+ CoroutineScope: ['kotlinx.coroutines.CoroutineScope'],
+
+ // Room
+ Entity: ['androidx.room.Entity'],
+ PrimaryKey: ['androidx.room.PrimaryKey'],
+ ColumnInfo: ['androidx.room.ColumnInfo'],
+ Dao: ['androidx.room.Dao'],
+ Query: ['androidx.room.Query'],
+ Insert: ['androidx.room.Insert'],
+ Delete: ['androidx.room.Delete'],
+ Update: ['androidx.room.Update'],
+ OnConflictStrategy: ['androidx.room.OnConflictStrategy'],
+ Database: ['androidx.room.Database'],
+ RoomDatabase: ['androidx.room.RoomDatabase'],
+ Room: ['androidx.room.Room'],
+
+ // Hilt
+ HiltViewModel: ['dagger.hilt.android.lifecycle.HiltViewModel'],
+ HiltAndroidApp: ['dagger.hilt.android.HiltAndroidApp'],
+ AndroidEntryPoint: ['dagger.hilt.android.AndroidEntryPoint'],
+ Inject: ['javax.inject.Inject'],
+ Provides: ['dagger.Provides'],
+ Singleton: ['javax.inject.Singleton'],
+ Module: ['dagger.Module'],
+ InstallIn: ['dagger.hilt.InstallIn'],
+ SingletonComponent: ['dagger.hilt.components.SingletonComponent'],
+
+ // Coil / Image
+ AsyncImage: ['coil.compose.AsyncImage'],
+ rememberAsyncImagePainter: ['coil.compose.rememberAsyncImagePainter'],
+
+ // Accompanist
+ rememberPermissionState: ['com.google.accompanist.permissions.rememberPermissionState'],
+ rememberMultiplePermissionsState: ['com.google.accompanist.permissions.rememberMultiplePermissionsState'],
+
+ // ConstraintLayout
+ ConstraintLayout: ['androidx.constraintlayout.compose.ConstraintLayout'],
+ Dimension: ['androidx.constraintlayout.compose.Dimension'],
+};
+
+/**
+ * CompletionItemProvider that offers to add missing Kotlin/Compose imports.
+ * Triggers when user types a known identifier in a .kt file.
+ */
+export class ImportCompletionProvider implements vscode.CompletionItemProvider {
+ provideCompletionItems(
+ document: vscode.TextDocument,
+ position: vscode.Position,
+ ): vscode.CompletionItem[] {
+ const wordRange = document.getWordRangeAtPosition(position, /[\w.]+/);
+ const word = wordRange ? document.getText(wordRange) : '';
+
+ const existingText = document.getText();
+ const items: vscode.CompletionItem[] = [];
+
+ // Search the IMPORT_MAP for anything starting with what the user is typing
+ // If word is empty, we return nothing to avoid spamming the whole map
+ if (word.length === 0) {
+ return [];
+ }
+
+ const searchWord = word.toLowerCase();
+
+ for (const [identifier, imports] of Object.entries(IMPORT_MAP)) {
+ if (identifier.toLowerCase().startsWith(searchWord)) {
+ for (const imp of imports) {
+ // Skip if already imported
+ if (existingText.includes(`import ${imp}`)) {
+ continue;
+ }
+
+ const item = new vscode.CompletionItem(
+ `import ${imp}`,
+ vscode.CompletionItemKind.Module,
+ );
+ item.detail = 'JetStart: add import';
+ item.documentation = new vscode.MarkdownString(`Adds \`import ${imp}\` to the top of the file.`);
+
+ // Complete the identifier being typed
+ item.insertText = identifier;
+ item.range = wordRange;
+
+ item.filterText = identifier; // Filter against the identifier
+ item.sortText = '0' + identifier;
+
+ // Add the import edit
+ const insertLine = findImportInsertLine(document);
+ item.additionalTextEdits = [
+ vscode.TextEdit.insert(
+ new vscode.Position(insertLine, 0),
+ `import ${imp}\n`
+ ),
+ ];
+
+ items.push(item);
+ }
+ }
+ }
+
+ return items;
+ }
+}
diff --git a/packages/extension/src/importUtils.ts b/packages/extension/src/importUtils.ts
new file mode 100644
index 0000000..9d5a2ce
--- /dev/null
+++ b/packages/extension/src/importUtils.ts
@@ -0,0 +1,54 @@
+import * as vscode from 'vscode';
+
+/**
+ * Find the line number after which to insert a new import.
+ * Priority:
+ * 1. After the last existing import.
+ * 2. After the package declaration.
+ * 3. At the beginning of the file.
+ */
+export function findImportInsertLine(document: vscode.TextDocument): number {
+ let lastImportLine = -1;
+ let packageLine = -1;
+
+ // Scan the first 100 lines for package and import declarations
+ const lineCount = Math.min(document.lineCount, 100);
+ for (let i = 0; i < lineCount; i++) {
+ const text = document.lineAt(i).text.trim();
+ if (text.startsWith('package ')) {
+ packageLine = i;
+ }
+ if (text.startsWith('import ')) {
+ lastImportLine = i;
+ }
+ // If we hit a class/fun/val/var declaration, we've likely passed the header
+ if (/^\s*(class|fun|interface|object|val|var|sealed|data|enum)\s/.test(text)) {
+ break;
+ }
+ }
+
+ if (lastImportLine >= 0) {
+ return lastImportLine + 1;
+ }
+ if (packageLine >= 0) {
+ return packageLine + 2; // Add a blank line if possible
+ }
+ return 0;
+}
+
+/**
+ * Returns a list of TextEdits to add missing imports.
+ */
+export function getImportEdits(document: vscode.TextDocument, imports: string[]): vscode.TextEdit[] {
+ const existingText = document.getText();
+ const missingImports = imports.filter(imp => !existingText.includes(`import ${imp}`));
+
+ if (missingImports.length === 0) {
+ return [];
+ }
+
+ const insertLine = findImportInsertLine(document);
+ return missingImports.map(imp =>
+ vscode.TextEdit.insert(new vscode.Position(insertLine, 0), `import ${imp}\n`)
+ );
+}
diff --git a/packages/extension/src/packageDetector.ts b/packages/extension/src/packageDetector.ts
new file mode 100644
index 0000000..b127202
--- /dev/null
+++ b/packages/extension/src/packageDetector.ts
@@ -0,0 +1,74 @@
+
+import * as vscode from 'vscode';
+import * as path from 'path';
+
+/**
+ * Tries to determine the Kotlin package name for a document.
+ *
+ * Priority:
+ * 1. Already declared in the file (package line exists) β return null
+ * (caller uses this to skip adding package again)
+ * 2. Derive from file path after java/ or kotlin/ source root
+ * 3. Fall back to null (snippet will use a tab-stop placeholder)
+ */
+export function getPackageInfo(document: vscode.TextDocument): {
+ hasPackage: boolean;
+ packageName: string | null;
+ subPackage: string | null; // just the last segment e.g. "ui", "data"
+} {
+ const text = document.getText();
+
+ // Check if file already has a package declaration
+ const existing = text.match(/^\s*package\s+([\w.]+)/m);
+ if (existing) {
+ return { hasPackage: true, packageName: existing[1], subPackage: null };
+ }
+
+ // Derive from file path
+ const filePath = document.uri.fsPath.replace(/\\/g, '/');
+
+ // Match Android project structure: .../java//FileName.kt
+ const match = filePath.match(/\/(?:java|kotlin)\/((?:[\w]+\/)*[\w]+)\/[^/]+\.kt$/);
+ if (match) {
+ const pkg = match[1].replace(/\//g, '.');
+ const parts = pkg.split('.');
+ const subPackage = parts.length > 1 ? parts[parts.length - 1] : null;
+ return { hasPackage: false, packageName: pkg, subPackage };
+ }
+
+ return { hasPackage: false, packageName: null, subPackage: null };
+}
+
+/**
+ * Derives a class name suggestion from the file name.
+ * e.g. "notes_screen.kt" β "NotesScreen"
+ * "NoteItem.kt" β "NoteItem"
+ */
+export function classNameFromFile(document: vscode.TextDocument): string {
+ const fileName = path.basename(document.uri.fsPath, '.kt');
+ // PascalCase: split on _ or - or existing camel humps
+ return fileName
+ .replace(/[-_](.)/g, (_, c) => c.toUpperCase())
+ .replace(/^(.)/, c => c.toUpperCase());
+}
+
+/**
+ * Builds the package prefix string to prepend to a snippet body.
+ * Returns "" if the file already declares a package (don't re-add it).
+ * Returns "package \n\n" if we could detect the package.
+ * Returns "package ${1:com.example}\n\n" (tab stop) if we could not detect.
+ */
+export function buildPkgLine(document: vscode.TextDocument): string {
+ const { hasPackage, packageName } = getPackageInfo(document);
+
+ if (hasPackage) {
+ return ''; // file already has package β don't add another
+ }
+
+ if (packageName) {
+ return `package ${packageName}\n\n`;
+ }
+
+ // Unknown β let user fill it in
+ return 'package ${1:com.example}\n\n';
+}
diff --git a/packages/extension/src/snippets/definitions.ts b/packages/extension/src/snippets/definitions.ts
new file mode 100644
index 0000000..7d51d91
--- /dev/null
+++ b/packages/extension/src/snippets/definitions.ts
@@ -0,0 +1,762 @@
+// JetStart Snippet Definitions
+// Each snippet has:
+// prefix - what the user types (like ktc, ktvm, ktcf β¦)
+// label - shown in autocomplete dropdown
+// detail - right-side annotation in the dropdown
+// body() - function receiving context; returns the snippet string
+// $1, $2 β¦ are tab stops; \${1:placeholder} has default text
+// pkgLine is "package com.example.app.ui\n\n" or "" if file
+
+// already declares its own package
+
+export interface SnippetContext {
+ className: string; // suggested class name from file name
+}
+
+export interface SnippetDef {
+ prefix: string;
+ label: string;
+ detail: string;
+ body: (ctx: SnippetContext) => string;
+ documentation: string;
+ imports?: string[];
+}
+
+// helpers
+const OPT = (annotation: string) =>
+ `@OptIn(ExperimentalMaterial3Api::class)
+${annotation}`;
+
+// all snippets
+export const SNIPPETS: SnippetDef[] = [
+
+ // Classes
+ {
+ prefix: 'ktc',
+ label: 'ktc β Kotlin Class',
+ detail: 'class ${Name} { }',
+ documentation: 'Creates a Kotlin class.',
+ body: ({ className }) =>
+`class \${1:${className}} {
+ \${0:// TODO}
+}`,
+ },
+
+ {
+ prefix: 'ktdc',
+ label: 'ktdc β Data Class',
+ detail: 'data class ${Name}(...)',
+ documentation: 'Creates a Kotlin data class.',
+ body: ({ className }) =>
+`data class \${1:${className}}(
+ val \${2:id}: \${3:Int},
+ val \${4:name}: \${5:String},
+) {\${0}}`,
+ },
+
+ {
+ prefix: 'ktsc',
+ label: 'ktsc β Sealed Class',
+ detail: 'sealed class ${Name}',
+ documentation: 'Creates a Kotlin sealed class with common subclasses.',
+ body: ({ className }) =>
+`sealed class \${1:${className}} {
+ data class Success(val \${2:data}: \${3:Any}) : \${1:${className}}()
+ data class Error(val \${4:message}: String) : \${1:${className}}()
+ object Loading : \${1:${className}}()
+}\${0}`,
+ },
+
+ {
+ prefix: 'ktec',
+ label: 'ktec β Enum Class',
+ detail: 'enum class ${Name}',
+ documentation: 'Creates a Kotlin enum class.',
+ body: ({ className }) =>
+`enum class \${1:${className}} {
+ \${2:OPTION_ONE},
+ \${3:OPTION_TWO},
+ \${4:OPTION_THREE},
+}
+\${0}`,
+ },
+
+ {
+ prefix: 'ktobj',
+ label: 'ktobj β Object',
+ detail: 'object ${Name} { }',
+ documentation: 'Creates a Kotlin singleton object.',
+ body: ({ className }) =>
+`object \${1:${className}} {
+ \${0:// TODO}
+}`,
+ },
+
+ {
+ prefix: 'ktint',
+ label: 'ktint β Interface',
+ detail: 'interface ${Name} { }',
+ documentation: 'Creates a Kotlin interface.',
+ body: ({ className }) =>
+`interface \${1:${className}} {
+ \${0:// TODO}
+}`,
+ },
+
+ {
+ prefix: 'ktabsc',
+ label: 'ktabsc β Abstract Class',
+ detail: 'abstract class ${Name}',
+ documentation: 'Creates a Kotlin abstract class.',
+ body: ({ className }) =>
+`abstract class \${1:${className}} {
+ abstract fun \${2:method}(): \${3:Unit}
+ \${0}
+}`,
+ },
+
+ // Android Architecture
+ {
+ prefix: 'ktvm',
+ label: 'ktvm β ViewModel',
+ detail: 'class ${Name}ViewModel : ViewModel()',
+ documentation: 'Creates a ViewModel with StateFlow and coroutine scope.',
+ imports: [
+ 'androidx.lifecycle.ViewModel',
+ 'androidx.lifecycle.viewModelScope',
+ 'kotlinx.coroutines.flow.MutableStateFlow',
+ 'kotlinx.coroutines.flow.StateFlow',
+ 'kotlinx.coroutines.flow.asStateFlow',
+ 'kotlinx.coroutines.launch',
+ ],
+ body: ({ className }) =>
+`class \${1:${className}}ViewModel : ViewModel() {
+
+ private val _\${2:state} = MutableStateFlow<\${3:String}>(\${4:""})
+ val \${2:state}: StateFlow<\${3:String}> = _\${2:state}.asStateFlow()
+
+ fun \${5:loadData}() {
+ viewModelScope.launch {
+ \${0:// TODO}
+ }
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktrep',
+ label: 'ktrep β Repository',
+ detail: 'class ${Name}Repository',
+ documentation: 'Creates a Repository class with suspend functions.',
+ imports: ['kotlinx.coroutines.flow.Flow'],
+ body: ({ className }) =>
+`class \${1:${className}}Repository(
+ private val \${2:dao}: \${3:${className}Dao},
+) {
+
+ fun getAll(): Flow> = \${2:dao}.\${5:getAll}()
+
+ suspend fun insert(\${6:item}: \${4:${className}}) {
+ \${2:dao}.\${7:insert}(\${6:item})
+ }
+
+ suspend fun delete(\${6:item}: \${4:${className}}) {
+ \${2:dao}.\${8:delete}(\${6:item})
+ }
+
+ \${0}
+}`,
+ },
+
+ // Room
+ {
+ prefix: 'ktent',
+ label: 'ktent β Room Entity',
+ detail: '@Entity data class ${Name}',
+ documentation: 'Creates a Room database entity.',
+ imports: [
+ 'androidx.room.Entity',
+ 'androidx.room.PrimaryKey',
+ ],
+ body: ({ className }) =>
+`@Entity(tableName = "\${2:${className.toLowerCase()}s}")
+data class \${1:${className}}(
+ @PrimaryKey(autoGenerate = true)
+ val id: Int = 0,
+ val \${3:name}: \${4:String},
+ val \${5:createdAt}: Long = System.currentTimeMillis(),
+)
+\${0}`,
+ },
+
+ {
+ prefix: 'ktdao',
+ label: 'ktdao β Room DAO',
+ detail: '@Dao interface ${Name}Dao',
+ documentation: 'Creates a Room DAO interface.',
+ imports: [
+ 'androidx.room.*',
+ 'kotlinx.coroutines.flow.Flow',
+ ],
+ body: ({ className }) =>
+`@Dao
+interface \${1:${className}}Dao {
+
+ @Query("SELECT * FROM \${2:${className.toLowerCase()}s} ORDER BY id DESC")
+ fun getAll(): Flow>
+
+ @Query("SELECT * FROM \${2:${className.toLowerCase()}s} WHERE id = :id")
+ suspend fun getById(id: Int): \${1:${className}}?
+
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
+ suspend fun insert(item: \${1:${className}})
+
+ @Delete
+ suspend fun delete(item: \${1:${className}})
+
+ @Update
+ suspend fun update(item: \${1:${className}})
+
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktdb',
+ label: 'ktdb β Room Database',
+ detail: '@Database abstract class ${Name}Database',
+ documentation: 'Creates a Room Database abstract class.',
+ imports: [
+ 'android.content.Context',
+ 'androidx.room.Database',
+ 'androidx.room.Room',
+ 'androidx.room.RoomDatabase',
+ ],
+ body: ({ className }) =>
+`@Database(
+ entities = [\${1:${className}}::class],
+ version = \${2:1},
+ exportSchema = false,
+)
+abstract class \${3:${className}}Database : RoomDatabase() {
+
+ abstract fun \${4:${className.toLowerCase()}}Dao(): \${1:${className}}Dao
+
+ companion object {
+ @Volatile private var INSTANCE: \${3:${className}}Database? = null
+
+ fun getDatabase(context: Context): \${3:${className}}Database =
+ INSTANCE ?: synchronized(this) {
+ Room.databaseBuilder(
+ context.applicationContext,
+ \${3:${className}}Database::class.java,
+ "\${5:${className.toLowerCase()}_database}",
+ ).build().also { INSTANCE = it }
+ }
+ }
+}
+\${0}`,
+ },
+
+ // Composable Functions
+ {
+ prefix: 'ktcf',
+ label: 'ktcf β Composable Function',
+ detail: '@Composable fun ${Name}()',
+ documentation: 'Creates a Composable function.',
+ imports: ['androidx.compose.runtime.Composable'],
+ body: () =>
+`@Composable
+fun \${1:MyScreen}(\${2}) {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktcfs',
+ label: 'ktcfs β Composable with State',
+ detail: '@Composable fun ${Name}() + remember state',
+ documentation: 'Creates a Composable function with local state using remember.',
+ imports: ['androidx.compose.runtime.*'],
+ body: () =>
+`@Composable
+fun \${1:MyScreen}(\${2}) {
+ var \${3:value} by remember { mutableStateOf(\${4:""}) }
+
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktprev',
+ label: 'ktprev β Composable Preview',
+ detail: '@Preview @Composable fun ${Name}Preview()',
+ documentation: 'Creates a Composable preview function.',
+ imports: [
+ 'androidx.compose.runtime.Composable',
+ 'androidx.compose.ui.tooling.preview.Preview',
+ ],
+ body: () =>
+`@Preview(showBackground = true)
+@Composable
+fun \${1:MyScreen}Preview() {
+ \${1:MyScreen}(\${2})
+}`,
+ },
+
+ // Compose UI Blocks
+ {
+ prefix: 'ktscaffold',
+ label: 'ktscaffold β Scaffold',
+ detail: 'Scaffold { ... }',
+ documentation: 'Full Material3 Scaffold with TopAppBar and FAB.',
+ imports: [
+ 'androidx.compose.material3.*',
+ 'androidx.compose.material.icons.Icons',
+ 'androidx.compose.material.icons.filled.Add',
+ 'androidx.compose.ui.Modifier',
+ ],
+ body: () =>
+`${OPT('@Composable')}
+fun \${1:MyScreen}() {
+ Scaffold(
+ topBar = {
+ TopAppBar(title = { Text("\${2:Title}") })
+ },
+ floatingActionButton = {
+ FloatingActionButton(onClick = { \${3} }) {
+ Icon(Icons.Default.\${4:Add}, contentDescription = "\${5:Action}")
+ }
+ },
+ ) { padding ->
+ Column(modifier = Modifier.padding(padding).fillMaxSize()) {
+ \${0}
+ }
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktlazycol',
+ label: 'ktlazycol β LazyColumn',
+ detail: 'LazyColumn { items(...) }',
+ documentation: 'LazyColumn with items block.',
+ body: () =>
+`LazyColumn(
+ contentPadding = PaddingValues(\${1:16}.dp),
+ verticalArrangement = Arrangement.spacedBy(\${2:8}.dp),
+ modifier = Modifier.fillMaxSize(),
+) {
+ items(\${3:items}) { \${4:item} ->
+ \${0}
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktlazyr',
+ label: 'ktlazyr β LazyRow',
+ detail: 'LazyRow { items(...) }',
+ documentation: 'LazyRow with items block.',
+ body: () =>
+`LazyRow(
+ contentPadding = PaddingValues(horizontal = \${1:16}.dp),
+ horizontalArrangement = Arrangement.spacedBy(\${2:8}.dp),
+) {
+ items(\${3:items}) { \${4:item} ->
+ \${0}
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktlazysgrid',
+ label: 'ktlazysgrid β LazyVerticalStaggeredGrid',
+ detail: 'LazyVerticalStaggeredGrid { items(...) }',
+ documentation: 'Staggered grid layout.',
+ body: () =>
+`LazyVerticalStaggeredGrid(
+ columns = StaggeredGridCells.Fixed(\${1:2}),
+ contentPadding = PaddingValues(\${2:16}.dp),
+ horizontalArrangement = Arrangement.spacedBy(\${3:12}.dp),
+ verticalItemSpacing = \${4:12}.dp,
+ modifier = Modifier.fillMaxSize(),
+) {
+ items(\${5:items}) { \${6:item} ->
+ \${0}
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktcard',
+ label: 'ktcard β Card',
+ detail: 'Card { Column { ... } }',
+ documentation: 'Material3 Card with Column content.',
+ body: () =>
+`Card(
+ colors = CardDefaults.cardColors(
+ containerColor = MaterialTheme.colorScheme.\${1:surfaceVariant},
+ ),
+ shape = MaterialTheme.shapes.\${2:medium},
+ modifier = Modifier.\${3:fillMaxWidth()},
+) {
+ Column(modifier = Modifier.padding(\${4:16}.dp)) {
+ \${0}
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktrow',
+ label: 'ktrow β Row',
+ detail: 'Row(horizontalArrangement, verticalAlignment)',
+ documentation: 'Row layout composable.',
+ body: () =>
+`Row(
+ horizontalArrangement = Arrangement.\${1:spacedBy(8.dp)},
+ verticalAlignment = Alignment.\${2:CenterVertically},
+ modifier = Modifier.\${3:fillMaxWidth()},
+) {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktcol',
+ label: 'ktcol β Column',
+ detail: 'Column(verticalArrangement, horizontalAlignment)',
+ documentation: 'Column layout composable.',
+ body: () =>
+`Column(
+ verticalArrangement = Arrangement.\${1:spacedBy(8.dp)},
+ horizontalAlignment = Alignment.\${2:CenterHorizontally},
+ modifier = Modifier.\${3:fillMaxSize()},
+) {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktalertd',
+ label: 'ktalertd β AlertDialog',
+ detail: 'AlertDialog { ... }',
+ documentation: 'Material3 AlertDialog.',
+ body: () =>
+`AlertDialog(
+ onDismissRequest = \${1:onDismiss},
+ title = { Text("\${2:Title}") },
+ text = {
+ \${0}
+ },
+ confirmButton = {
+ Button(onClick = \${3:onConfirm}) {
+ Text("\${4:Confirm}")
+ }
+ },
+ dismissButton = {
+ TextButton(onClick = \${1:onDismiss}) {
+ Text("\${5:Cancel}")
+ }
+ },
+)`,
+ },
+
+ {
+ prefix: 'ktbottomsheet',
+ label: 'ktbottomsheet β ModalBottomSheet',
+ detail: 'ModalBottomSheet { ... }',
+ documentation: 'Material3 ModalBottomSheet.',
+ imports: [
+ 'androidx.compose.material3.*',
+ 'androidx.compose.runtime.*',
+ 'androidx.compose.ui.unit.dp',
+ ],
+ body: () =>
+`${OPT('val sheetState = rememberModalBottomSheetState()')}
+var showSheet by remember { mutableStateOf(false) }
+
+if (showSheet) {
+ ModalBottomSheet(
+ onDismissRequest = { showSheet = false },
+ sheetState = sheetState,
+ ) {
+ Column(modifier = Modifier.padding(16.dp)) {
+ \${0}
+ }
+ }
+}`,
+ },
+
+ {
+ prefix: 'kttab',
+ label: 'kttab β TopAppBar',
+ detail: '@OptIn TopAppBar { ... }',
+ documentation: 'Material3 TopAppBar.',
+ imports: [
+ 'androidx.compose.material3.*',
+ 'androidx.compose.material.icons.Icons',
+ 'androidx.compose.material.icons.filled.ArrowBack',
+ ],
+ body: () =>
+`${OPT('TopAppBar(')}
+ title = { Text("\${1:Title}") },
+ navigationIcon = {
+ \${2:IconButton(onClick = \${3:onBack}) {
+ Icon(Icons.Default.ArrowBack, contentDescription = "Back")
+ }}
+ },
+ actions = {
+ \${0}
+ },
+)`,
+ },
+
+ {
+ prefix: 'ktnav',
+ label: 'ktnav β NavHost Setup',
+ detail: 'NavHost with composable routes',
+ documentation: 'Sets up a NavHost with multiple composable routes.',
+ imports: [
+ 'androidx.compose.runtime.Composable',
+ 'androidx.navigation.compose.NavHost',
+ 'androidx.navigation.compose.composable',
+ 'androidx.navigation.compose.rememberNavController',
+ ],
+ body: () =>
+`@Composable
+fun \${1:AppNavigation}() {
+ val navController = rememberNavController()
+
+ NavHost(
+ navController = navController,
+ startDestination = "\${2:home}",
+ ) {
+ composable("\${2:home}") {
+ \${3:HomeScreen}(navController = navController)
+ }
+ composable("\${4:detail}/{id}") { backStackEntry ->
+ val id = backStackEntry.arguments?.getString("id")
+ \${5:DetailScreen}(id = id, navController = navController)
+ }
+ \${0}
+ }
+}`,
+ },
+
+ // State & Flow
+ {
+ prefix: 'ktstate',
+ label: 'ktstate β remember mutableStateOf',
+ detail: 'var x by remember { mutableStateOf(...) }',
+ documentation: 'Creates a remembered mutable state variable.',
+ body: () =>
+`var \${1:value} by remember { mutableStateOf(\${2:""}) }\${0}`,
+ },
+
+ {
+ prefix: 'ktsflow',
+ label: 'ktsflow β StateFlow pair',
+ detail: 'private _x MutableStateFlow + x StateFlow',
+ documentation: 'Creates a private MutableStateFlow and its public StateFlow.',
+ body: () =>
+`private val _\${1:state} = MutableStateFlow<\${2:String}>(\${3:""})
+val \${1:state}: StateFlow<\${2:String}> = _\${1:state}.asStateFlow()\${0}`,
+ },
+
+ {
+ prefix: 'ktcollect',
+ label: 'ktcollect β collectAsState',
+ detail: 'val x by flow.collectAsState()',
+ documentation: 'Collects a Flow/StateFlow as Compose state.',
+ body: () =>
+`val \${1:value} by \${2:viewModel}.\${3:state}.collectAsState()\${0}`,
+ },
+
+ {
+ prefix: 'ktlaunch',
+ label: 'ktlaunch β LaunchedEffect',
+ detail: 'LaunchedEffect(key) { }',
+ documentation: 'Creates a LaunchedEffect with a key.',
+ body: () =>
+`LaunchedEffect(\${1:key1}) {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktsideef',
+ label: 'ktsideef β SideEffect',
+ detail: 'SideEffect { }',
+ documentation: 'Creates a SideEffect block.',
+ body: () =>
+`SideEffect {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktdisposable',
+ label: 'ktdisposable β DisposableEffect',
+ detail: 'DisposableEffect(key) { onDispose { } }',
+ documentation: 'Creates a DisposableEffect with cleanup.',
+ body: () =>
+`DisposableEffect(\${1:key1}) {
+ \${2:// setup}
+ onDispose {
+ \${0:// cleanup}
+ }
+}`,
+ },
+
+ {
+ prefix: 'ktderived',
+ label: 'ktderived β derivedStateOf',
+ detail: 'val x by remember { derivedStateOf { } }',
+ documentation: 'Creates a derived state that only recomposes when result changes.',
+ body: () =>
+`val \${1:derived} by remember {
+ derivedStateOf { \${0} }
+}`,
+ },
+
+ // Coroutines
+ {
+ prefix: 'ktcoro',
+ label: 'ktcoro β viewModelScope.launch',
+ detail: 'viewModelScope.launch { }',
+ documentation: 'Launches a coroutine in viewModelScope.',
+ body: () =>
+`viewModelScope.launch {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktio',
+ label: 'ktio β withContext IO',
+ detail: 'withContext(Dispatchers.IO) { }',
+ documentation: 'Runs a block on the IO dispatcher.',
+ body: () =>
+`withContext(Dispatchers.IO) {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktasync',
+ label: 'ktasync β async/await',
+ detail: 'val x = async { }.await()',
+ documentation: 'Creates an async deferred value and awaits it.',
+ body: () =>
+`val \${1:result} = async {
+ \${0}
+}.await()`,
+ },
+
+ // Functions
+ {
+ prefix: 'ktfun',
+ label: 'ktfun β Function',
+ detail: 'fun name(): ReturnType { }',
+ documentation: 'Creates a Kotlin function.',
+ body: () =>
+`fun \${1:functionName}(\${2}): \${3:Unit} {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktsfun',
+ label: 'ktsfun β Suspend Function',
+ detail: 'suspend fun name(): ReturnType { }',
+ documentation: 'Creates a Kotlin suspend function.',
+ body: () =>
+`suspend fun \${1:functionName}(\${2}): \${3:Unit} {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktef',
+ label: 'ktef β Extension Function',
+ detail: 'fun Type.name(): ReturnType { }',
+ documentation: 'Creates a Kotlin extension function.',
+ body: () =>
+`fun \${1:String}.\${2:extensionName}(\${3}): \${4:Unit} {
+ \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktlambda',
+ label: 'ktlambda β Lambda',
+ detail: 'val name: (Type) -> ReturnType = { }',
+ documentation: 'Creates a Kotlin lambda.',
+ body: () =>
+`val \${1:name}: (\${2:String}) -> \${3:Unit} = { \${4:it} ->
+ \${0}
+}`,
+ },
+
+ // Control Flow
+ {
+ prefix: 'ktwhen',
+ label: 'ktwhen β when expression',
+ detail: 'when (x) { ... }',
+ documentation: 'Creates a Kotlin when expression.',
+ body: () =>
+`when (\${1:value}) {
+ \${2:condition1} -> \${3}
+ \${4:condition2} -> \${5}
+ else -> \${0}
+}`,
+ },
+
+ {
+ prefix: 'ktwhenresult',
+ label: 'ktwhenresult β when Result',
+ detail: 'when (result) { is Success -> ... }',
+ documentation: 'Handles a sealed Result class with when.',
+ body: () =>
+`when (val result = \${1:result}) {
+ is \${2:UiState}.Loading -> \${3:LoadingView()}
+ is \${2:UiState}.Success -> \${4:SuccessView(result.data)}
+ is \${2:UiState}.Error -> \${0:ErrorView(result.message)}
+}`,
+ },
+
+ // Hilt
+ {
+ prefix: 'kthiltvm',
+ label: 'kthiltvm β Hilt ViewModel',
+ detail: '@HiltViewModel class ${Name}ViewModel @Inject',
+ documentation: 'Creates a Hilt-injected ViewModel.',
+ imports: [
+ 'androidx.lifecycle.ViewModel',
+ 'androidx.lifecycle.viewModelScope',
+ 'dagger.hilt.android.lifecycle.HiltViewModel',
+ 'kotlinx.coroutines.flow.MutableStateFlow',
+ 'kotlinx.coroutines.flow.StateFlow',
+ 'kotlinx.coroutines.flow.asStateFlow',
+ 'kotlinx.coroutines.launch',
+ 'javax.inject.Inject',
+ ],
+ body: ({ className }) =>
+`@HiltViewModel
+class \${1:${className}}ViewModel @Inject constructor(
+ private val \${2:repository}: \${3:${className}Repository},
+) : ViewModel() {
+
+ private val _\${4:state} = MutableStateFlow<\${5:String}>(\${6:""})
+ val \${4:state}: StateFlow<\${5:String}> = _\${4:state}.asStateFlow()
+
+ fun \${7:loadData}() {
+ viewModelScope.launch {
+ \${0:// TODO}
+ }
+ }
+}`,
+ },
+
+];
diff --git a/packages/extension/tsconfig.json b/packages/extension/tsconfig.json
new file mode 100644
index 0000000..ebc3aee
--- /dev/null
+++ b/packages/extension/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "target": "ES2020",
+ "outDir": "./dist",
+ "rootDir": "./src",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "sourceMap": true
+ },
+ "include": [
+ "src/**/*"
+ ],
+ "exclude": [
+ "node_modules",
+ "dist"
+ ]
+}