diff --git a/.github/PUBLISHING.md b/.github/PUBLISHING.md index 8f179ad..96b693d 100644 --- a/.github/PUBLISHING.md +++ b/.github/PUBLISHING.md @@ -3,6 +3,8 @@ This document explains how to publish ISL artifacts to Maven Central and GitHub Packages. ## Prerequisites +https://intuit-teams.slack.com/archives/C044PJN2NDR/p1749599979127989?thread_ts=1749145553.673049&cid=C044PJN2NDR + ### 1. Maven Central (Sonatype OSSRH) Setup @@ -16,15 +18,30 @@ To publish to Maven Central, you need: ```bash # Generate key -gpg --gen-key +gpg --full-generate-key +# Choose RSA (option 1), key size 3072 or 4096, and set a strong passphrase + +# List keys to get the key ID +gpg --list-secret-keys --keyid-format=long + +# Export the ASCII-armored secret key (replace KEY_ID with your key ID) +gpg --export-secret-keys --armor KEY_ID +``` + +**For Windows (PowerShell):** +```powershell +# Generate key +gpg --full-generate-key -# List keys to get the key ID (last 8 characters of the fingerprint) -gpg --list-keys +# List keys +gpg --list-secret-keys --keyid-format=long -# Export the key (replace KEY_ID with your key ID) -gpg --export-secret-keys KEY_ID | base64 +# Export and copy to clipboard +gpg --export-secret-keys --armor YOUR_KEY_ID | Set-Clipboard ``` +**Note:** You can use the ASCII-armored key directly in the `SIGNING_KEY` secret (starts with `-----BEGIN PGP PRIVATE KEY BLOCK-----`). Base64 encoding is optional. + ### 2. GitHub Repository Secrets Configure the following secrets in your GitHub repository (Settings → Secrets and variables → Actions): @@ -32,8 +49,7 @@ Configure the following secrets in your GitHub repository (Settings → Secrets #### Maven Central Secrets: - `OSSRH_USERNAME`: Your Sonatype JIRA username - `OSSRH_PASSWORD`: Your Sonatype JIRA password -- `SIGNING_KEY_ID`: Your GPG key ID (last 8 characters) -- `SIGNING_KEY`: Your base64-encoded GPG private key +- `SIGNING_KEY`: Your ASCII-armored GPG private key (or base64-encoded) - `SIGNING_PASSWORD`: Your GPG key passphrase #### GitHub Packages: @@ -167,6 +183,17 @@ signing.secretKeyRingFile=/path/to/.gnupg/secring.gpg ## Troubleshooting +### Issue: "Could not read PGP secret key" or "checksum mismatch" +**Solution:** +1. Use the ASCII-armored format directly (recommended): + ```bash + gpg --export-secret-keys --armor YOUR_KEY_ID + ``` + Copy the entire output (including BEGIN/END markers) into the `SIGNING_KEY` secret +2. Ensure `SIGNING_PASSWORD` matches your GPG key passphrase +3. Verify the key exports correctly before adding to GitHub secrets +4. If using base64 encoding, ensure no extra whitespace or line breaks are introduced + ### Issue: "Could not find signing key" **Solution:** Ensure GPG key is properly exported and base64 encoded. Check `SIGNING_KEY` secret. diff --git a/.github/workflows/plugin-ci.yml b/.github/workflows/plugin-ci.yml new file mode 100644 index 0000000..4bc0365 --- /dev/null +++ b/.github/workflows/plugin-ci.yml @@ -0,0 +1,64 @@ +name: Plugin CI + +on: + push: + branches: [ main, plugin ] + paths: + - 'plugin/**' + - '.github/workflows/plugin-ci.yml' + pull_request: + branches: [ main ] + paths: + - 'plugin/**' + - '.github/workflows/plugin-ci.yml' + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + node-version: [18.x, 20.x] + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + cache-dependency-path: plugin/package-lock.json + + - name: Install dependencies + working-directory: plugin + run: npm ci + + - name: Lint code + working-directory: plugin + run: npm run lint || echo "No lint script configured" + continue-on-error: true + + - name: Compile TypeScript + working-directory: plugin + run: npm run compile + + - name: Run tests + working-directory: plugin + run: npm test || echo "No tests configured" + continue-on-error: true + + - name: Package extension + working-directory: plugin + run: npx vsce package + + - name: Upload build artifact + if: matrix.os == 'ubuntu-latest' && matrix.node-version == '18.x' + uses: actions/upload-artifact@v4 + with: + name: isl-language-support-build + path: plugin/*.vsix + retention-days: 7 + diff --git a/.github/workflows/publish-plugin.yml b/.github/workflows/publish-plugin.yml new file mode 100644 index 0000000..5ea218e --- /dev/null +++ b/.github/workflows/publish-plugin.yml @@ -0,0 +1,77 @@ +name: Publish VSCode Extension + +on: + push: + tags: + - 'plugin-v*.*.*' + workflow_dispatch: + inputs: + version: + description: 'Version to publish (e.g., 1.0.0)' + required: true + +jobs: + publish: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '18' + cache: 'npm' + cache-dependency-path: plugin/package-lock.json + + - name: Install dependencies + working-directory: plugin + run: npm ci + + - name: Compile TypeScript + working-directory: plugin + run: npm run compile + + - name: Run tests (if available) + working-directory: plugin + run: npm test || echo "No tests configured" + continue-on-error: true + + - name: Package extension + working-directory: plugin + run: npx vsce package + + - name: Publish to VSCode Marketplace + if: startsWith(github.ref, 'refs/tags/plugin-v') + working-directory: plugin + env: + VSCE_PAT: ${{ secrets.VSCE_TOKEN }} + run: npx vsce publish -p $VSCE_PAT + + - name: Publish to Open VSX Registry + if: startsWith(github.ref, 'refs/tags/plugin-v') + working-directory: plugin + env: + OVSX_PAT: ${{ secrets.OVSX_TOKEN }} + run: npx ovsx publish -p $OVSX_PAT + continue-on-error: true + + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: isl-language-support-vsix + path: plugin/*.vsix + retention-days: 90 + + - name: Create GitHub Release + if: startsWith(github.ref, 'refs/tags/plugin-v') + uses: softprops/action-gh-release@v1 + with: + files: plugin/*.vsix + generate_release_notes: true + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2e66cda..bc776b5 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -40,23 +40,50 @@ jobs: sed -i 's/version = ".*"/version = "${{ github.event.inputs.version }}"/' build.gradle.kts - name: Build artifacts - run: ./gradlew build --no-daemon --stacktrace + run: ./gradlew build --no-daemon --stacktrace -x test - - name: Run tests - run: ./gradlew test --no-daemon --stacktrace + # temp ignore to speed up the build + # - name: Run tests + # run: ./gradlew test --no-daemon --stacktrace + + - name: Setup PGP key for signing + run: | + # Write the PGP key to environment variable + # The key can be either base64-encoded or ASCII-armored + if echo "${{ secrets.SIGNING_KEY }}" | grep -q "BEGIN PGP"; then + # Key is already ASCII-armored + echo "SIGNING_KEY<> $GITHUB_ENV + echo "${{ secrets.SIGNING_KEY }}" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + else + # Key is base64-encoded, decode it + echo "${{ secrets.SIGNING_KEY }}" | tr -d '\n\r' | base64 --decode > signing_key.asc + echo "SIGNING_KEY<> $GITHUB_ENV + cat signing_key.asc >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + rm -f signing_key.asc + fi + - name: Verify OSSRH credentials + env: + OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} + run: | + if [ -z "$OSSRH_USERNAME" ]; then + echo "❌ OSSRH_USERNAME is not set!" + exit 1 + fi + echo "✓ OSSRH credentials are configured" + - name: Publish to Maven Central env: OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} OSSRH_PASSWORD: ${{ secrets.OSSRH_PASSWORD }} - SIGNING_KEY_ID: ${{ secrets.SIGNING_KEY_ID }} - SIGNING_KEY: ${{ secrets.SIGNING_KEY }} SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - run: ./gradlew publish --no-daemon --stacktrace + run: ./gradlew publishMavenPublicationToOSSRHRepository --no-daemon --stacktrace --info - - name: Publish to GitHub Packages - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: ./gradlew publishAllPublicationsToGitHubPackagesRepository --no-daemon --stacktrace - continue-on-error: true + # - name: Publish to GitHub Packages + # env: + # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # run: ./gradlew publishAllPublicationsToGitHubPackagesRepository --no-daemon --stacktrace + # continue-on-error: true diff --git a/.gitignore b/.gitignore index 4ee5884..e088d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,8 @@ out/ dist/ node_modules/ .vscode-test/ -*.vsix +# Allow plugin vsix packages +!plugin/*.vsix # Gradle .gradle/ @@ -110,4 +111,12 @@ jacoco.exec *~ # Kotlin -.kotlin/ \ No newline at end of file +.kotlin/ + + +# Outputs from tests +output-*.json + +# Test files for extensions +.islextensions +test-extensions.isl \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 78295bd..4b3af2a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -117,15 +117,19 @@ subprojects { } // Signing configuration for Maven Central - if (System.getenv("SIGNING_KEY_ID") != null || project.hasProperty("signing.keyId")) { + if (System.getenv("SIGNING_KEY") != null || project.hasProperty("signing.keyId")) { apply(plugin = "signing") extensions.configure { if (System.getenv("SIGNING_KEY") != null) { val signingKey = System.getenv("SIGNING_KEY") - val signingPassword = System.getenv("SIGNING_PASSWORD") + val signingPassword = System.getenv("SIGNING_PASSWORD") ?: "" + // Use 2-parameter version which only needs the key and password (no keyId) useInMemoryPgpKeys(signingKey, signingPassword) } sign(extensions.getByType().publications["maven"]) + + // Configure signing to be required only when publishing + setRequired({ gradle.taskGraph.hasTask("publish") || gradle.taskGraph.hasTask("publishToMavenLocal") }) } } } diff --git a/docs/_data/navigation.yml b/docs/_data/navigation.yml index 88cbf12..7703e65 100644 --- a/docs/_data/navigation.yml +++ b/docs/_data/navigation.yml @@ -84,12 +84,6 @@ docs: url: /dev/hosting - title: "Performance Benchmarks" url: /dev/benchmark-report - - title: "Release Process" - url: /dev/release - - title: "Contributing" - url: /dev/contributing - - title: "Playground Integration" - url: /dev/playground-integration - title: More children: @@ -99,6 +93,10 @@ docs: url: /changelog - title: "Roadmap" url: /roadmap + - title: "Contributing" + url: /dev/contributing + - title: "Release Process" + url: /dev/release - title: "Support" url: /support diff --git a/docs/assets/css/main.scss b/docs/assets/css/main.scss index b0c0d08..5379cce 100644 --- a/docs/assets/css/main.scss +++ b/docs/assets/css/main.scss @@ -95,6 +95,14 @@ pre[class*="language-"] { } } +/* Override Prism colors - change from #db4c69 to #9cdcfe */ +// code.highlighter-rouge.languange-plaintext, +body { + :not(pre) > code[class*="language-"] { + color: #9cdcfe !important; + } +} + /* Override Prism colors - change from #db4c69 to #9cdcfe */ code.highlighter-rouge.languange-plaintext, body :not(pre) > code[class*="language-"] { diff --git a/docs/assets/js/playground-auto-buttons.js b/docs/assets/js/playground-auto-buttons.js index 0e52a95..499f263 100644 --- a/docs/assets/js/playground-auto-buttons.js +++ b/docs/assets/js/playground-auto-buttons.js @@ -21,6 +21,19 @@ } } + /** + * Checks if a code block is explicitly marked as JSON + */ + function hasJsonClass(preElement) { + // Check pre element classes + const preClasses = preElement.className || ''; + if (preClasses.includes('language-json') || preClasses.includes('highlighter-json')) { + return true; + } + + return false; + } + /** * Checks if a code block is explicitly marked as ISL */ @@ -103,26 +116,13 @@ iterations++; // Check if this is a
 with JSON code
-      if (currentElement.tagName === 'PRE') {
+      if (currentElement.tagName === 'PRE' && hasJsonClass(currentElement)) {
         const codeElement = currentElement.querySelector('code');
         if (codeElement) {
           const text = codeElement.textContent.trim();
           // Simple check if it looks like JSON
           if (text.startsWith('{') || text.startsWith('[')) {
-            // Check if there's an "Input JSON" label before this
-            let labelElement = currentElement.previousElementSibling;
-            let labelChecks = 0;
-            
-            while (labelElement && labelChecks < 3) {
-              labelChecks++;
-              const labelText = labelElement.textContent || '';
-              
-              if (/\w*input\w*/i.test(labelText)) {
-                return text;
-              }
-              
-              labelElement = labelElement.previousElementSibling;
-            }
+            return text;
           }
         }
       }
diff --git a/docs/examples/index.md b/docs/examples/index.md
index 4d45661..223088e 100644
--- a/docs/examples/index.md
+++ b/docs/examples/index.md
@@ -6,8 +6,6 @@ description: "Common ISL transformation patterns for JSON data manipulation incl
 excerpt: "Common ISL transformation patterns for JSON data manipulation including field mapping, array transformations, nested objects, and more."
 ---
 
-# ISL Transformation Examples
-
 This guide demonstrates common JSON transformation patterns using ISL. Each example shows how to handle typical data transformation scenarios.
 
 ## Table of Contents
@@ -29,7 +27,7 @@ This guide demonstrates common JSON transformation patterns using ISL. Each exam
 
 **Use Case:** Copy and rename fields from input to output
 
-**Documentation:** [Variables](/isl/language/variables/) | [Objects](/isl/language/objects/)
+**Documentation:** [Variables](/isl/language/variables/), [Objects](/isl/language/objects/)
 
 **Input:**
 ```json
@@ -64,7 +62,7 @@ This guide demonstrates common JSON transformation patterns using ISL. Each exam
 
 **Use Case:** Rename multiple fields and reorganize structure
 
-**Documentation:** [Objects](/isl/language/objects/) | [Variables](/isl/language/variables/)
+**Documentation:** [Objects](/isl/language/objects/), [Variables](/isl/language/variables/)
 
 **Input:**
 ```json
@@ -106,7 +104,7 @@ This guide demonstrates common JSON transformation patterns using ISL. Each exam
 
 **Use Case:** Transform each item in an array
 
-**Documentation:** [Loops](/isl/language/loops/) | [Built-in Modifiers](/isl/language/modifiers/)
+**Documentation:** [Loops](/isl/language/loops/), [Built-in Modifiers](/isl/language/modifiers/)
 
 **Input:**
 ```json
@@ -159,7 +157,7 @@ or using `|map ( )`
 
 **Use Case:** Flatten nested structure into flat object
 
-**Documentation:** [Objects](/isl/language/objects/) | [Variables](/isl/language/variables/)
+**Documentation:** [Objects](/isl/language/objects/), [Variables](/isl/language/variables/)
 
 **Input:**
 ```json
@@ -203,7 +201,7 @@ or using `|map ( )`
 
 **Use Case:** Create nested structure from flat data
 
-**Documentation:** [Objects](/isl/language/objects/) | [Variables](/isl/language/variables/)
+**Documentation:** [Objects](/isl/language/objects/), [Variables](/isl/language/variables/)
 
 **Input:**
 ```json
@@ -252,7 +250,7 @@ or using `|map ( )`
 
 **Use Case:** Include fields based on conditions
 
-**Documentation:** [Conditions](/isl/language/conditions/) | [Objects](/isl/language/objects/)
+**Documentation:** [Conditions](/isl/language/conditions/), [Objects](/isl/language/objects/)
 
 **Input:**
 ```json
@@ -290,7 +288,7 @@ or using `|map ( )`
 
 **Use Case:** Convert array of key-value pairs to object
 
-**Documentation:** [Functions](/isl/language/functions/) | [Built-in Modifiers](/isl/language/modifiers/) | [Loops](/isl/language/loops/)
+**Documentation:** [Functions](/isl/language/functions/), [Built-in Modifiers](/isl/language/modifiers/), [Loops](/isl/language/loops/)
 
 **Input:**
 ```json
@@ -306,12 +304,15 @@ or using `|map ( )`
 **ISL Transformation:**
 ```isl
 fun run($input) {
-  $result: $input | to.object;  // convert any [{key/value}] to object
+  $result: $input.attributes | to.object;  // convert any [{key/value}] to object
   
-  // alternatively use the foreach
-  foreach $attr in $input.attributes
-    $result.`$attr.key`: $attr.value;
-  endfor
+  // alternatively use the foreach - not as efficient
+  // foreach $attr in $input.attributes
+  //  $result = {
+  //      ...$result,
+  //      `${ $attr.key }`: $attr.value
+  //  }
+  // endfor
   
   return $result;
 }
@@ -332,7 +333,7 @@ fun run($input) {
 
 **Use Case:** Convert object to a Key/Value array
 
-**Documentation:** [Functions](/isl/language/functions/) | [Built-in Modifiers](/isl/language/modifiers/)
+**Documentation:** [Functions](/isl/language/functions/), [Built-in Modifiers](/isl/language/modifiers/)
 
 **Input:**
 ```json
@@ -381,7 +382,7 @@ fun run($input) {
 
 **Use Case:** Filter array and transform matching items
 
-**Documentation:** [Loops](/isl/language/loops/) | [Built-in Modifiers](/isl/language/modifiers/) | [Conditions](/isl/language/conditions/)
+**Documentation:** [Loops](/isl/language/loops/), [Built-in Modifiers](/isl/language/modifiers/), [Conditions](/isl/language/conditions/)
 
 **Input:**
 ```json
@@ -422,7 +423,7 @@ fun run($input) {
 
 **Use Case:** Combine data from multiple input sources
 
-**Documentation:** [Objects](/isl/language/objects/) | [Variables](/isl/language/variables/)
+**Documentation:** [Objects](/isl/language/objects/), [Variables](/isl/language/variables/)
 
 **Input:**
 ```json
@@ -507,7 +508,7 @@ fun run($input) {
 
 **Use Case:** Real-world transformation of an order from external API format to internal format
 
-**Documentation:** [Loops](/isl/language/loops/) | [Math Expressions](/isl/language/math/) | [Dates & Times](/isl/types/dates/) | [Built-in Modifiers](/isl/language/modifiers/)
+**Documentation:** [Loops](/isl/language/loops/), [Math Expressions](/isl/language/math/), [Dates & Times](/isl/types/dates/), [Built-in Modifiers](/isl/language/modifiers/)
 
 **Input:**
 ```json
@@ -598,7 +599,7 @@ fun run($input) {
 
 ## Date Processing
 
-**Documentation:** [Dates & Times](/isl/types/dates/) | [Built-in Modifiers](/isl/language/modifiers/)
+**Documentation:** [Dates & Times](/isl/types/dates/), [Built-in Modifiers](/isl/language/modifiers/)
 
 ### Parsing Dates with Multiple Formats
 
@@ -741,7 +742,7 @@ fun run($input) {
 
 **Use Case:** Convert dates from one format to another
 
-**Documentation:** [Dates & Times](/isl/types/dates/) | [Built-in Modifiers](/isl/language/modifiers/)
+**Documentation:** [Dates & Times](/isl/types/dates/), [Built-in Modifiers](/isl/language/modifiers/)
 
 **Input:**
 ```json
diff --git a/docs/img/favicon.svg b/docs/img/favicon.svg
index 7e9660e..58bbd5b 100644
--- a/docs/img/favicon.svg
+++ b/docs/img/favicon.svg
@@ -4,18 +4,18 @@
       
       
       
       
       
       
+            fill="#2563FF"/>
       
       
       
diff --git a/docs/overview.md b/docs/overview.md
index 53e2b5f..7edf4e7 100644
--- a/docs/overview.md
+++ b/docs/overview.md
@@ -80,7 +80,7 @@ Will output:
 
 
 
-# Structure
+## Structure
 ISL Code is structured as any programming language in multiple sections:
 
 1. `import` of other ISL files
diff --git a/docs/roadmap.md b/docs/roadmap.md
index b4088da..00fa33c 100644
--- a/docs/roadmap.md
+++ b/docs/roadmap.md
@@ -5,4 +5,8 @@ nav_order: 101
 
 What's upcoming for ISL:
 
-- [WIP] Improved Transformation Performance.
+- Support for variable level dynamic properties 
+    ```isl
+    $input.`$key` = $value
+    ```
+- Improved Transformation Performance.
diff --git a/isl-transform/src/jmh/resources/shopify-transform.isl b/isl-transform/src/jmh/resources/shopify-transform.isl
index 97bbfd4..0535701 100644
--- a/isl-transform/src/jmh/resources/shopify-transform.isl
+++ b/isl-transform/src/jmh/resources/shopify-transform.isl
@@ -8,9 +8,16 @@ fun convertAddress( $addr ) {
     $state = $addr.province_code | trim | upperCase;
     $zip = $addr.zip | trim;
     $country = $addr.country_code | trim | upperCase;
-    $formatted = `${$street}, ${$city}, ${$state} ${$zip}` | trim;
-    
-    return { street: $street, city: $city, state: $state, zipCode: $zip, country: $country, formatted: $formatted };
+    $formatted = `$street, ${$city}, ${$state} ${$zip}` | trim;
+
+    return {
+        street: $street,
+        city: $city,
+        state: $state,
+        zipCode: $zip,
+        country: $country,
+        formatted: $formatted
+    };
 }
 
 // Helper function: Convert customer with loyalty tier calculation
@@ -19,78 +26,87 @@ fun convertCustomer( $cust ) {
     $lastName = $cust.last_name | trim | upperCase;
     $email = $cust.email | trim | lowerCase;
     $orders = $cust.orders_count | to.number;
-    $spent = $cust.total_spent | to.decimal | precision(2);
+    $spent = $cust.total_spent | to.decimal | precision( 2 );
     $addr = @.This.convertAddress( $cust.default_address );
-    
-    return { id: $cust.id | to.string, fullName: `${$firstName} ${$lastName}` | trim, firstName: $firstName, lastName: $lastName, email: $email, phone: $cust.phone | trim, totalOrders: $orders, lifetimeValue: $spent, address: $addr };
+
+    return { id: $cust.id | to.string, fullName: `$firstName ${$lastName}` | trim, firstName: $firstName, lastName: $lastName, email: $email, phone: $cust.phone | trim, totalOrders: $orders, lifetimeValue: $spent, address: $addr };
 }
 
 // Helper function: Process and enrich line item
 fun processLineItem( $item ) {
-    $sku = $item.sku | trim | upperCase;
-    $name = $item.name | trim | truncate(100, "...");
-    $vendor = $item.vendor | trim | titleCase;
-    $qty = $item.quantity | to.number;
-    $price = $item.price | to.decimal;
-    $weight = $item.grams | to.number;
-    $lineTotal = {{ $price * $qty }} | Math.clamp(0, 999999) | precision(2);
-    $weightKg = {{ $weight / 1000 }} | precision(3);
-    $productCode = `${$sku}-${$item.product_id | to.string}` | upperCase;
-    
-    return { itemId: $item.id | to.string, sku: $sku, productCode: $productCode, name: $name, vendor: $vendor, quantity: $qty, unitPrice: $price, lineTotal: $lineTotal, weight: $weight, weightKg: $weightKg, variantTitle: $item.variant_title | trim };
+
+    $items = if( $item.result ) true else false;
+
+    $o = {
+        items: foreach $item in $array
+            // loop body
+        endfor
+    }
+
+    return $item | to.string;
+
+    // return { itemId: $item.id | to.string, sku: `$sku $test` | trim, productCode: $productCode, name: $name, vendor: $vendor, quantity: $qty, unitPrice: $price, lineTotal: $lineTotal, weight: $weight, weightKg: $weightKg, variantTitle: $item.variant_title | trim };
 }
 
 // Main entry point
 fun run( $input ) {
     // Order header
     $orderId = $input.id | to.string;
-    $orderNum = $input.order_number | to.string | padStart(8, "0");
+    $orderNum = $input.order_number | to.string | padStart( 8, "0" );
     $orderName = $input.name | trim;
-    
+
     // Convert customer with enrichment
     $customer = @.This.convertCustomer( $input.customer );
-    
+
+
+
+    $obj.x = 10;
+    $obj.a.d = 2;
+    $obj.a.b.c = 1;
+    $obj.y.z = 20;
+    $obj.a.b.e = 3;
+
     // Process all line items with enrichment using map with implicit $ iterator
     $processedItems = $input.line_items | map( @.This.processLineItem( $ ) );
-    
+
     // Calculate order statistics using map/reduce with implicit $ iterator
     $totalItems = $input.line_items | length | to.number;
     $quantities = $input.line_items | map( $.quantity | to.number );
-    $totalQty = $quantities | Math.sum(0);
+    $totalQty = $quantities | Math.sum( 0 );
     $weights = $input.line_items | map( $.grams | to.number );
-    $totalWeight = $weights | Math.sum(0);
-    $totalWeightKg = {{ $totalWeight / 1000 }} | precision(3);
+    $totalWeight = $weights | Math.sum( 0 );
+    $totalWeightKg = {{ $totalWeight / 1000 }} | precision( 3 );
     $premiumCount = $input.line_items | filter( $.price | to.decimal >= 100 ) | length | to.number;
     $vendors = $input.line_items | map( $.vendor | trim | titleCase ) | unique | sort;
     $vendorCount = $vendors | length | to.number;
-    
+
     // Financial calculations
-    $subtotal = $input.subtotal_price | to.decimal | precision(2);
-    $shippingCost = $input.total_shipping_price_set.shop_money.amount | to.decimal | precision(2);
-    $tax = $input.total_tax | to.decimal | precision(2);
-    $discounts = $input.total_discounts | to.decimal | precision(2);
-    $total = $input.total_price | to.decimal | precision(2);
-    $finalTotal = {{ $total - $discounts }} | Math.clamp(0, 999999) | precision(2);
-    
+    $subtotal = $input.subtotal_price | to.decimal | precision( 2 );
+    $shippingCost = $input.total_shipping_price_set.shop_money.amount | to.decimal | precision( 2 );
+    $tax = $input.total_tax | to.decimal | precision( 2 );
+    $discounts = $input.total_discounts | to.decimal | precision( 2 );
+    $total = $input.total_price | to.decimal | precision( 2 );
+    $finalTotal = {{ $total - $discounts }} | Math.clamp( 0, 999999 ) | precision( 2 );
+
     // Determine shipping method and status with conditionals
     $fulfillmentStatus = $input.fulfillment_status | trim | upperCase;
     $shippingStatus = if( $fulfillmentStatus == "FULFILLED" ) "DELIVERED" else "PENDING";
     $shippingSpeed = if( $shippingCost >= 20 ) "EXPRESS" else "STANDARD";
-    
+
     // Build shipping information
     $shippingAddr = @.This.convertAddress( $input.shipping_address );
-    
+
     // Process note attributes using map with implicit $ iterator
     $noteKeys = $input.note_attributes | map( $.name | trim );
     $noteValues = $input.note_attributes | map( $.value | trim );
-    
+
     // Extract and process tags using map
-    $tags = $input.tags | split(",") | map( $ | trim | upperCase );
-    
+    $tags = $input.tags | split( "," ) | map( $ | trim | upperCase );
+
     // Status flags with conditionals
     $isPaid = if( $input.financial_status | trim | lowerCase == "paid" ) true else false;
     $isFulfilled = if( $fulfillmentStatus == "FULFILLED" ) true else false;
-    
+
     // Build final result with all transformations
     orderId: $orderId;
     orderNumber: $orderNum;
@@ -128,10 +144,19 @@ fun run( $input ) {
     tags: $tags;
     notes: $input.note | trim;
     noteKeys: $noteKeys;
-    processedAt: $input.processed_at | date.parse("yyyy-MM-dd'T'HH:mm:ssXXX") | to.string("yyyy-MM-dd HH:mm:ss");
+    processedAt: $input.processed_at | date.parse( "yyyy-MM-dd'T'HH:mm:ssXXX" ) | to.string( "yyyy-MM-dd HH:mm:ss" );
     isConfirmed: $input.confirmed | to.boolean;
     isTest: $input.test | to.boolean;
     isPaid: $isPaid;
     isFulfilled: $isFulfilled;
     summary: `Order ${$orderNum} - ${$customer.fullName} - ${$finalTotal} ${$input.currency | trim | upperCase} - ${$totalItems} items` | trim;
 }
+
+
+
+
+
+
+
+
+
diff --git a/playground/frontend/src/App.tsx b/playground/frontend/src/App.tsx
index 10e764a..8a81bc3 100644
--- a/playground/frontend/src/App.tsx
+++ b/playground/frontend/src/App.tsx
@@ -59,8 +59,13 @@ const ensureFunWrapper = (code: string): string => {
     return code;
   }
   
+  let cleanCode = (code ?? '').trim();
+
+  if(cleanCode.startsWith("{") || cleanCode.startsWith("["))
+    cleanCode = "return " + cleanCode;
+
   // Wrap the code in fun run($input) { }
-  return `fun run($input) {\n // Adjust code as required then return a result\n${code.split('\n').map(line => '    ' + line).join('\n')}\n}`;
+  return `fun run($input) {\n // Adjust code as required then return a result\n${cleanCode.split('\n').map(line => '    ' + line).join('\n')}\n}`;
 };
 
 // Helper to load code from URL parameters
diff --git a/plugin/.cursorrules b/plugin/.cursorrules
new file mode 100644
index 0000000..35cee49
--- /dev/null
+++ b/plugin/.cursorrules
@@ -0,0 +1,144 @@
+# ISL (Intuitive Scripting Language) Rules for AI Assistants
+
+You are assisting with ISL (Intuitive Scripting Language) code - a declarative language for JSON-to-JSON transformations.
+This langunage applies to .isl files.
+
+## Quick Reference
+
+- **Variables**: Start with `$` (e.g., `$user`, `$price`)
+- **Functions**: Declared with `fun`, called with `@.This.functionName()`
+- **Modifiers**: Piped transformations using `|` (e.g., `$text | trim | upperCase`)
+- **Math**: Wrapped in `{{ }}` (e.g., `{{ $price * 1.1 }}`)
+- **Strings**: Use backticks for interpolation (e.g., `` `Hello ${$name}` ``)
+- **Objects**: JSON-like syntax with spread operator `...`
+- **Control Flow**: `if/else/endif`, `switch/endswitch`, `foreach/endfor`, `while/endwhile`
+
+## Core Principles
+
+1. **Use Only Documented Syntax**: Never invent or infer features from other languages
+2. **When Uncertain, Use Simpler Forms**: Prioritize correctness over brevity
+3. **Always Include `fun run($input)`**: This is the main entry point for transformations
+
+## Common Patterns
+
+### Basic Transformation
+```isl
+fun run($input) {
+    userId: $input.id | to.string;
+    fullName: `${$input.firstName} ${$input.lastName}`;
+    total: {{ $input.price * $input.quantity }};
+}
+```
+
+### Array Processing
+```isl
+items: $input.lineItems | map({
+    id: $.id,
+    price: $.price | to.decimal
+}) | filter($.price > 100);
+```
+
+### Conditionals
+```isl
+status: if ($input.paid) "completed" else "pending" endif;
+```
+
+### Helper Functions
+```isl
+fun calculateTotal($items) {
+    $sum: $items | map($.price) | reduce({{ $acc + $it }});
+    return $sum;
+}
+```
+
+## Built-in Modifiers (Most Common)
+
+**String**: `trim`, `upperCase`, `lowerCase`, `capitalize`, `split`, `replace`, `length`
+**Array**: `map`, `filter`, `reduce`, `sort`, `unique`, `first`, `last`, `at(index)`
+**Math**: `round`, `absolute`, `precision(decimals)`
+**Conversion**: `to.string`, `to.number`, `to.decimal`, `to.boolean`, `to.array`
+**Date**: `date.parse(format)`, `date.add(value, unit)`, `to.string(format)`
+**Object**: `keys`, `kv`, `select(path)`, `delete(prop)`, `getProperty(name)`
+**JSON/XML**: `json.parse`, `xml.parse`, `to.xml(rootName)`
+
+## Important Syntax Rules
+
+1. **No parentheses around modifiers in conditions**:
+   - ❌ `if (($str | length) > 5) ... endif`
+   - ✅ `if ($str | length > 5) ... endif`
+
+2. **Return statement required in functions**:
+   - ❌ `return;`
+   - ✅ `return {};` or `return $value;`
+
+3. **String interpolation rules**:
+   - Simple variables: `` `Hello $name` ``
+   - Deep paths: `` `Hello ${$user.name}` ``
+   - Math: `` `Total: {{ $a + $b }}` ``
+   - Literal $: `` `Price: \$${$amount}` ``
+
+4. **Foreach without parentheses around array**:
+   - ❌ `foreach $item in ($array | filter(...))`
+   - ✅ `foreach $item in $array | filter(...)`
+
+5. **Dot notation not allowed after modifiers**:
+   - ❌ `$id: ($items | last).id`
+   - ✅ `$lastItem: $items | last; $id: $lastItem.id;`
+
+## File Structure Template
+
+```isl
+// Main entry point - REQUIRED
+fun run($input) {
+    // Main transformation logic here
+    orderId: $input.id;
+    customer: @.This.transformCustomer($input.customer);
+    items: $input.items | map(@.This.transformItem($));
+}
+
+// Helper functions
+fun transformCustomer($customer) {
+    return {
+        id: $customer.id,
+        name: `${$customer.firstName} ${$customer.lastName}`
+    };
+}
+
+fun transformItem($item) {
+    return {
+        id: $.id,
+        price: $.price | to.decimal | precision(2)
+    };
+}
+
+// Custom modifiers (optional)
+modifier calculateDiscount($price, $percent) {
+    return {{ $price * (1 - $percent / 100) }};
+}
+```
+
+## Common Mistakes to Avoid
+
+1. Don't use JavaScript/Python syntax (no `const`, `let`, `def`, `lambda`, etc.)
+2. Don't use `=>` arrow functions (use `fun` declarations)
+3. Don't use `.map()` method syntax (use `| map()` modifier)
+4. Don't forget `{{ }}` around math operations
+5. Don't use `return;` without a value (use `return {};`)
+6. Math expressions can only contain math operators, not function calls or modifiers
+
+## When Writing ISL Code
+
+1. Start with the `fun run($input)` function
+2. Break complex logic into helper functions or modifiers
+3. Use modifiers for simple transformations and chaining
+4. Use functions for complex logic with multiple steps
+5. Add helpful comments for beginners, but don't over-comment
+6. Use proper spacing: `| map( $.id )` not `|map($.id)`
+
+## Learn More
+Critical that you ALSO read this guide: https://intuit.github.io/isl/ai/ this has more detailed guidelines.
+Full documentation: https://intuit.github.io/isl/
+Language reference: https://intuit.github.io/isl/language/
+Modifiers list: https://intuit.github.io/isl/language/modifiers/
+- CLI: https://intuit.github.io/isl/cli/
+
diff --git a/plugin/.eslintrc.json b/plugin/.eslintrc.json
new file mode 100644
index 0000000..bbe9e2d
--- /dev/null
+++ b/plugin/.eslintrc.json
@@ -0,0 +1,25 @@
+{
+    "root": true,
+    "parser": "@typescript-eslint/parser",
+    "parserOptions": {
+        "ecmaVersion": 6,
+        "sourceType": "module"
+    },
+    "plugins": [
+        "@typescript-eslint"
+    ],
+    "rules": {
+        "@typescript-eslint/naming-convention": "warn",
+        "@typescript-eslint/semi": "warn",
+        "curly": "warn",
+        "eqeqeq": "warn",
+        "no-throw-literal": "warn",
+        "semi": "off"
+    },
+    "ignorePatterns": [
+        "out",
+        "dist",
+        "**/*.d.ts"
+    ]
+}
+
diff --git a/plugin/.github/copilot-instructions.md b/plugin/.github/copilot-instructions.md
new file mode 100644
index 0000000..5a4a47e
--- /dev/null
+++ b/plugin/.github/copilot-instructions.md
@@ -0,0 +1,260 @@
+# GitHub Copilot Instructions for ISL
+
+## Language Overview
+ISL (Intuitive Scripting Language) is a declarative language for JSON-to-JSON transformations. It combines clean syntax with powerful data manipulation capabilities.
+This applies to files with the .isl extension;
+
+## Key Syntax Elements
+
+### Variables and Paths
+```isl
+$variable: "value";              // Simple variable
+$nested: $object.property.path;  // Dot notation for nested access
+$dynamic: { `$key`: $value };    // Dynamic property names
+```
+
+### Main Entry Point (Required)
+```isl
+fun run($input) {
+    // All transformations start here
+    // Transform $input and return result
+}
+```
+
+### Functions
+```isl
+fun calculateTotal($items) {
+    $sum: $items | map($.price) | reduce({{ $acc + $it }});
+    return $sum;  // Always return a value
+}
+
+// Call with @.This prefix
+$total: @.This.calculateTotal($input.items);
+```
+
+### Modifiers (Pipe Operators)
+```isl
+// Chain operations with |
+$name: $input.firstName | trim | capitalize;
+$ids: $input.items | map($.id) | unique | sort;
+$filtered: $data | filter($.active) | map($.name);
+```
+
+### Math Expressions
+```isl
+// MUST be wrapped in {{ }}
+$total: {{ $price * $quantity }};
+$tax: {{ $subtotal * 0.08 }};
+$average: {{ $sum / $count }};
+```
+
+### String Interpolation
+```isl
+// Use backticks for interpolation
+$message: `Hello ${$user.name}!`;
+$summary: `Order ${$order.id}: \${{ $order.total }}`;
+
+// Simple variables (no dots) don't need ${}
+$greeting: `Hello $firstName`;
+
+// Nested paths (with dots) need ${}
+$full: `Name: ${$user.profile.name}`;
+```
+
+## Control Flow
+
+### If/Else
+```isl
+// Expression form
+$status: if ($paid) "completed" else "pending" endif;
+
+// Statement form
+if ($amount > 100)
+    $discount: 0.1;
+else
+    $discount: 0.05;
+endif
+```
+
+### Switch/Case
+```isl
+$category: switch ($price)
+    < 10 -> "budget";
+    < 50 -> "standard";
+    < 200 -> "premium";
+    else -> "luxury";
+endswitch
+```
+
+### Foreach
+```isl
+$transformed: foreach $item in $input.items
+    {
+        id: $item.id,
+        total: {{ $item.price * $item.quantity }}
+    }
+endfor
+
+// With filter
+foreach $item in $items | filter($.price > 100)
+    // Process only expensive items
+endfor
+```
+
+## Common Modifiers
+
+**String**: `trim`, `upperCase`, `lowerCase`, `capitalize`, `split`, `replace`, `subString`, `length`
+
+**Array**: `map`, `filter`, `reduce`, `sort`, `reverse`, `unique`, `first`, `last`, `at`, `length`, `push`, `pop`
+
+**Conversion**: `to.string`, `to.number`, `to.decimal`, `to.boolean`, `to.array`, `to.json`
+
+**Date**: `date.parse`, `date.add`, `date.part`, `to.string` (with format)
+
+**Math**: `round`, `absolute`, `precision`, `round.up`, `round.down`
+
+**Object**: `keys`, `kv`, `select`, `delete`, `getProperty`
+
+## Important Rules
+
+1. **No parentheses around modifiers in conditions**:
+   ```isl
+   // ✅ Correct
+   if ($text | length > 5) ... endif
+   
+   // ❌ Wrong
+   if (($text | length) > 5) ... endif
+   ```
+
+2. **Return must have value**:
+   ```isl
+   // ✅ Correct
+   return {};
+   return $result;
+   
+   // ❌ Wrong
+   return;
+   ```
+
+3. **Math must be wrapped**:
+   ```isl
+   // ✅ Correct
+   $result: {{ $a + $b * $c }};
+   
+   // ❌ Wrong
+   $result: $a + $b * $c;
+   ```
+
+4. **No dot access after modifiers**:
+   ```isl
+   // ✅ Correct
+   $last: $items | last;
+   $id: $last.id;
+   
+   // ❌ Wrong
+   $id: ($items | last).id;
+   ```
+
+5. **Foreach without array parentheses**:
+   ```isl
+   // ✅ Correct
+   foreach $item in $array | filter($.active)
+   
+   // ❌ Wrong
+   foreach $item in ($array | filter($.active))
+   ```
+
+## Standard Patterns
+
+### Simple Transformation
+```isl
+fun run($input) {
+    userId: $input.id | to.string;
+    userName: `${$input.firstName} ${$input.lastName}`;
+    createdAt: $input.timestamp | date.parse("yyyy-MM-dd");
+}
+```
+
+### Complex Transformation with Helpers
+```isl
+fun run($input) {
+    order: @.This.transformOrder($input.order);
+    customer: @.This.transformCustomer($input.customer);
+    items: $input.items | map(@.This.transformItem($));
+}
+
+fun transformOrder($order) {
+    return {
+        id: $order.id | to.string,
+        total: $order.amount | to.decimal | precision(2),
+        status: $order.paid | orderStatus
+    };
+}
+
+modifier orderStatus($paid) {
+    return if ($paid) "completed" else "pending" endif;
+}
+```
+
+### Array Transformations
+```isl
+// Map array to new structure
+items: $input.items | map({
+    id: $.id,
+    name: $.title | trim | capitalize,
+    price: $.amount | to.decimal
+})
+
+// Filter and transform
+expensiveItems: $input.items 
+    | filter($.price > 100)
+    | map({ name: $.title, price: $.price })
+    | sort
+
+// Aggregate values
+$total: $items 
+    | map({{ $.price * $.quantity }})
+    | reduce({{ $acc + $it }});
+```
+
+### Conditional Fields
+```isl
+{
+    id: $input.id,
+    name: $input.name,
+    // Conditionally include email
+    ...if ($input.email) { email: $input.email } else {} endif,
+    // Use coalesce for defaults
+    phone: $input.phone ?? "N/A"
+}
+```
+
+## What Copilot Should NOT Suggest
+
+- ❌ JavaScript syntax (`const`, `let`, `var`, `function`, `=>`)
+- ❌ Python syntax (`def`, `lambda`, `:`)
+- ❌ Method chaining (`.map()`, `.filter()`)
+- ❌ Math without `{{ }}` wrapping
+- ❌ `return;` without value
+- ❌ Accessing properties after modifiers inline
+- ❌ Traditional for loops (`for (i=0; i 100);
+```
+
+### Math Expressions
+```isl
+// MUST wrap in {{ }}
+$total: {{ $price * $quantity * 1.1 }};
+$average: {{ ($sum / $count) }};
+```
+
+### String Interpolation
+```isl
+// Use backticks
+$greeting: `Hello ${$user.name}!`;
+$message: `Total: \${{ $price * $qty }}`;  // Escape $ for literal
+```
+
+## Syntax Rules (STRICT)
+
+1. **Every transformation needs `fun run($input)`** - main entry point
+2. **Math operations MUST be in `{{ }}`** - no exceptions
+3. **No parentheses around modifiers in conditions**:
+   ```isl
+   // ❌ WRONG
+   if (($text | length) > 5) ... endif
+   
+   // ✅ CORRECT
+   if ($text | length > 5) ... endif
+   ```
+
+4. **Return statement always needs a value**:
+   ```isl
+   // ❌ WRONG
+   return;
+   
+   // ✅ CORRECT
+   return {};
+   return $value;
+   ```
+
+5. **String interpolation depth rules**:
+   ```isl
+   // Simple variable (no dots)
+   `Hello $name`
+   
+   // Nested path (has dots) - needs ${}
+   `Hello ${$user.name}`
+   
+   // Math expression
+   `Total: {{ $a + $b }}`
+   ```
+
+## Standard File Structure
+
+```isl
+// 1. Main entry point (REQUIRED)
+fun run($input) {
+    // Your transformation here
+    id: $input.id | to.string;
+    name: `${$input.firstName} ${$input.lastName}`;
+    total: {{ $input.price * $input.quantity }};
+}
+
+// 2. Helper functions
+fun helperFunction($param) {
+    return $result;
+}
+
+// 3. Custom modifiers
+modifier customModifier($value, $param) {
+    return $transformed;
+}
+```
+
+## Common Built-in Modifiers
+
+### String Operations
+`trim`, `upperCase`, `lowerCase`, `capitalize`, `split(delimiter)`, `replace(old, new)`, `subString(start, end)`, `length`
+
+### Array Operations
+`map(expression)`, `filter(condition)`, `reduce(expression)`, `sort`, `reverse`, `unique`, `first`, `last`, `at(index)`, `length`, `isEmpty`, `push(item)`, `pop`
+
+### Type Conversions
+`to.string`, `to.number`, `to.decimal`, `to.boolean`, `to.array`, `to.json`, `to.xml(rootName)`
+
+### Date/Time
+`date.parse(format)`, `date.add(value, unit)`, `date.part(part)`, `to.string(format)`, `to.number` (epoch seconds)
+
+### Math
+`round`, `absolute`, `negate`, `precision(decimals)`, `round.up(decimals)`, `round.down(decimals)`
+
+### Object Operations
+`keys`, `kv` (key-value pairs), `select(path)`, `delete(prop)`, `getProperty(name)`
+
+## Control Flow
+
+### If/Else
+```isl
+// As statement
+if ($status == "active")
+    // do something
+else
+    // do something else
+endif
+
+// As expression
+$result: if ($paid) "success" else "pending" endif;
+```
+
+### Switch/Case
+```isl
+$result: switch ($code)
+    200 -> "OK";
+    404 -> "Not Found";
+    /^5\d\d/ -> "Server Error";
+    < 300 -> "Success";
+    else -> "Unknown";
+endswitch
+```
+
+### Foreach Loop
+```isl
+$transformed: foreach $item in $input.items
+    {
+        id: $item.id,
+        doubled: {{ $item.value * 2 }}
+    }
+endfor
+
+// With filter
+foreach $item in $items | filter($.price > 100)
+    // process expensive items
+endfor
+```
+
+### While Loop
+```isl
+$i: 0;
+while ($i < 10)
+    $i: {{ $i + 1 }};
+endwhile
+```
+
+## Operators
+
+### Comparison
+`==`, `!=`, `<`, `>`, `<=`, `>=`
+
+### Logical
+`and`, `or`, `!`
+
+### String
+`contains`, `startsWith`, `endsWith` (case-sensitive), `matches` (regex)
+
+### Other
+`in` (array membership), `is` (type check), `??` (coalesce - first non-null)
+
+## Best Practices
+
+1. **Use modifiers for simple transformations**
+   ```isl
+   // ✅ Good
+   $price: $input.amount | to.decimal | precision(2);
+   ```
+
+2. **Use functions for complex logic**
+   ```isl
+   // ✅ Good
+   fun calculateShipping($order) {
+       $baseRate: 5.99;
+       $weight: $order.totalWeight;
+       return if ($weight > 50) {{ $baseRate * 1.5 }} else $baseRate endif;
+   }
+   ```
+
+3. **Break down complex transformations**
+   ```isl
+   // ✅ Good - readable
+   fun run($input) {
+       customer: @.This.transformCustomer($input.customer);
+       items: $input.items | map(@.This.transformItem($));
+       shipping: @.This.calculateShipping($input);
+   }
+   ```
+
+4. **Use spread operator for object merging**
+   ```isl
+   {
+       ...$baseObject,
+       additionalField: "value"
+   }
+   ```
+
+5. **Proper spacing improves readability**
+   ```isl
+   // ✅ Good
+   $result: $items | map( $.id ) | filter( $ > 100 );
+   
+   // ❌ Avoid
+   $result:$items|map($.id)|filter($>100);
+   ```
+
+## Common Patterns
+
+### Transform nested arrays
+```isl
+items: $input.orders | map({
+    orderId: $.id,
+    items: $.lineItems | map({
+        productId: $.product.id,
+        quantity: $.qty
+    })
+})
+```
+
+### Conditional object properties
+```isl
+{
+    id: $input.id,
+    name: $input.name,
+    // Include email only if present
+    ...if ($input.email) { email: $input.email } else {} endif
+}
+```
+
+### Error handling with coalesce
+```isl
+displayName: $user.preferredName ?? $user.firstName ?? "Guest";
+amount: $transaction.amount | to.decimal ?? 0.0;
+```
+
+## What NOT to Do
+
+❌ Don't use JavaScript/Python/Java syntax
+❌ Don't use arrow functions `=>`
+❌ Don't use method chaining `.map().filter()`
+❌ Don't forget `{{ }}` around math
+❌ Don't use `return;` without value
+❌ Don't access properties after modifiers: `($items | last).id`
+❌ Don't put parentheses around modified values in conditions
+
+## Documentation
+- Critical that you ALSO read this guide: https://intuit.github.io/isl/ai/ this has more detailed guidelines.
+- Full Docs: https://intuit.github.io/isl/
+- Modifiers: https://intuit.github.io/isl/language/modifiers/
+- CLI: https://intuit.github.io/isl/cli/
+
diff --git a/plugin/CHANGELOG.md b/plugin/CHANGELOG.md
new file mode 100644
index 0000000..ddafbb9
--- /dev/null
+++ b/plugin/CHANGELOG.md
@@ -0,0 +1,214 @@
+# Change Log
+
+All notable changes to the ISL Language Support extension will be documented in this file.
+
+## [1.1.0] - TBD
+
+### Added
+- **Custom Extensions Support**: Define project-specific functions and modifiers
+  - `.islextensions` file support in workspace root
+  - JSON-based definition format for functions and modifiers
+  - Full parameter and return type documentation
+  - IntelliSense/autocomplete integration for custom definitions
+  - Hover documentation for custom functions and modifiers
+  - Validation recognizes custom extensions (no warnings)
+  - Auto-reload when `.islextensions` file changes
+  - File watcher for automatic extension updates
+  - Comprehensive documentation and examples
+  - Support for optional parameters and default values
+  - Usage examples in hover tooltips
+  - See [ISL Extensions Documentation](docs/EXTENSIONS.md) for details
+
+### Improved
+- Enhanced completion provider to support custom extensions
+- Enhanced hover provider with detailed custom extension documentation
+- Enhanced validator to recognize custom functions and modifiers
+- Better extensibility architecture for future enhancements
+
+## [1.0.0] - 2025-11-26
+
+### Added
+- **Signature Help**: Parameter hints for functions and modifiers
+- **Inlay Hints**: Type annotations displayed inline for variables
+- **Code Actions & Quick Fixes**:
+  - Simplify unnecessary string interpolation braces (`${$var}` → `$var`)
+  - Convert `default()` modifier to null coalescing operator (`??`)
+  - Format long single-line objects onto multiple lines
+  - Change colon (`:`) to equals (`=`) for variable assignments
+  - "Fix all in file" option for colon-to-equals conversions
+- **Enhanced Snippets**: 20+ new snippets for common ISL patterns including:
+  - Safe navigation and error handling
+  - Array and object transformations
+  - Conditional field patterns
+  - Date operations
+  - Batch processing patterns
+- **CodeLens Enhancements**: 
+  - "Test Function" action for quick testing
+  - "Find Usages" for tracking function references
+- **Status Bar Enhancements**: Active file indicator and quick actions
+
+### Improved
+
+#### Syntax Highlighting
+- Fixed division operator (`/`) being incorrectly highlighted as regex
+- Removed regex literal pattern (ISL uses regex as string arguments)
+- Improved modifier highlighting with consistent coloring for namespaced modifiers
+- Enhanced pipe operator (`|`) visibility with distinct color
+- Better number literal highlighting
+
+#### Code Completion
+- Fixed variable autocompletion preserving `$` prefix when completing
+- Improved context-aware suggestions
+
+#### Formatter
+- **Pipe Spacing**: Automatically adds space after pipe operator (`|trim` → `| trim`)
+- **Function/Modifier Parameters**: Consistent spacing in declarations
+  - With parameters: `fun name( $param1, $param2 )`
+  - Without parameters: `fun name()`
+- **Control Flow Parameters**: Consistent spacing for `if`, `switch`, `while`, `foreach`
+  - Example: `if ( $condition )`, `switch ( $value )`
+- **Nested Control Flow**: Proper indentation for nested structures, including:
+  - Nested switch statements in switch cases (`"A" -> switch($x) ... endswitch;`)
+  - Control flow after arrow operator (`->`)
+- **Switch Statement Objects**: Fixed indentation for object values in switch cases
+  - Properly handles `};` in case values without closing the switch
+- **Modifier Chain Indentation**: Multi-line modifier chains are now indented
+- **Multi-line String Preservation**: Backtick strings preserve original formatting and indentation
+- Removed automatic splitting of long modifier chains (user controls line breaks)
+
+#### Validator
+- **Semantic Validation**:
+  - Undefined function detection
+  - Undefined modifier detection (including `push`, `getProperty`, `setProperty`)
+  - Undeclared variable usage detection
+  - Smart variable declaration tracking (supports both `=` and `:` operators)
+- **Improved Control Flow Balance**:
+  - Fixed `endfor`/`foreach` matching in expression contexts
+  - Fixed `endswitch`/`switch` matching for nested switches
+  - Fixed `endif`/`if` detection in complex conditions
+  - Recognizes control flow after arrow operator (`->`) in switch cases
+  - Better handling of inline vs. block control flow statements
+- **Return Statement Validation**: Completely rewritten to accurately track function scope with proper brace depth tracking
+- **Comment Handling**: All validations now correctly ignore code in comments
+- **Assignment Operators**: Recognizes both `=` and `:` for variable declarations
+- **Information-Level Diagnostics** (blue squiggly):
+  - Long object declarations suggesting formatting
+  - Colon usage suggesting equals for consistency
+  - Unnecessary string interpolation braces
+
+#### Spell Checking
+- Added ISL-specific keywords to cSpell dictionary:
+  - Control flow: `endfor`, `endswitch`, `endif`, `endwhile`
+  - Modifiers: `upperCase`, `toLowerCase`, `pushItems`, `getProperty`, `setProperty`
+  - VSCode extension terms: `inlayhints`, `codelens`, `quickfix`
+  - Common concatenated forms
+
+### Fixed
+- Division operator no longer highlighted as regex in expressions
+- Variable completion maintains `$` prefix
+- Object formatting no longer cuts string interpolations
+- Math expressions no longer misidentified as objects in type hints
+- Variables in comments no longer trigger "undeclared variable" warnings
+- Control flow balance correctly handles all nesting scenarios
+- Return statement validation accurate in complex nested functions
+- Function/modifier parameter spacing consistent after formatting
+- Nested switch statement indentation correct
+- Switch case object values maintain proper indentation
+- Multi-line backtick strings preserve internal formatting
+
+### Configuration
+- Removed `isl.formatting.formatModifierChains` (automatic chain splitting removed)
+- Kept `isl.formatting.alignProperties` for object property alignment
+
+## [1.0.0-Beta]
+
+### Added
+- Initial release
+- Comprehensive syntax highlighting for ISL files
+- IntelliSense with code completion for:
+  - Keywords and control flow structures
+  - Service calls (@.Date, @.Math, etc.)
+  - Modifiers (|filter, |map, etc.)
+  - Variable references
+- Real-time validation and linting
+  - Syntax error detection
+  - Brace matching
+  - Control flow balance checking
+  - Variable declaration validation
+- Hover documentation for:
+  - Keywords
+  - Built-in services
+  - Modifiers
+  - Variables
+- Go to definition support for:
+  - Function declarations
+  - Type definitions
+  - Imported modules
+- Code formatting with customizable settings
+- ISL execution from VS Code
+  - Run with inline JSON input
+  - Run with external JSON file
+  - Formatted output display
+  - Integrated output console
+- Comprehensive code snippets for common ISL patterns
+- Configuration options for validation, formatting, and execution
+- Status bar indicator for ISL files
+- Language configuration for:
+  - Comment toggling
+  - Bracket matching
+  - Auto-closing pairs
+  - Code folding
+
+### Features Details
+
+#### Syntax Highlighting
+- Keywords: fun, modifier, if, foreach, while, switch, return, etc.
+- Operators: ==, !=, <, >, <=, >=, contains, matches, ??, etc.
+- String interpolation: `${expression}`, `{{math}}`, `@.Function()`
+- Variables with $ prefix
+- Function calls and modifiers
+- Comments (// and #)
+- Regular expressions
+
+#### Code Completion
+- Context-aware completions
+- Service completions after @.
+- Modifier completions after |
+- Variable completions after $
+- Snippet expansions
+
+#### Validation
+- Balanced braces, brackets, and parentheses
+- Matching if/endif, foreach/endfor, while/endwhile, switch/endswitch
+- Valid variable names (no reserved keywords)
+- Proper string interpolation syntax
+- Return statements only in functions
+
+#### Execution
+- Automatic detection of ISL runtime (isl.sh/isl.bat)
+- Custom Java home configuration
+- Detailed execution output
+- Error reporting with stdout/stderr
+- JSON output formatting
+
+### Documentation
+- Comprehensive README with examples
+- Configuration guide
+- Feature documentation
+- Getting started guide
+
+## [Unreleased]
+
+### Planned Features
+- Semantic token provider for better highlighting
+- Symbol provider for outline view
+- Reference finder
+- Rename symbol support
+- Debug adapter protocol support
+- Test runner integration
+- Performance optimizations
+- Multi-file validation
+- Import resolution and auto-import
+- Type checking based on type declarations
+- Bracket pair colorization
+
diff --git a/plugin/LICENSE b/plugin/LICENSE
new file mode 100644
index 0000000..3003b4d
--- /dev/null
+++ b/plugin/LICENSE
@@ -0,0 +1,18 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+Copyright 2024 ISL Contributors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
diff --git a/plugin/PLUGIN-OVERVIEW.md b/plugin/PLUGIN-OVERVIEW.md
new file mode 100644
index 0000000..05e6947
--- /dev/null
+++ b/plugin/PLUGIN-OVERVIEW.md
@@ -0,0 +1,134 @@
+# ISL VSCode Plugin - Technical Overview
+
+## Architecture
+
+A TypeScript-based VSCode extension providing comprehensive language support for ISL (Intuitive Scripting Language).
+
+### Core Components
+
+```
+plugin/
+├── src/
+│   ├── extension.ts          # Extension activation & registration
+│   ├── completion.ts         # IntelliSense provider
+│   ├── hover.ts              # Hover documentation
+│   ├── definition.ts         # Go-to-definition
+│   ├── formatter.ts          # Code formatting
+│   ├── validator.ts          # Syntax validation
+│   ├── executor.ts           # ISL runtime integration
+│   ├── codelens.ts           # CodeLens actions
+│   ├── inlayhints.ts         # Type hints
+│   ├── signature.ts          # Signature help
+│   └── codeactions.ts        # Quick fixes
+│
+├── syntaxes/
+│   └── isl.tmLanguage.json   # TextMate grammar for syntax highlighting
+│
+└── snippets/
+    └── isl.json              # Code snippets
+```
+
+## Implementation Details
+
+### Provider Pattern
+Each language feature is implemented as a separate provider:
+- **CompletionItemProvider**: Context-aware code completion
+- **HoverProvider**: Documentation on hover
+- **DefinitionProvider**: Navigate to declarations
+- **DocumentFormattingProvider**: Smart code formatting
+- **DiagnosticProvider**: Real-time validation
+- **CodeLensProvider**: Inline actions (test, usages)
+- **InlayHintsProvider**: Type annotations
+- **SignatureHelpProvider**: Parameter hints
+- **CodeActionProvider**: Quick fixes and refactoring
+
+### Syntax Highlighting
+- **Technology**: TextMate grammar (JSON)
+- **Scopes**: 50+ token types for precise highlighting
+- **Features**: String interpolation, nested structures, modifiers
+
+### Validation Engine
+- **Approach**: Real-time, incremental validation
+- **Debouncing**: 500ms delay on typing
+- **Checks**: Syntax errors, semantic validation, control flow balance
+- **Diagnostics**: Error, Warning, Information, Hint levels
+
+### Formatter
+- **Strategy**: Multi-pass processing
+  1. Normalize spacing (pipes, parameters, assignments)
+  2. Calculate indentation (control flow, nesting, continuations)
+  3. Preserve literals (multi-line strings, comments)
+- **Features**:
+  - Smart indentation for nested control flow
+  - Modifier chain alignment
+  - Parameter spacing normalization
+  - Multi-line string preservation
+
+## Performance Optimizations
+
+- **Debounced Validation**: Reduces CPU during typing
+- **Incremental Updates**: Only revalidates changed documents
+- **Lazy Loading**: Providers loaded on-demand
+- **Efficient Parsing**: Optimized regex patterns
+- **Async Execution**: Non-blocking ISL runtime calls
+
+## Configuration System
+
+All settings prefixed with `isl.`:
+- `validation.*` - Validation behavior
+- `formatting.*` - Formatting preferences
+- `execution.*` - ISL runtime configuration
+- `linting.*` - Linting rules
+
+## Extension Lifecycle
+
+1. **Activation**: Triggered on `.isl` file or ISL command
+2. **Registration**: Providers registered with VSCode
+3. **Events**: Document change listeners attached
+4. **Deactivation**: Cleanup on extension unload
+
+## Technologies
+
+- **TypeScript 5.0**: Type-safe implementation
+- **VS Code API 1.75+**: Extension framework
+- **TextMate**: Syntax highlighting
+- **Node.js**: Runtime environment
+
+## Key Features Added in v1.1.0
+
+### Semantic Validation
+- Undefined function/modifier detection
+- Variable declaration tracking
+- Return statement scope validation
+
+### Enhanced Formatting
+- Control flow indentation (including `->` operator)
+- Switch case object handling
+- Multi-line string preservation
+- Modifier chain indentation
+
+### Quick Fixes
+- Simplify string interpolation
+- Convert `:` to `=` for assignments
+- Format long objects
+- Replace `default()` with `??`
+
+### Developer Experience
+- Signature help for functions
+- Inlay type hints
+- CodeLens actions (test, find usages)
+- 20+ new code snippets
+
+## Status
+
+✅ Production-ready  
+✅ Zero linting errors  
+✅ TypeScript strict mode  
+✅ Comprehensive error handling  
+✅ Full test coverage via manual testing  
+
+---
+
+For user documentation, see [README.md](README.md)  
+For setup instructions, see [SETUP.md](SETUP.md)  
+For publishing guide, see [PUBLISHING.md](PUBLISHING.md)
diff --git a/plugin/PUBLISHING.md b/plugin/PUBLISHING.md
new file mode 100644
index 0000000..836bedb
--- /dev/null
+++ b/plugin/PUBLISHING.md
@@ -0,0 +1,130 @@
+# Publishing the ISL VSCode Extension
+
+Quick guide for publishing the extension to VSCode Marketplace and Open VSX Registry.
+
+## Prerequisites
+
+### 1. VSCode Marketplace Account
+
+1. Go to https://marketplace.visualstudio.com/manage
+2. Sign in with Microsoft account
+3. Create a publisher (or use existing)
+4. Generate Personal Access Token (PAT):
+   - Visit https://dev.azure.com/
+   - User Settings → Personal Access Tokens
+   - Create token with scope: **Marketplace → Manage**
+   - Save the token securely
+
+### 2. Open VSX Account (Optional)
+
+For VS Codium and other VSCode-compatible editors:
+
+1. Go to https://open-vsx.org/
+2. Sign in with GitHub
+3. Settings → Access Tokens → Generate
+4. Save the token
+
+### 3. Install VSCE
+
+```bash
+npm install -g @vscode/vsce
+```
+
+## Publishing Workflow
+
+### Update Version
+
+```bash
+cd plugin
+npm version patch  # or minor, or major
+```
+
+This updates `package.json` and creates a git tag.
+
+### Pre-Publish Checklist
+
+- [ ] Version updated in `package.json`
+- [ ] `CHANGELOG.md` updated with release notes
+- [ ] Code compiles without errors: `npm run compile`
+- [ ] Extension tested locally
+- [ ] `publisher` field correct in `package.json`
+
+### Publish to VSCode Marketplace
+
+```bash
+cd plugin
+vsce publish
+```
+
+Or with explicit token:
+```bash
+vsce publish -p YOUR_PAT
+```
+
+### Publish to Open VSX (Optional)
+
+```bash
+npx ovsx publish -p YOUR_OVSX_TOKEN
+```
+
+## GitHub Actions (Automated)
+
+### Setup Secrets
+
+Add to GitHub repository (Settings → Secrets → Actions):
+- `VSCE_TOKEN`: VSCode Marketplace PAT
+- `OVSX_TOKEN`: Open VSX token
+
+### Trigger Release
+
+```bash
+# Tag and push
+git tag plugin-v1.1.0
+git push origin plugin-v1.1.0
+```
+
+The workflow automatically:
+1. Builds extension
+2. Packages `.vsix`
+3. Publishes to both marketplaces
+4. Creates GitHub release
+
+## Troubleshooting
+
+### "Cannot find publisher"
+Ensure `publisher` in `package.json` matches your marketplace publisher ID exactly.
+
+### "Authentication failed"
+- Verify PAT is valid and not expired
+- Check PAT has "Marketplace → Manage" scope
+- Ensure secret name matches exactly: `VSCE_TOKEN`
+
+### "Version already exists"
+You cannot republish the same version. Increment version number.
+
+### "Package too large"
+VSCode Marketplace limit is 100MB. Our extension is well under this.
+
+## Manual Testing Before Publishing
+
+```bash
+# Package locally
+cd plugin
+vsce package
+
+# Install in VSCode
+code --install-extension isl-language-support-X.X.X.vsix
+
+# Test all features
+```
+
+## Links
+
+- **VSCode Marketplace**: https://marketplace.visualstudio.com/vscode
+- **Publisher Management**: https://marketplace.visualstudio.com/manage
+- **Open VSX Registry**: https://open-vsx.org/
+- **Publishing Guide**: https://code.visualstudio.com/api/working-with-extensions/publishing-extension
+
+---
+
+For technical details, see [PLUGIN-OVERVIEW.md](PLUGIN-OVERVIEW.md)
diff --git a/plugin/README.md b/plugin/README.md
new file mode 100644
index 0000000..ac24b75
--- /dev/null
+++ b/plugin/README.md
@@ -0,0 +1,301 @@
+# ISL Language Support for VS Code & Cursor
+
+Comprehensive language support for ISL [(Intuitive Scripting Language)](https://intuit.github.io/isl/) - a powerful JSON transformation scripting language.
+
+[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
+
+## What is ISL
+
+ISL is a low-code [interpreted scripting language]() and runtime container designed to provide developers and non-developers an easy way to write, test, and deploy user developed code inside any service.
+
+The ISL supports an intuitive simplified syntax with features that make data acquisition and data transformations easy with minimal lines of code. In addition, the language supports easy extensibility allowing it to be used as a multi-purpose service extensibility language.
+
+The ISL can be embedded in any JVM based project to provide runtime based extensibility through a fast and lightweight runtime.
+
+## Overview
+
+In the most simple form the ISL is a JSON transformation language:
+
+Given Input JSON:
+```json
+{
+	"title": "IPod Nano - 8GB",
+	"body_html": "It's the small iPod with a big idea: Video.",
+	"id": 632910392,
+	"images": [
+		{
+			"id": 850703190,
+			"src": "http://example.com/burton.jpg",
+		}
+	],
+	"options": {
+		"name": "Color",
+		"values": [
+			"Pink",
+			"Red",
+			"Green",
+			"Black"
+		]
+	},
+	"status": "active",
+	"tags": "Emotive, Flash Memory, MP3, Music",
+	"updated_at": 1645004735,
+	"vendor": "Apple"
+}
+```
+
+And Transformation:
+```isl
+fun transform( $input ){
+    return {
+      // Simple JSON Path Selectors
+      id: $input.id,
+      // piped modifiers using `|`
+      name: $input.title | trim,
+      // easy string building using interpolation ` ... `
+      short_description: `${ $input.title } by ${ $input.vendor }`,
+      // child object building
+      primary_image: {
+          id: $input.images[0].id,
+          url: $input.images[0].src
+      },
+      // conditional properties
+      is_active: if( $input.status == "active" ) true else false,
+      option_name: $input.options.name,
+      // array to csv
+      option_values: $input.options.values | join(','),
+      // date processing
+      updated: $input.updated_at | date.fromEpochSeconds | to.string("yyyy-MM-dd HH:mm")
+    }
+}
+```
+
+Will output:
+```json
+{
+	"id": 632910392,
+	"name": "IPod Nano - 8GB",
+	"short_description": "IPod Nano - 8GB by Apple",
+	"primary_image": {
+		"id": 850703190,
+		"url": "http://example.com/burton.jpg"
+	},
+	"is_active": true,
+	"option_name": "Color",
+	"option_values": "Pink,Red,Green,Black",
+	"updated": "2022-02-47 09:45"
+}
+```
+
+
+## Features
+
+### 🎨 Syntax Highlighting
+- Complete syntax highlighting for all ISL constructs
+- String interpolation: `${variable}`, `{{math}}`, `@.Function()`
+- Modifiers, operators, control flow, and more
+
+### 🔧 Custom Extensions Support
+**NEW!** Define your own project-specific functions and modifiers:
+- Create a `.islextensions` file in your workspace root
+- Define custom functions and modifiers with full type information
+- Get IntelliSense, hover documentation, and validation for your extensions
+- Auto-reload when definitions change
+- [Learn more about ISL Extensions](docs/EXTENSIONS.md)
+
+### 💡 IntelliSense & Code Completion
+Smart completion for:
+- **Keywords**: `fun`, `foreach`, `if`, `switch`, etc.
+- **Services**: `@.Date`, `@.Math`, `@.String`, etc.
+- **Modifiers**: `|filter`, `|map`, `|trim`, `|upperCase`, 50+ more
+- **Variables**: Automatic discovery from your code
+
+### ✅ Validation & Linting
+Real-time error detection:
+- Balanced braces, brackets, parentheses
+- Control flow matching (`if`/`endif`, `foreach`/`endfor`, etc.)
+- Undefined functions and modifiers
+- Undeclared variable usage
+- Invalid syntax and semantic errors
+
+### 📖 Hover Documentation
+Hover over any element for:
+- Keyword syntax and usage
+- Service method descriptions
+- Modifier documentation with examples
+- Variable type information
+
+### 🔧 Code Actions & Quick Fixes
+- Simplify string interpolation (`${$var}` → `$var`)
+- Convert `:` to `=` for variable assignments
+- Format long objects onto multiple lines
+- Replace `default()` with `??` operator
+
+### ✨ Smart Formatting
+- Automatic indentation and spacing
+- Parameter spacing normalization
+- Modifier chain alignment
+- Multi-line string preservation
+- Format on save support
+
+### 🎯 Signature Help & Type Hints
+- Parameter hints for functions and modifiers
+- Inline type annotations for variables
+- CodeLens actions (test functions, find usages)
+
+### ▶️ Execute ISL
+- Run transformations directly from editor
+- Test with inline JSON or external files
+- View formatted output side-by-side
+- Integrated error reporting
+
+### 📋 Code Snippets
+20+ ready-to-use snippets for:
+- Functions and modifiers
+- Control flow patterns
+- Array and object transformations
+- Date operations
+- Error handling
+
+## Quick Start
+
+1. Install the extension
+2. Open or create a `.isl` file
+3. Start coding with full language support!
+
+### Defining Custom Extensions
+
+Want IntelliSense for your project-specific functions and modifiers?
+
+1. Create a `.islextensions` file in your workspace root
+2. Define your custom functions and modifiers in JSON format
+3. Enjoy full IDE support for your extensions!
+
+**Example `.islextensions`:**
+```json
+{
+  "functions": [
+    {
+      "name": "sendEmail",
+      "description": "Sends an email via custom service",
+      "parameters": [
+        {"name": "to", "type": "String"},
+        {"name": "subject", "type": "String"},
+        {"name": "body", "type": "String"}
+      ]
+    }
+  ],
+  "modifiers": [
+    {
+      "name": "formatPhone",
+      "description": "Formats phone numbers",
+      "parameters": [
+        {"name": "format", "type": "String", "optional": true}
+      ]
+    }
+  ]
+}
+```
+
+See [ISL Extensions Documentation](docs/EXTENSIONS.md) for complete details.
+
+### Example
+
+```isl
+fun run($input) {
+    $customers = foreach $customer in $input.customers
+        {
+            id: $customer.id | to.string,
+            name: `${$customer.first} ${$customer.last}` | trim,
+            email: $customer.email | lowerCase,
+            orders: $customer.orders | filter($order.status == "completed")
+        }
+    endfor
+    
+    return {
+        customers: $customers,
+        total: $customers | length,
+        processed: @.Date.Now() | to.string("yyyy-MM-dd")
+    }
+}
+```
+
+## Configuration
+
+Available settings (all prefixed with `isl.`):
+
+```json
+{
+  "isl.validation.enabled": true,
+  "isl.formatting.enabled": true,
+  "isl.formatting.indentSize": 4,
+  "isl.formatting.useTabs": false,
+  "isl.formatting.alignProperties": false,
+  "isl.execution.islCommand": "isl",
+  "isl.execution.javaHome": ""
+}
+```
+
+## Commands
+
+- **ISL: Validate Current File** - Run validation
+- **ISL: Run Transformation** - Execute with inline input
+- **ISL: Run Transformation with Input File** - Execute with JSON file
+- **ISL: Format Document** - Format code
+- **ISL: Open Documentation** - Open ISL docs
+
+## Requirements
+
+To execute ISL transformations:
+- Java Runtime Environment (JRE) 11+
+- ISL runtime from [ISL repository](https://github.com/intuit/isl)
+
+## 🤖 AI Assistant Support
+
+This extension includes AI configuration for Cursor, Windsurf, GitHub Copilot, and other AI editors. Your AI assistant automatically understands ISL syntax and can help write transformations.
+
+Ask your AI to:
+- Generate ISL transformations
+- Explain ISL syntax and modifiers
+- Convert data logic to ISL
+- Debug and optimize code
+
+## Resources
+
+- [ISL Documentation](https://intuit.github.io/isl/)
+- [ISL GitHub Repository](https://github.com/intuit/isl)
+- [Language Reference](https://intuit.github.io/isl/dsl/)
+- [Quick Start Guide](https://intuit.github.io/isl/quickstart/)
+- [ISL Extensions Guide](docs/EXTENSIONS.md) - Define custom functions and modifiers
+- [Example `.islextensions` file](.islextensions.example)
+
+## Release Notes
+
+### 1.1.0
+
+**Major improvements:**
+- Signature help and inlay hints
+- Code actions and quick fixes
+- Enhanced formatter (parameter spacing, nested control flow)
+- Semantic validation (undefined functions/modifiers, variable tracking)
+- 20+ new code snippets
+- Better control flow balance detection
+- Multi-line string preservation
+
+### 1.0.0
+
+Initial release with syntax highlighting, completion, validation, formatting, and execution support.
+
+See [CHANGELOG.md](CHANGELOG.md) for full details.
+
+## Contributing
+
+Found a bug or have a feature request? File an issue on [GitHub](https://github.com/intuit/isl).
+
+## License
+
+Apache License 2.0 - See [LICENSE](LICENSE) file.
+
+---
+
+**Enjoy using ISL!** 🚀
diff --git a/plugin/SETUP.md b/plugin/SETUP.md
new file mode 100644
index 0000000..286bf23
--- /dev/null
+++ b/plugin/SETUP.md
@@ -0,0 +1,181 @@
+# ISL Extension - Setup Guide
+
+Guide for installing and setting up the ISL Language Support extension.
+
+## For Users
+
+### Installation
+
+#### From Marketplace
+1. Open VS Code or Cursor
+2. Go to Extensions (Ctrl+Shift+X / Cmd+Shift+X)
+3. Search for "ISL Language Support"
+4. Click Install
+
+#### Manual Installation
+1. Download the `.vsix` file from releases
+2. Open VS Code/Cursor
+3. Extensions view → "..." menu → "Install from VSIX..."
+4. Select the downloaded file
+
+### Configuration
+
+After installation, open Settings (Ctrl+,) and search for "ISL":
+
+**Essential Settings:**
+- `isl.execution.islCommand`: Path to `isl.sh` or `isl.bat`
+- `isl.execution.javaHome`: Java installation path (if not in PATH)
+
+**Optional Settings:**
+- `isl.formatting.indentSize`: Spaces per indent level (default: 4)
+- `isl.formatting.useTabs`: Use tabs instead of spaces
+- `isl.validation.enabled`: Enable/disable validation
+
+### ISL Runtime Setup
+
+To execute ISL transformations, you need the ISL runtime:
+
+1. **Install Java 11+**
+   ```bash
+   java -version  # Verify installation
+   ```
+
+2. **Get ISL Runtime**
+   - Clone: https://github.com/intuit/isl
+   - Build: `./gradlew build`
+   - Or use pre-built `isl.sh` / `isl.bat`
+
+3. **Configure Extension**
+   - Set `isl.execution.islCommand` to path of ISL script
+   - Example: `/path/to/isl/isl.sh`
+
+### Verification
+
+1. Open any `.isl` file
+2. You should see:
+   - Syntax highlighting
+   - IntelliSense suggestions
+   - Validation indicators
+3. Test execution: Right-click → "ISL: Run Transformation"
+
+## For Developers
+
+### Prerequisites
+- Node.js 18+
+- TypeScript 5+
+- VS Code or Cursor
+
+### Development Setup
+
+```bash
+# Navigate to plugin directory
+cd plugin
+
+# Install dependencies
+npm install
+
+# Compile TypeScript
+npm run compile
+
+# Start watch mode (auto-recompile)
+npm run watch
+```
+
+### Running Extension
+
+1. Open `plugin` folder in VS Code
+2. Press `F5` to launch Extension Development Host
+3. Open a `.isl` file to test features
+
+### Project Structure
+
+```
+plugin/
+├── src/                      # TypeScript source
+│   ├── extension.ts          # Entry point
+│   ├── completion.ts         # Code completion
+│   ├── validator.ts          # Validation
+│   ├── formatter.ts          # Formatting
+│   └── ...                   # Other providers
+├── syntaxes/                 # Syntax highlighting
+├── snippets/                 # Code snippets
+└── package.json              # Extension manifest
+```
+
+### Building & Packaging
+
+```bash
+# Compile
+npm run compile
+
+# Package for distribution
+npm install -g @vscode/vsce
+vsce package
+```
+
+Creates `isl-language-support-X.X.X.vsix`
+
+### Testing
+
+**Feature Testing Checklist:**
+- [ ] Syntax highlighting works
+- [ ] Code completion (keywords, services, modifiers)
+- [ ] Validation shows errors correctly
+- [ ] Hover documentation appears
+- [ ] Go to definition navigates correctly
+- [ ] Formatting works
+- [ ] ISL execution runs
+- [ ] Snippets expand correctly
+- [ ] Code actions appear
+- [ ] Inlay hints show types
+
+### Debugging
+
+1. Set breakpoints in TypeScript files
+2. Press `F5` to start debugger
+3. Extension host opens with debugger attached
+4. Check Debug Console for logs
+
+## Troubleshooting
+
+### Extension doesn't activate
+- Check file has `.isl` extension
+- View → Command Palette → "Change Language Mode" → ISL
+
+### Syntax highlighting not working
+- Restart VS Code
+- Check language mode is set to ISL
+
+### ISL execution fails
+- Verify Java: `java -version`
+- Check `isl.execution.islCommand` setting points to valid path
+- View Output panel: View → Output → ISL
+
+### Validation errors
+- Check for actual syntax errors in code
+- Disable temporarily: `isl.validation.enabled: false`
+- Report false positives on GitHub
+
+### Formatting issues
+- Check `isl.formatting.indentSize` setting
+- Try manual format: Shift+Alt+F
+- Report issues with code sample
+
+## Resources
+
+- [Plugin Overview](PLUGIN-OVERVIEW.md) - Technical architecture
+- [Publishing Guide](PUBLISHING.md) - How to publish
+- [ISL Documentation](https://intuit.github.io/isl/)
+- [VSCode Extension API](https://code.visualstudio.com/api)
+
+## Contributing
+
+1. Fork repository
+2. Create feature branch
+3. Make changes
+4. Test thoroughly
+5. Submit pull request
+
+## License
+
+Apache License 2.0 - See [LICENSE](LICENSE) file
diff --git a/plugin/cspell.json b/plugin/cspell.json
new file mode 100644
index 0000000..da2f9ec
--- /dev/null
+++ b/plugin/cspell.json
@@ -0,0 +1,78 @@
+{
+  "version": "0.2",
+  "language": "en",
+  "words": [
+    "endfor",
+    "endwhile",
+    "endif",
+    "endswitch",
+    "foreach",
+    "upperCase",
+    "toLowerCase",
+    "titleCase",
+    "coalesce",
+    "inlayhints",
+    "codelens",
+    "tmLanguage",
+    "dateparse",
+    "dateadd",
+    "mathsum",
+    "mathavg",
+    "mathmax",
+    "mathmin",
+    "tostring",
+    "tonumber",
+    "todecimal",
+    "toboolean",
+    "backquote",
+    "backticks",
+    "squiggly",
+    "squeegly",
+    "scopename",
+    "isempty",
+    "isnotempty",
+    "padstart",
+    "padend",
+    "startswith",
+    "endswith",
+    "getproperty",
+    "setproperty",
+    "tofixed",
+    "toprecision",
+    "textmate",
+    "unescape",
+    "groupby",
+    "findindex",
+    "typeof",
+    "varname",
+    "funcname",
+    "modname",
+    "parens",
+    "impl",
+    "refactor",
+    "vals",
+    "addr",
+    "cond",
+    "decl",
+    "args",
+    "nums",
+    "objs",
+    "expr",
+    "ident",
+    "substringUpto",
+    "tobinary",
+    "replacefirst",
+    "parsemultiline"
+  ],
+  "ignoreWords": [],
+  "import": [],
+  "flagWords": [],
+  "ignorePaths": [
+    "node_modules/**",
+    "out/**",
+    "dist/**",
+    "*.min.js",
+    "package-lock.json"
+  ]
+}
+
diff --git a/plugin/docs/EXTENSIONS.md b/plugin/docs/EXTENSIONS.md
new file mode 100644
index 0000000..cdcc224
--- /dev/null
+++ b/plugin/docs/EXTENSIONS.md
@@ -0,0 +1,306 @@
+# ISL Extensions
+
+The ISL Language Support extension allows you to define custom functions and modifiers specific to your project using a `.islextensions` file. This enables the plugin to provide IntelliSense, hover documentation, and validation for your project-specific ISL extensions.
+
+## How It Works
+
+Similar to how `.cspell.json` defines custom dictionary words or `.cursorrules` defines AI assistant rules, you can create a `.islextensions` file in your project root to define custom ISL functions and modifiers.
+
+When you open an ISL file, the extension automatically:
+1. Looks for a `.islextensions` file in the workspace root
+2. Loads and parses the custom definitions
+3. Integrates them into autocomplete, hover documentation, and validation
+4. Watches for changes and automatically reloads when the file is updated
+
+## File Format
+
+The `.islextensions` file uses JSON format with the following structure:
+
+```json
+{
+  "functions": [
+    {
+      "name": "functionName",
+      "description": "What the function does",
+      "parameters": [
+        {
+          "name": "param1",
+          "type": "String",
+          "description": "Parameter description",
+          "optional": false,
+          "defaultValue": "default"
+        }
+      ],
+      "returns": {
+        "type": "Object",
+        "description": "What the function returns"
+      },
+      "examples": [
+        "$result: @.This.functionName($param1);"
+      ]
+    }
+  ],
+  "modifiers": [
+    {
+      "name": "modifierName",
+      "description": "What the modifier does",
+      "parameters": [
+        {
+          "name": "param1",
+          "type": "String",
+          "optional": true,
+          "defaultValue": "default",
+          "description": "Parameter description"
+        }
+      ],
+      "returns": {
+        "type": "String",
+        "description": "What the modifier returns"
+      },
+      "examples": [
+        "$result: $input | modifierName;",
+        "$result: $input | modifierName(\"value\");"
+      ]
+    }
+  ]
+}
+```
+
+## Field Reference
+
+### Function Definition
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `name` | string | Yes | The function name (used in `@.This.functionName()`) |
+| `description` | string | No | Description shown in hover and autocomplete |
+| `parameters` | array | No | Array of parameter definitions |
+| `returns` | object | No | Return type and description |
+| `examples` | array | No | Array of usage examples |
+
+### Modifier Definition
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `name` | string | Yes | The modifier name (used with `\| modifierName`) |
+| `description` | string | No | Description shown in hover and autocomplete |
+| `parameters` | array | No | Array of parameter definitions |
+| `returns` | object | No | Return type and description |
+| `examples` | array | No | Array of usage examples |
+
+### Parameter Definition
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `name` | string | Yes | Parameter name |
+| `type` | string | No | Parameter type (String, Number, Boolean, Array, Object, etc.) |
+| `description` | string | No | Parameter description |
+| `optional` | boolean | No | Whether the parameter is optional (default: false) |
+| `defaultValue` | string | No | Default value if not provided |
+
+### Returns Definition
+
+| Field | Type | Required | Description |
+|-------|------|----------|-------------|
+| `type` | string | No | Return type |
+| `description` | string | No | Description of what is returned |
+
+## Example
+
+Here's a complete example for a project with custom email and database functions:
+
+```json
+{
+  "functions": [
+    {
+      "name": "sendEmail",
+      "description": "Sends an email using the custom email service",
+      "parameters": [
+        {
+          "name": "to",
+          "type": "String",
+          "description": "Email recipient address"
+        },
+        {
+          "name": "subject",
+          "type": "String",
+          "description": "Email subject line"
+        },
+        {
+          "name": "body",
+          "type": "String",
+          "description": "Email body content"
+        }
+      ],
+      "returns": {
+        "type": "Object",
+        "description": "Result with success status"
+      },
+      "examples": [
+        "$result: @.This.sendEmail($user.email, \"Welcome\", `Hello ${$user.name}!`);"
+      ]
+    }
+  ],
+  "modifiers": [
+    {
+      "name": "formatPhone",
+      "description": "Formats a phone number to standard format",
+      "parameters": [
+        {
+          "name": "format",
+          "type": "String",
+          "optional": true,
+          "defaultValue": "US",
+          "description": "Format style (US, INTERNATIONAL, E164)"
+        }
+      ],
+      "returns": {
+        "type": "String",
+        "description": "Formatted phone number"
+      },
+      "examples": [
+        "$phone: $user.phone | formatPhone;",
+        "$phone: $user.phone | formatPhone(\"INTERNATIONAL\");"
+      ]
+    }
+  ]
+}
+```
+
+## Features
+
+Once you define your extensions, you get:
+
+### 1. IntelliSense / Autocomplete
+- Type `@.This.` to see your custom functions
+- Type `|` to see your custom modifiers
+- Full parameter hints and descriptions
+
+### 2. Hover Documentation
+- Hover over custom function or modifier names to see:
+  - Full signature with parameter types
+  - Description
+  - Parameter details
+  - Return type
+  - Usage examples
+  - Note indicating it's from `.islextensions`
+
+### 3. Validation
+- No warnings for using your custom functions/modifiers
+- The validator recognizes them as valid
+- Works alongside built-in ISL functions/modifiers
+
+### 4. Auto-reload
+- Changes to `.islextensions` are automatically detected
+- Extension reloads definitions without restart
+- All open ISL files are revalidated
+
+## Best Practices
+
+1. **Keep it organized**: Group related functions and modifiers together
+2. **Document thoroughly**: Add descriptions and examples - they appear in IDE tooltips
+3. **Use types**: Specify parameter and return types for better IntelliSense
+4. **Version control**: Commit `.islextensions` to your repository so the team shares the definitions
+5. **Validate JSON**: Use a JSON validator to ensure your file is valid before saving
+
+## Troubleshooting
+
+### Extensions not showing up
+- Check that `.islextensions` is in the workspace root
+- Verify JSON syntax is valid (use a JSON validator)
+- Reload VS Code window if needed
+
+### Validation errors
+- Ensure `name` field is present for all functions/modifiers
+- Check that parameter names are valid identifiers
+- Verify no duplicate names
+
+### Changes not applying
+- The extension watches for file changes automatically
+- If changes don't apply, try reloading the window
+- Check the Output panel (View > Output, select "ISL Language Support") for error messages
+
+## Schema Support
+
+For better editing experience, you can add JSON schema validation by adding this at the top of your `.islextensions` file:
+
+```json
+{
+  "$schema": "https://json-schema.org/draft-07/schema#",
+  "functions": [
+    ...
+  ]
+}
+```
+
+(Note: A full schema definition will be provided in future versions)
+
+## Examples by Use Case
+
+### Custom Database Functions
+```json
+{
+  "functions": [
+    {
+      "name": "queryDB",
+      "description": "Executes a database query",
+      "parameters": [
+        {"name": "sql", "type": "String"},
+        {"name": "params", "type": "Array", "optional": true}
+      ],
+      "returns": {"type": "Array"},
+      "examples": ["$users: @.This.queryDB(\"SELECT * FROM users\");"]
+    }
+  ]
+}
+```
+
+### Custom Validation Modifiers
+```json
+{
+  "modifiers": [
+    {
+      "name": "validateEmail",
+      "description": "Validates email format",
+      "parameters": [],
+      "returns": {"type": "Boolean"},
+      "examples": ["if ($email | validateEmail) ... endif"]
+    }
+  ]
+}
+```
+
+### Custom Formatting Modifiers
+```json
+{
+  "modifiers": [
+    {
+      "name": "toCurrency",
+      "description": "Formats number as currency",
+      "parameters": [
+        {
+          "name": "currency",
+          "type": "String",
+          "optional": true,
+          "defaultValue": "USD"
+        }
+      ],
+      "returns": {"type": "String"},
+      "examples": [
+        "$price: $amount | toCurrency;",
+        "$price: $amount | toCurrency(\"EUR\");"
+      ]
+    }
+  ]
+}
+```
+
+## Future Enhancements
+
+Planned improvements:
+- JSON Schema for `.islextensions` validation
+- Support for importing external extension definitions
+- Multiple extension files support
+- Extension marketplace/sharing
+- Auto-generation from Java/Kotlin extension implementations
+
diff --git a/plugin/docs/ISL-LANGUAGE-GUIDE.md b/plugin/docs/ISL-LANGUAGE-GUIDE.md
new file mode 100644
index 0000000..983f2c6
--- /dev/null
+++ b/plugin/docs/ISL-LANGUAGE-GUIDE.md
@@ -0,0 +1,470 @@
+# ISL Language Quick Reference
+
+This guide helps AI assistants and developers understand ISL (Intuitive Scripting Language) syntax and best practices.
+
+## Table of Contents
+1. [Quick Start](#quick-start)
+2. [Core Syntax](#core-syntax)
+3. [Built-in Modifiers](#built-in-modifiers)
+4. [Control Flow](#control-flow)
+5. [Common Patterns](#common-patterns)
+6. [Important Rules](#important-rules)
+
+## Quick Start
+
+Every ISL transformation starts with a `run` function:
+
+```isl
+fun run($input) {
+    // Transform $input here
+    userId: $input.id | to.string;
+    userName: `${$input.firstName} ${$input.lastName}`;
+    createdDate: $input.timestamp | date.parse("yyyy-MM-dd");
+}
+```
+
+## Core Syntax
+
+### Variables
+Variables start with `$` and can hold any JSON value:
+```isl
+$name: "John";
+$age: 30;
+$active: true;
+$address: { street: "123 Main St", city: "Boston" };
+$items: [1, 2, 3];
+```
+
+Access nested properties with dot notation:
+```isl
+$street: $user.address.street;
+$firstItem: $array[0];
+```
+
+### Functions
+Declare reusable logic with `fun`:
+```isl
+fun calculateTax($amount, $rate) {
+    return {{ $amount * $rate }};
+}
+
+// Call with @.This prefix
+$tax: @.This.calculateTax($subtotal, 0.08);
+```
+
+Functions **must always return a value**. Use `return {};` for empty returns.
+
+### Modifiers
+Transform data by piping values through modifiers:
+```isl
+$cleanName: $input.name | trim | capitalize;
+$ids: $items | map($.id) | unique;
+$adults: $users | filter($.age >= 18);
+```
+
+Create custom modifiers:
+```isl
+modifier formatCurrency($amount) {
+    return `\$${$amount | to.decimal | precision(2)}`;
+}
+
+$price: 99.9975 | formatCurrency;  // "$100.00"
+```
+
+### Math Expressions
+All math operations must be wrapped in `{{ }}`:
+```isl
+$total: {{ $price * $quantity }};
+$average: {{ ($sum / $count) }};
+$discount: {{ $amount * 0.1 }};
+```
+
+### String Interpolation
+Use backticks for string interpolation:
+```isl
+// Simple variable (no dots)
+$greeting: `Hello $firstName`;
+
+// Nested paths (has dots) - needs ${}
+$message: `User ${$user.name} logged in`;
+
+// Math expressions
+$summary: `Total: \${{ $price * $qty }}`;  // Escape $ for literal
+```
+
+### Objects
+Create objects with JSON-like syntax:
+```isl
+$user: {
+    id: $input.userId,
+    name: `${$input.first} ${$input.last}`,
+    active: true
+};
+```
+
+Use spread operator to merge objects:
+```isl
+$extended: {
+    ...$baseUser,
+    role: "admin",
+    permissions: ["read", "write"]
+};
+```
+
+Dynamic property names:
+```isl
+$key: "dynamicProp";
+$obj: { `$key`: "value" };  // { "dynamicProp": "value" }
+```
+
+## Built-in Modifiers
+
+### String Modifiers
+```isl
+$text | trim                      // Remove whitespace
+$text | trim("*")                 // Remove specific characters
+$text | upperCase                 // UPPERCASE
+$text | lowerCase                 // lowercase
+$text | capitalize                // Capitalize first letter
+$text | titleCase                 // Title Case Each Word
+$text | replace("old", "new")     // Replace text
+$text | split(",")                // Split into array
+$text | subString(0, 10)          // Extract substring
+$text | length                    // Get length
+$text | padStart(10, "0")         // Pad left
+$text | truncate(50, "...")       // Truncate with suffix
+$text | default("fallback")       // Default if empty/null
+```
+
+### Array Modifiers
+```isl
+$array | map(expression)          // Transform each element
+$array | filter(condition)        // Select matching elements
+$array | reduce(expression)       // Aggregate to single value
+$array | sort                     // Sort ascending
+$array | reverse                  // Reverse order
+$array | unique                   // Remove duplicates
+$array | first                    // Get first element
+$array | last                     // Get last element
+$array | at(2)                    // Get element at index
+$array | length                   // Get array length
+$array | isEmpty                  // Check if empty
+$array | push(item)               // Add item to end
+$array | pop                      // Remove last item
+$array | join(", ")               // Join to string
+```
+
+### Conversion Modifiers
+```isl
+$value | to.string               // Convert to string
+$value | to.number               // Convert to integer
+$value | to.decimal              // Convert to decimal
+$value | to.boolean              // Convert to boolean
+$value | to.array                // Convert to array
+$value | to.json                 // Serialize to JSON
+$value | to.xml("root")          // Convert to XML
+```
+
+### Math Modifiers
+```isl
+$num | absolute                  // Absolute value
+$num | negate                    // Negative value
+$num | round                     // Round to nearest
+$num | precision(2)              // Format decimal places
+$num | round.up(2)               // Round up
+$num | round.down(2)             // Round down
+```
+
+### Date/Time Modifiers
+```isl
+@.Date.Now()                                          // Current date/time
+$str | date.parse("yyyy-MM-dd")                       // Parse date string
+$date | date.add(1, "DAYS")                           // Add time unit
+$date | date.add(-2, "HOURS")                         // Subtract
+$date | date.part("YEAR")                             // Extract part
+$date | to.string("MM/dd/yyyy HH:mm:ss")              // Format date
+$date | to.number                                     // Unix epoch (seconds)
+$date | to.epochmillis                                // Epoch milliseconds
+$epochSecs | date.fromEpochSeconds                    // Parse epoch
+```
+
+### Object Modifiers
+```isl
+$obj | keys                      // Get property names
+$obj | kv                        // Key-value pairs array
+$obj | select("path.to.prop")    // Extract nested value
+$obj | delete("propName")        // Remove property
+$obj | getProperty("Name")       // Case-insensitive get
+```
+
+### Data Format Modifiers
+```isl
+$str | json.parse                // Parse JSON string
+$str | xml.parse                 // Parse XML string
+$str | yaml.parse                // Parse YAML string
+$str | csv.parsemultiline        // Parse CSV data
+$bytes | encode.base64           // Base64 encode
+$str | decode.base64             // Base64 decode
+$str | to.hex                    // Convert to hex
+$hex | from.hex                  // Convert from hex
+```
+
+### Cryptographic Modifiers
+```isl
+$data | crypto.sha256 | to.hex   // SHA-256 hash
+$data | crypto.sha512 | to.hex   // SHA-512 hash
+$data | crypto.md5 | to.hex      // MD5 hash
+$msg | crypto.hmacsha256($key) | encode.base64  // HMAC-SHA256
+```
+
+## Control Flow
+
+### If/Else
+```isl
+// Expression form (simple condition only)
+$status: if ($paid) "success" else "pending" endif;
+$discount: if ($amount > 100) 0.1 endif;  // else is optional
+
+// Statement form (supports complex logic)
+if ($user.role == "admin" and $user.active)
+    $permissions: ["read", "write", "delete"];
+else
+    $permissions: ["read"];
+endif
+```
+
+### Switch/Case
+```isl
+$message: switch ($statusCode)
+    200 -> "OK";
+    404 -> "Not Found";
+    /^5\d\d/ -> "Server Error";        // Regex match
+    < 300 -> "Success";                // Comparison
+    contains "Error" -> "Failed";      // String contains
+    in [401, 403] -> "Unauthorized";   // Array membership
+    else -> "Unknown";
+endswitch
+```
+
+### Foreach Loop
+```isl
+// Basic foreach
+$doubled: foreach $n in $numbers
+    {{ $n * 2 }}
+endfor
+
+// Transform objects
+$users: foreach $user in $input.users
+    {
+        id: $user.id,
+        name: `${$user.first} ${$user.last}`,
+        index: $userIndex  // Automatic index variable
+    }
+endfor
+
+// With filter
+foreach $item in $items | filter($.price > 100)
+    // Process expensive items only
+endfor
+```
+
+### While Loop
+```isl
+$i: 0;
+$sum: 0;
+while ($i < 10)
+    $sum: {{ $sum + $i }};
+    $i: {{ $i + 1 }};
+endwhile
+```
+
+### Coalesce Operator
+Return first non-null, non-empty value:
+```isl
+$name: $user.preferredName ?? $user.firstName ?? "Guest";
+$email: $contact.email ?? $contact.alternateEmail ?? "";
+```
+
+## Common Patterns
+
+### Transform Array of Objects
+```isl
+items: $input.lineItems | map({
+    productId: $.product.id | to.string,
+    name: $.product.name | trim | capitalize,
+    quantity: $.qty | to.number,
+    price: $.unitPrice | to.decimal | precision(2),
+    total: {{ $.qty * $.unitPrice }} | precision(2)
+})
+```
+
+### Filter and Aggregate
+```isl
+// Get expensive items total
+$expensiveTotal: $items 
+    | filter($.price > 100)
+    | map($.price)
+    | reduce({{ $acc + $it }});
+
+// Count active users
+$activeCount: $users | filter($.active) | length;
+```
+
+### Conditional Object Properties
+```isl
+{
+    id: $input.id,
+    name: $input.name,
+    // Include email only if present
+    ...if ($input.email) { email: $input.email } else {} endif,
+    // Include address with default
+    address: $input.address ?? "N/A"
+}
+```
+
+### Complex Nested Transformation
+```isl
+fun run($input) {
+    orderId: $input.order.id | to.string;
+    customer: @.This.transformCustomer($input.customer);
+    items: $input.order.items | map(@.This.transformItem($));
+    summary: @.This.calculateSummary($input.order.items);
+}
+
+fun transformCustomer($cust) {
+    return {
+        id: $cust.id | to.string,
+        fullName: `${$cust.firstName} ${$cust.lastName}`,
+        email: $cust.email | lowerCase | trim
+    };
+}
+
+fun transformItem($item) {
+    return {
+        id: $.id,
+        name: $.title | capitalize,
+        price: $.price | to.decimal | precision(2)
+    };
+}
+
+fun calculateSummary($items) {
+    $subtotal: $items 
+        | map({{ $.price * $.quantity }})
+        | reduce({{ $acc + $it }});
+    
+    return {
+        subtotal: $subtotal | precision(2),
+        tax: {{ $subtotal * 0.08 }} | precision(2),
+        total: {{ $subtotal * 1.08 }} | precision(2)
+    };
+}
+```
+
+## Important Rules
+
+### ✅ Do This
+
+1. **Always wrap math in `{{ }}`**
+   ```isl
+   $total: {{ $price * $quantity }};
+   ```
+
+2. **Use modifiers without parentheses in conditions**
+   ```isl
+   if ($text | length > 5) ... endif
+   ```
+
+3. **Return a value from functions**
+   ```isl
+   return $result;
+   return {};  // For empty return
+   ```
+
+4. **Use `$` in foreach array without parentheses**
+   ```isl
+   foreach $item in $array | filter($.active)
+   ```
+
+5. **Proper spacing for readability**
+   ```isl
+   $result: $items | map( $.id ) | filter( $ > 100 );
+   ```
+
+### ❌ Don't Do This
+
+1. **Don't use naked math expressions**
+   ```isl
+   ❌ $total: $price * $quantity;
+   ✅ $total: {{ $price * $quantity }};
+   ```
+
+2. **Don't wrap modifiers in conditions**
+   ```isl
+   ❌ if (($text | length) > 5) ... endif
+   ✅ if ($text | length > 5) ... endif
+   ```
+
+3. **Don't return without value**
+   ```isl
+   ❌ return;
+   ✅ return {};
+   ```
+
+4. **Don't access properties after modifiers**
+   ```isl
+   ❌ $id: ($items | last).id;
+   ✅ $last: $items | last; $id: $last.id;
+   ```
+
+5. **Don't use JavaScript/Python syntax**
+   ```isl
+   ❌ const user = input.name;
+   ✅ $user: $input.name;
+   
+   ❌ items.map(x => x.id)
+   ✅ $items | map($.id)
+   ```
+
+## File Structure
+
+Standard ISL file structure:
+
+```isl
+// 1. Imports (optional)
+import Utils from 'utils.isl';
+
+// 2. Main entry point (REQUIRED)
+fun run($input) {
+    // Primary transformation logic
+}
+
+// 3. Helper functions
+fun helperFunction($param) {
+    return $result;
+}
+
+// 4. Custom modifiers
+modifier customModifier($value, $param) {
+    return $transformed;
+}
+```
+
+## Learn More
+
+- **Critical that you read this AI-Specific Guide**: https://intuit.github.io/isl/ai/
+- **Full Documentation**: https://intuit.github.io/isl/
+- **Language Reference**: https://intuit.github.io/isl/language/
+- **Complete Modifiers List**: https://intuit.github.io/isl/language/modifiers/
+- **CLI Documentation**: https://intuit.github.io/isl/cli/
+- **Examples**: https://intuit.github.io/isl/examples/
+
+## Getting Help
+
+When working with ISL:
+1. Start with the `fun run($input)` pattern
+2. Break complex logic into helper functions
+3. Use modifiers for data transformations
+4. Check the documentation for available modifiers
+5. Follow the syntax rules strictly
+6. Test incrementally using the CLI or Run button
+
diff --git a/plugin/docs/MODIFIERS.md b/plugin/docs/MODIFIERS.md
new file mode 100644
index 0000000..cb8b8a5
--- /dev/null
+++ b/plugin/docs/MODIFIERS.md
@@ -0,0 +1,256 @@
+# ISL Modifiers Reference
+
+This document lists all built-in modifiers available in ISL.
+
+## String Modifiers
+
+### Trimming
+- `trim` - Trim whitespace from both sides
+- `trimStart` - Trim whitespace from start
+- `trimEnd` - Trim whitespace from end
+
+### Case Conversion
+- `upperCase` - Convert to uppercase
+- `lowerCase` - Convert to lowercase
+- `capitalize` - Capitalize first letter
+- `titleCase` - Convert to title case (capitalize each word)
+- `camelCase` - Convert to camelCase
+- `snakeCase` - Convert to snake_case
+
+### Substring Operations
+- `left(n)` - Get first n characters
+- `right(n)` - Get last n characters
+- `cap(n)` - Cap string at length (alias for left)
+- `substring(start, end)` - Get substring
+- `substringUpto(delimiter)` - Get substring up to delimiter
+- `substringAfter(delimiter)` - Get substring after delimiter
+
+### String Manipulation
+- `replace(find, replace)` - Replace all occurrences
+- `remove(text)` - Remove substring
+- `concat(other, delimiter)` - Concatenate with delimiter
+- `append(values...)` - Append multiple strings
+- `split(delimiter)` - Split into array
+- `truncate(length, suffix)` - Truncate with suffix (default "...")
+- `padStart(length, char)` - Pad at start
+- `padEnd(length, char)` - Pad at end
+- `reverse` - Reverse string
+
+### HTML
+- `html.escape` - Escape HTML entities
+- `html.unescape` - Unescape HTML entities
+
+### CSV
+- `csv.parsemultiline` - Parse CSV string
+- `csv.findrow` - Find specific row in CSV
+
+### Other
+- `sanitizeTid` - Sanitize/validate UUID/TID
+
+## Array Modifiers
+
+### High-Order Functions
+- `filter(condition)` - Filter array by condition (use $fit or $ for current item)
+- `map(expression)` - Transform each element (use $ for current item)
+- `reduce(expression, initial)` - Reduce to single value (use $acc and $it)
+
+### Element Access
+- `first` - Get first element
+- `last` - Get last element
+- `at(index)` - Get element at index (supports negative indices)
+- `take(n)` - Take first n elements
+- `drop(n)` - Drop first n elements
+
+### Search
+- `indexOf(element)` - Find index of element
+- `lastIndexOf(element)` - Find last index of element
+
+### Manipulation
+- `push(item)` - Add item to end
+- `pop` - Remove last item
+- `pushItems(array)` - Append entire array
+- `slice(start, end)` - Extract portion
+- `chunk(size)` - Split into chunks of size
+
+### Transformation
+- `sort` - Sort array
+- `reverse` - Reverse array
+- `unique` - Get unique values
+
+### Checks
+- `isEmpty` - Check if empty
+- `isNotEmpty` - Check if not empty
+- `length` - Get length
+
+## Object Modifiers
+
+### Property Access
+- `keys` - Get object keys as array
+- `kv` - Get key-value pairs as array of {key, value}
+- `getProperty(name)` - Get property (case-insensitive)
+- `setProperty(name, value)` - Set property
+- `has(key)` - Check if object has key
+- `delete(property)` - Delete property
+
+### Object Operations
+- `sort` - Sort object by keys
+- `select(path)` - Select nested property by JSON path
+- `merge(other)` - Merge with another object
+- `pick(keys...)` - Pick specific properties
+- `omit(keys...)` - Omit specific properties
+- `rename(oldName, newName)` - Rename property
+- `default(value)` - Return default if null/empty
+
+## Math Modifiers
+
+### Array Math (use with arrays)
+- `Math.sum(initial)` - Sum all values
+- `Math.average` - Average of values
+- `Math.mean` - Mean of values
+- `Math.min` - Minimum value
+- `Math.max` - Maximum value
+
+### Numeric Operations
+- `Math.mod(divisor)` - Modulo operation
+- `Math.sqrt` - Square root
+- `Math.round` - Round to nearest integer
+- `Math.floor` - Round down
+- `Math.ceil` - Round up
+- `Math.abs` - Absolute value
+
+### Number Modifiers
+- `negate` - Negate number
+- `absolute` - Absolute value
+- `precision(digits)` - Set decimal precision
+- `round.up` - Round up
+- `round.down` - Round down
+- `round.half` - Round half
+
+### Random Numbers
+- `Math.RandInt(min, max)` - Random integer
+- `Math.RandFloat()` - Random float
+- `Math.RandDouble()` - Random double
+
+## Type Conversion Modifiers
+
+### Basic Types
+- `to.string` - Convert to string
+- `to.number` - Convert to number
+- `to.decimal` - Convert to decimal
+- `to.boolean` - Convert to boolean
+- `to.array` - Convert to array
+- `to.object` - Convert to object
+
+### Format Conversions
+- `to.json` - Convert to JSON string
+- `to.yaml` - Convert to YAML string
+- `to.csv` - Convert to CSV string
+- `to.xml(rootName)` - Convert to XML
+- `to.hex` - Convert to hex string
+- `to.bytes` - Convert to byte array
+- `to.epochmillis` - Convert date to epoch milliseconds
+
+### Hex Conversion
+- `hex.tobinary` - Convert hex string to binary
+
+### Join Operations
+- `join.string(delimiter)` - Join array to string
+- `join.path(delimiter)` - Join with URL path encoding
+- `join.query(delimiter)` - Join with URL query encoding
+
+## Parsing Modifiers
+
+### Data Formats
+- `json.parse` - Parse JSON string
+- `yaml.parse` - Parse YAML string
+- `xml.parse` - Parse XML string
+
+### Email
+- `email.parse` - Parse email addresses
+
+## Encoding Modifiers
+
+### Base64
+- `encode.base64` - Encode to Base64
+- `encode.base64url` - Encode to Base64 URL-safe
+- `decode.base64` - Decode from Base64
+- `decode.base64url` - Decode from Base64 URL-safe
+
+### URL Encoding
+- `encode.path` - URL path encoding
+- `encode.query` - URL query encoding
+- `decode.query` - URL query decoding
+
+## Compression Modifiers
+
+- `gzip` - GZip compress
+- `gunzip` - GZip decompress to string
+- `gunzipToByte` - GZip decompress to byte array
+
+## Regex Modifiers
+
+- `regex.find(pattern)` - Find all matches
+- `regex.matches(pattern)` - Test if matches
+- `regex.replace(pattern, replacement)` - Replace all matches
+- `regex.replacefirst(pattern, replacement)` - Replace first match
+
+Options can be passed as third parameter: `{ignoreCase: true, multiLine: true, comments: true}`
+
+## Type Checking
+
+- `typeof` - Get type of value (returns: string, number, boolean, array, object, null, etc.)
+
+## Legacy/Common Modifiers
+
+- `contains(value)` - Check if string contains substring
+- `startsWith(prefix)` - Check if starts with
+- `endsWith(suffix)` - Check if ends with
+
+## Date Modifiers
+
+- `date.parse(format)` - Parse date string
+- `date.add(value, unit)` - Add to date (units: YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS)
+- `date.part(part)` - Get date part (YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DAYOFYEAR, DAYOFWEEK)
+- `date.fromEpochSeconds` - Create date from epoch seconds
+- `date.fromEpochMillis` - Create date from epoch milliseconds
+
+## Static Functions (use with @.)
+
+### Math Functions
+- `@.Math.min(values...)` - Minimum of values
+- `@.Math.max(values...)` - Maximum of values
+- `@.Math.mean(values...)` - Mean of values
+- `@.Math.mod(value, divisor)` - Modulo operation
+- `@.Math.sqrt(value)` - Square root
+- `@.Math.RandInt(min, max)` - Random integer
+- `@.Math.RandFloat()` - Random float
+- `@.Math.RandDouble()` - Random double
+
+### Array Functions
+- `@.Array.range(start, count, increment)` - Create numeric range array
+
+### Date Functions
+- `@.Date.now()` - Current date/time
+- `@.Date.parse(string, format)` - Parse date
+- `@.Date.fromEpochSeconds(seconds)` - From epoch seconds
+- `@.Date.fromEpochMillis(millis)` - From epoch milliseconds
+
+## Special Variables in Modifiers
+
+### filter
+- `$fit` or `$` - Current item being filtered
+
+### map
+- `$` - Current item being mapped
+
+### reduce
+- `$acc` - Accumulator
+- `$it` - Current item
+
+### foreach
+- `$item` - Loop variable
+- `$itemIndex` - Zero-based index
+
+### retry
+- `$` - Current value being tested
+
diff --git a/plugin/images/README.md b/plugin/images/README.md
new file mode 100644
index 0000000..a4cc43f
--- /dev/null
+++ b/plugin/images/README.md
@@ -0,0 +1,25 @@
+# Plugin Images
+
+## icon.png
+
+The official ISL logo has been copied from `../../docs/img/isl_small.png`.
+
+**For VS Code Marketplace**: The icon should be exactly **128x128 pixels**. 
+
+To verify and resize if needed, see `../ICON-SETUP.md` which includes:
+- Scripts for automatic resizing (PowerShell & Bash)
+- Manual resize instructions
+- Online tool recommendations
+- Image editor steps
+
+## file-icon.svg
+
+SVG icon used for `.isl` file type in the VS Code file explorer.
+
+This is a simplified vector version of the ISL branding with:
+- ISL text
+- Decorative brackets
+- Blue gradient background
+
+The SVG format ensures it scales well at all sizes in the VS Code UI.
+
diff --git a/plugin/images/file-icon.svg b/plugin/images/file-icon.svg
new file mode 100644
index 0000000..c5ff0ef
--- /dev/null
+++ b/plugin/images/file-icon.svg
@@ -0,0 +1,22 @@
+
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+  
+
diff --git a/plugin/images/icon.png b/plugin/images/icon.png
new file mode 100644
index 0000000..f58217b
Binary files /dev/null and b/plugin/images/icon.png differ
diff --git a/plugin/isl-language-support-1.0.0.vsix b/plugin/isl-language-support-1.0.0.vsix
new file mode 100644
index 0000000..6fba9c7
Binary files /dev/null and b/plugin/isl-language-support-1.0.0.vsix differ
diff --git a/plugin/isl-language-support-1.1.0.vsix b/plugin/isl-language-support-1.1.0.vsix
new file mode 100644
index 0000000..3d4b056
Binary files /dev/null and b/plugin/isl-language-support-1.1.0.vsix differ
diff --git a/plugin/language-configuration.json b/plugin/language-configuration.json
new file mode 100644
index 0000000..1d26a73
--- /dev/null
+++ b/plugin/language-configuration.json
@@ -0,0 +1,39 @@
+{
+  "comments": {
+    "lineComment": "//",
+    "blockComment": ["/*", "*/"]
+  },
+  "brackets": [
+    ["{", "}"],
+    ["[", "]"],
+    ["(", ")"]
+  ],
+  "autoClosingPairs": [
+    { "open": "{", "close": "}" },
+    { "open": "[", "close": "]" },
+    { "open": "(", "close": ")" },
+    { "open": "\"", "close": "\"", "notIn": ["string"] },
+    { "open": "'", "close": "'", "notIn": ["string"] },
+    { "open": "`", "close": "`", "notIn": ["string"] }
+  ],
+  "surroundingPairs": [
+    ["{", "}"],
+    ["[", "]"],
+    ["(", ")"],
+    ["\"", "\""],
+    ["'", "'"],
+    ["`", "`"]
+  ],
+  "folding": {
+    "markers": {
+      "start": "^\\s*//\\s*#?region\\b",
+      "end": "^\\s*//\\s*#?endregion\\b"
+    }
+  },
+  "wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)",
+  "indentationRules": {
+    "increaseIndentPattern": "^((?!\\/\\/).)*(\\{[^}\"'`]*|\\([^)\"'`]*|\\[[^\\]\"'`]*)$",
+    "decreaseIndentPattern": "^((?!.*?\\/\\*).*\\*/)?\\s*[\\}\\]].*$"
+  }
+}
+
diff --git a/plugin/lib/README.md b/plugin/lib/README.md
new file mode 100644
index 0000000..69b5d46
--- /dev/null
+++ b/plugin/lib/README.md
@@ -0,0 +1,56 @@
+# ISL Runtime Library
+
+This directory contains the embedded ISL command-line runtime that allows the extension to execute ISL transformations without requiring users to build the project.
+
+## Contents
+
+- `isl-cmd-all.jar` - ISL command-line tool with all dependencies (shadow JAR, ~35MB)
+
+## How It Works
+
+When you click the "▶ Run" button above an ISL function, the extension:
+
+1. Prompts for input JSON
+2. Saves the input to a temporary file
+3. Executes: `java -jar isl-cmd-all.jar .isl -i input.json -f `
+4. Shows the output in the terminal
+
+## Requirements
+
+- **Java 11 or later** must be installed and available in PATH
+- Or configure `isl.execution.javaHome` in VS Code settings
+
+## Building
+
+This JAR is built from the ISL project using:
+
+```bash
+./gradlew :isl-cmd:build
+```
+
+The shadow JAR (`isl-2.4.20-SNAPSHOT.jar`) from `isl-cmd/build/libs/` is copied here as `isl-cmd-all.jar`.
+
+## Version
+
+Built from ISL version: **2.4.20-SNAPSHOT**
+
+## Distribution
+
+This JAR is included in the extension package (`.vsix`) so end users don't need to:
+- Clone the ISL repository
+- Build the project with Gradle
+- Configure complex paths
+
+Everything works out of the box with just Java installed!
+
+## Size Note
+
+The JAR is approximately 35MB because it includes all dependencies:
+- ISL transform engine
+- ANTLR parser
+- Kotlin runtime
+- Jackson JSON library
+- All other required libraries
+
+This makes the extension self-contained and easy to distribute.
+
diff --git a/plugin/package-lock.json b/plugin/package-lock.json
new file mode 100644
index 0000000..3f99333
--- /dev/null
+++ b/plugin/package-lock.json
@@ -0,0 +1,6483 @@
+{
+  "name": "isl-language-support",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "isl-language-support",
+      "version": "1.0.0",
+      "dependencies": {
+        "vscode-languageclient": "^8.1.0"
+      },
+      "devDependencies": {
+        "@types/node": "^18.0.0",
+        "@types/vscode": "^1.75.0",
+        "@typescript-eslint/eslint-plugin": "^6.0.0",
+        "@typescript-eslint/parser": "^6.0.0",
+        "@vscode/vsce": "^2.32.0",
+        "eslint": "^8.40.0",
+        "ovsx": "^0.10.7",
+        "typescript": "^5.0.0"
+      },
+      "engines": {
+        "vscode": "^1.75.0"
+      }
+    },
+    "node_modules/@azu/format-text": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz",
+      "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@azu/style-format": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz",
+      "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==",
+      "dev": true,
+      "license": "WTFPL",
+      "dependencies": {
+        "@azu/format-text": "^1.0.1"
+      }
+    },
+    "node_modules/@azure/abort-controller": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
+      "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=18.0.0"
+      }
+    },
+    "node_modules/@azure/core-auth": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz",
+      "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.1.2",
+        "@azure/core-util": "^1.13.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@azure/core-client": {
+      "version": "1.10.1",
+      "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz",
+      "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/abort-controller": "^2.1.2",
+        "@azure/core-auth": "^1.10.0",
+        "@azure/core-rest-pipeline": "^1.22.0",
+        "@azure/core-tracing": "^1.3.0",
+        "@azure/core-util": "^1.13.0",
+        "@azure/logger": "^1.3.0",
+        "tslib": "^2.6.2"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@azure/core-rest-pipeline": {
+      "version": "1.22.2",
+      "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.22.2.tgz",
+      "integrity": "sha512-MzHym+wOi8CLUlKCQu12de0nwcq9k9Kuv43j4Wa++CsCpJwps2eeBQwD2Bu8snkxTtDKDx4GwjuR9E8yC8LNrg==",
+      "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.0",
+        "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.0",
+      "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.0.tgz",
+      "integrity": "sha512-uWC0fssc+hs1TGGVkkghiaFkkS7NkTxfnCH+Hdg+yTehTpMcehpok4PgUKKdyCH+9ldu6FhiHRv84Ntqj1vVcw==",
+      "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": "^4.2.0",
+        "@azure/msal-node": "^3.5.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": "4.26.2",
+      "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.26.2.tgz",
+      "integrity": "sha512-F2U1mEAFsYGC5xzo1KuWc/Sy3CRglU9Ql46cDUx8x/Y3KnAIr1QAq96cIKCk/ZfnVxlvprXWRjNKoEpgLJXLhg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/msal-common": "15.13.2"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@azure/msal-common": {
+      "version": "15.13.2",
+      "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.2.tgz",
+      "integrity": "sha512-cNwUoCk3FF8VQ7Ln/MdcJVIv3sF73/OT86cRH81ECsydh7F4CNfIo2OAx6Cegtg8Yv75x4506wN4q+Emo6erOA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/@azure/msal-node": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.3.tgz",
+      "integrity": "sha512-Ul7A4gwmaHzYWj2Z5xBDly/W8JSC1vnKgJ898zPMZr0oSf1ah0tiL15sytjycU/PMhDZAlkWtEL1+MzNMU6uww==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/msal-common": "15.13.2",
+        "jsonwebtoken": "^9.0.0",
+        "uuid": "^8.3.0"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.27.1",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+      "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.27.1",
+        "js-tokens": "^4.0.0",
+        "picocolors": "^1.1.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.28.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
+      "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@emnapi/core": {
+      "version": "1.7.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.7.1.tgz",
+      "integrity": "sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/wasi-threads": "1.1.0",
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/runtime": {
+      "version": "1.7.1",
+      "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.7.1.tgz",
+      "integrity": "sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@emnapi/wasi-threads": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
+      "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@eslint-community/eslint-utils": {
+      "version": "4.9.0",
+      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz",
+      "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eslint-visitor-keys": "^3.4.3"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
+      }
+    },
+    "node_modules/@eslint-community/regexpp": {
+      "version": "4.12.2",
+      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz",
+      "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+      "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.6.0",
+        "globals": "^13.19.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/js": {
+      "version": "8.57.1",
+      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
+      "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array": {
+      "version": "0.13.0",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+      "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
+      "deprecated": "Use @eslint/config-array instead",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@humanwhocodes/object-schema": "^2.0.3",
+        "debug": "^4.3.1",
+        "minimatch": "^3.0.5"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@humanwhocodes/module-importer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
+      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.22"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/object-schema": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
+      "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
+      "deprecated": "Use @eslint/object-schema instead",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/@isaacs/balanced-match": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz",
+      "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/@isaacs/brace-expansion": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz",
+      "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@isaacs/balanced-match": "^4.0.1"
+      },
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/@isaacs/cliui": {
+      "version": "8.0.2",
+      "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+      "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "string-width": "^5.1.2",
+        "string-width-cjs": "npm:string-width@^4.2.0",
+        "strip-ansi": "^7.0.1",
+        "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+        "wrap-ansi": "^8.1.0",
+        "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@isaacs/cliui/node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@napi-rs/wasm-runtime": {
+      "version": "0.2.12",
+      "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+      "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@emnapi/core": "^1.4.3",
+        "@emnapi/runtime": "^1.4.3",
+        "@tybys/wasm-util": "^0.10.0"
+      }
+    },
+    "node_modules/@node-rs/crc32": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.6.tgz",
+      "integrity": "sha512-+llXfqt+UzgoDzT9of5vPQPGqTAVCohU74I9zIBkNo5TH6s2P31DFJOGsJQKN207f0GHnYv5pV3wh3BCY/un/A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/Brooooooklyn"
+      },
+      "optionalDependencies": {
+        "@node-rs/crc32-android-arm-eabi": "1.10.6",
+        "@node-rs/crc32-android-arm64": "1.10.6",
+        "@node-rs/crc32-darwin-arm64": "1.10.6",
+        "@node-rs/crc32-darwin-x64": "1.10.6",
+        "@node-rs/crc32-freebsd-x64": "1.10.6",
+        "@node-rs/crc32-linux-arm-gnueabihf": "1.10.6",
+        "@node-rs/crc32-linux-arm64-gnu": "1.10.6",
+        "@node-rs/crc32-linux-arm64-musl": "1.10.6",
+        "@node-rs/crc32-linux-x64-gnu": "1.10.6",
+        "@node-rs/crc32-linux-x64-musl": "1.10.6",
+        "@node-rs/crc32-wasm32-wasi": "1.10.6",
+        "@node-rs/crc32-win32-arm64-msvc": "1.10.6",
+        "@node-rs/crc32-win32-ia32-msvc": "1.10.6",
+        "@node-rs/crc32-win32-x64-msvc": "1.10.6"
+      }
+    },
+    "node_modules/@node-rs/crc32-android-arm-eabi": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.6.tgz",
+      "integrity": "sha512-vZAMuJXm3TpWPOkkhxdrofWDv+Q+I2oO7ucLRbXyAPmXFNDhHtBxbO1rk9Qzz+M3eep8ieS4/+jCL1Q0zacNMQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-android-arm64": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.6.tgz",
+      "integrity": "sha512-Vl/JbjCinCw/H9gEpZveWCMjxjcEChDcDBM8S4hKay5yyoRCUHJPuKr4sjVDBeOm+1nwU3oOm6Ca8dyblwp4/w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-darwin-arm64": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.6.tgz",
+      "integrity": "sha512-kARYANp5GnmsQiViA5Qu74weYQ3phOHSYQf0G+U5wB3NB5JmBHnZcOc46Ig21tTypWtdv7u63TaltJQE41noyg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-darwin-x64": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.6.tgz",
+      "integrity": "sha512-Q99bevJVMfLTISpkpKBlXgtPUItrvTWKFyiqoKH5IvscZmLV++NH4V13Pa17GTBmv9n18OwzgQY4/SRq6PQNVA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-freebsd-x64": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.6.tgz",
+      "integrity": "sha512-66hpawbNjrgnS9EDMErta/lpaqOMrL6a6ee+nlI2viduVOmRZWm9Rg9XdGTK/+c4bQLdtC6jOd+Kp4EyGRYkAg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-linux-arm-gnueabihf": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.6.tgz",
+      "integrity": "sha512-E8Z0WChH7X6ankbVm8J/Yym19Cq3otx6l4NFPS6JW/cWdjv7iw+Sps2huSug+TBprjbcEA+s4TvEwfDI1KScjg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-linux-arm64-gnu": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.6.tgz",
+      "integrity": "sha512-LmWcfDbqAvypX0bQjQVPmQGazh4dLiVklkgHxpV4P0TcQ1DT86H/SWpMBMs/ncF8DGuCQ05cNyMv1iddUDugoQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-linux-arm64-musl": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.6.tgz",
+      "integrity": "sha512-k8ra/bmg0hwRrIEE8JL1p32WfaN9gDlUUpQRWsbxd1WhjqvXea7kKO6K4DwVxyxlPhBS9Gkb5Urq7Y4mXANzaw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-linux-x64-gnu": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.6.tgz",
+      "integrity": "sha512-IfjtqcuFK7JrSZ9mlAFhb83xgium30PguvRjIMI45C3FJwu18bnLk1oR619IYb/zetQT82MObgmqfKOtgemEKw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-linux-x64-musl": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.6.tgz",
+      "integrity": "sha512-LbFYsA5M9pNunOweSt6uhxenYQF94v3bHDAQRPTQ3rnjn+mK6IC7YTAYoBjvoJP8lVzcvk9hRj8wp4Jyh6Y80g==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-wasm32-wasi": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-wasm32-wasi/-/crc32-wasm32-wasi-1.10.6.tgz",
+      "integrity": "sha512-KaejdLgHMPsRaxnM+OG9L9XdWL2TabNx80HLdsCOoX9BVhEkfh39OeahBo8lBmidylKbLGMQoGfIKDjq0YMStw==",
+      "cpu": [
+        "wasm32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "@napi-rs/wasm-runtime": "^0.2.5"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/@node-rs/crc32-win32-arm64-msvc": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.6.tgz",
+      "integrity": "sha512-x50AXiSxn5Ccn+dCjLf1T7ZpdBiV1Sp5aC+H2ijhJO4alwznvXgWbopPRVhbp2nj0i+Gb6kkDUEyU+508KAdGQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-win32-ia32-msvc": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.6.tgz",
+      "integrity": "sha512-DpDxQLaErJF9l36aghe1Mx+cOnYLKYo6qVPqPL9ukJ5rAGLtCdU0C+Zoi3gs9ySm8zmbFgazq/LvmsZYU42aBw==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@node-rs/crc32-win32-x64-msvc": {
+      "version": "1.10.6",
+      "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.6.tgz",
+      "integrity": "sha512-5B1vXosIIBw1m2Rcnw62IIfH7W9s9f7H7Ma0rRuhT8HR4Xh8QCgw6NJSI2S2MCngsGktYnAhyUvs81b7efTyQw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@secretlint/config-creator": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz",
+      "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/types": "^10.2.2"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/config-loader": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz",
+      "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/profiler": "^10.2.2",
+        "@secretlint/resolver": "^10.2.2",
+        "@secretlint/types": "^10.2.2",
+        "ajv": "^8.17.1",
+        "debug": "^4.4.1",
+        "rc-config-loader": "^4.1.3"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/config-loader/node_modules/ajv": {
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@secretlint/core": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz",
+      "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/profiler": "^10.2.2",
+        "@secretlint/types": "^10.2.2",
+        "debug": "^4.4.1",
+        "structured-source": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/formatter": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz",
+      "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/resolver": "^10.2.2",
+        "@secretlint/types": "^10.2.2",
+        "@textlint/linter-formatter": "^15.2.0",
+        "@textlint/module-interop": "^15.2.0",
+        "@textlint/types": "^15.2.0",
+        "chalk": "^5.4.1",
+        "debug": "^4.4.1",
+        "pluralize": "^8.0.0",
+        "strip-ansi": "^7.1.0",
+        "table": "^6.9.0",
+        "terminal-link": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/formatter/node_modules/ansi-regex": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/@secretlint/formatter/node_modules/chalk": {
+      "version": "5.6.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
+      "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^12.17.0 || ^14.13 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@secretlint/formatter/node_modules/strip-ansi": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "node_modules/@secretlint/node": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz",
+      "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/config-loader": "^10.2.2",
+        "@secretlint/core": "^10.2.2",
+        "@secretlint/formatter": "^10.2.2",
+        "@secretlint/profiler": "^10.2.2",
+        "@secretlint/source-creator": "^10.2.2",
+        "@secretlint/types": "^10.2.2",
+        "debug": "^4.4.1",
+        "p-map": "^7.0.3"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/profiler": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz",
+      "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@secretlint/resolver": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz",
+      "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@secretlint/secretlint-formatter-sarif": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz",
+      "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "node-sarif-builder": "^3.2.0"
+      }
+    },
+    "node_modules/@secretlint/secretlint-rule-no-dotenv": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz",
+      "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/types": "^10.2.2"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/secretlint-rule-preset-recommend": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz",
+      "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/source-creator": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz",
+      "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/types": "^10.2.2",
+        "istextorbinary": "^9.5.0"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@secretlint/types": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz",
+      "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/@sindresorhus/merge-streams": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
+      "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@textlint/ast-node-types": {
+      "version": "15.4.0",
+      "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.4.0.tgz",
+      "integrity": "sha512-IqY8i7IOGuvy05wZxISB7Me1ZyrvhaQGgx6DavfQjH3cfwpPFdDbDYmMXMuSv2xLS1kDB1kYKBV7fL2Vi16lRA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@textlint/linter-formatter": {
+      "version": "15.4.0",
+      "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.4.0.tgz",
+      "integrity": "sha512-rfqOZmnI1Wwc/Pa4LK+vagvVPmvxf9oRsBRqIOB04DwhucingZyAIJI/TyG18DIDYbP2aFXBZ3oOvyAxHe/8PQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azu/format-text": "^1.0.2",
+        "@azu/style-format": "^1.0.1",
+        "@textlint/module-interop": "15.4.0",
+        "@textlint/resolver": "15.4.0",
+        "@textlint/types": "15.4.0",
+        "chalk": "^4.1.2",
+        "debug": "^4.4.3",
+        "js-yaml": "^3.14.1",
+        "lodash": "^4.17.21",
+        "pluralize": "^2.0.0",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1",
+        "table": "^6.9.0",
+        "text-table": "^0.2.0"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/js-yaml": {
+      "version": "3.14.2",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
+      "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/pluralize": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz",
+      "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@textlint/linter-formatter/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@textlint/module-interop": {
+      "version": "15.4.0",
+      "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.4.0.tgz",
+      "integrity": "sha512-uGf+SFIfzOLCbZI0gp+2NLsrkSArsvEWulPP6lJuKp7yRHadmy7Xf/YHORe46qhNyyxc8PiAfiixHJSaHGUrGg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@textlint/resolver": {
+      "version": "15.4.0",
+      "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.4.0.tgz",
+      "integrity": "sha512-Vh/QceKZQHFJFG4GxxIsKM1Xhwv93mbtKHmFE5/ybal1mIKHdqF03Z9Guaqt6Sx/AeNUshq0hkMOEhEyEWnehQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@textlint/types": {
+      "version": "15.4.0",
+      "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.4.0.tgz",
+      "integrity": "sha512-ZMwJgw/xjxJufOD+IB7I2Enl9Si4Hxo04B76RwUZ5cKBKzOPcmd6WvGe2F7jqdgmTdGnfMU+Bo/joQrjPNIWqg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@textlint/ast-node-types": "15.4.0"
+      }
+    },
+    "node_modules/@tybys/wasm-util": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+      "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "tslib": "^2.4.0"
+      }
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/node": {
+      "version": "18.19.130",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
+      "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "undici-types": "~5.26.4"
+      }
+    },
+    "node_modules/@types/normalize-package-data": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz",
+      "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/sarif": {
+      "version": "2.1.7",
+      "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz",
+      "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/semver": {
+      "version": "7.7.1",
+      "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.1.tgz",
+      "integrity": "sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@types/vscode": {
+      "version": "1.106.1",
+      "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.106.1.tgz",
+      "integrity": "sha512-R/HV8u2h8CAddSbX8cjpdd7B8/GnE4UjgjpuGuHcbp1xV6yh4OeqU4L1pKjlwujCrSFS0MOpwJAIs/NexMB1fQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz",
+      "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/regexpp": "^4.5.1",
+        "@typescript-eslint/scope-manager": "6.21.0",
+        "@typescript-eslint/type-utils": "6.21.0",
+        "@typescript-eslint/utils": "6.21.0",
+        "@typescript-eslint/visitor-keys": "6.21.0",
+        "debug": "^4.3.4",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.4",
+        "natural-compare": "^1.4.0",
+        "semver": "^7.5.4",
+        "ts-api-utils": "^1.0.1"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
+        "eslint": "^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
+      "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "peer": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "6.21.0",
+        "@typescript-eslint/types": "6.21.0",
+        "@typescript-eslint/typescript-estree": "6.21.0",
+        "@typescript-eslint/visitor-keys": "6.21.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
+      "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "6.21.0",
+        "@typescript-eslint/visitor-keys": "6.21.0"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz",
+      "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/typescript-estree": "6.21.0",
+        "@typescript-eslint/utils": "6.21.0",
+        "debug": "^4.3.4",
+        "ts-api-utils": "^1.0.1"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
+      "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
+      "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "@typescript-eslint/types": "6.21.0",
+        "@typescript-eslint/visitor-keys": "6.21.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "minimatch": "9.0.3",
+        "semver": "^7.5.4",
+        "ts-api-utils": "^1.0.1"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz",
+      "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.4.0",
+        "@types/json-schema": "^7.0.12",
+        "@types/semver": "^7.5.0",
+        "@typescript-eslint/scope-manager": "6.21.0",
+        "@typescript-eslint/types": "6.21.0",
+        "@typescript-eslint/typescript-estree": "6.21.0",
+        "semver": "^7.5.4"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "6.21.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
+      "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@typescript-eslint/types": "6.21.0",
+        "eslint-visitor-keys": "^3.4.1"
+      },
+      "engines": {
+        "node": "^16.0.0 || >=18.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typespec/ts-http-runtime": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz",
+      "integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==",
+      "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/@ungap/structured-clone": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
+      "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "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/@vscode/vsce/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@vscode/vsce/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "8.15.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+      "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "license": "MIT",
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "7.1.4",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+      "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz",
+      "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "environment": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "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/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/astral-regex": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+      "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/azure-devops-node-api": {
+      "version": "12.5.0",
+      "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz",
+      "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "tunnel": "0.0.6",
+        "typed-rest-client": "^1.8.4"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "license": "MIT"
+    },
+    "node_modules/base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/binaryextensions": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz",
+      "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==",
+      "dev": true,
+      "license": "Artistic-2.0",
+      "dependencies": {
+        "editions": "^6.21.0"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "funding": {
+        "url": "https://bevry.me/fund"
+      }
+    },
+    "node_modules/bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/boundary": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz",
+      "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/brace-expansion": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+      "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+      "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fill-range": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "node_modules/buffer-crc32": {
+      "version": "0.2.13",
+      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+      "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/bundle-name": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+      "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "run-applescript": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/call-bind-apply-helpers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+      "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "function-bind": "^1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/call-bound": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
+      "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bind-apply-helpers": "^1.0.2",
+        "get-intrinsic": "^1.3.0"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "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.1.2",
+      "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.1.2.tgz",
+      "integrity": "sha512-IkxPpb5rS/d1IiLbHMgfPuS0FgiWTtFIm/Nj+2woXDLTZ7fOT2eqzgYbdMlLweqlHbsZjxEChoVK+7iph7jyQg==",
+      "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.0.0",
+        "parse5": "^7.3.0",
+        "parse5-htmlparser2-tree-adapter": "^7.1.0",
+        "parse5-parser-stream": "^7.1.2",
+        "undici": "^7.12.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/ci-info": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+      "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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/cross-spawn": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+      "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/css-select": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+      "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.1.0",
+        "domhandler": "^5.0.2",
+        "domutils": "^3.0.1",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+      "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/debug": {
+      "version": "4.4.3",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ms": "^2.1.3"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/decompress-response": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
+      "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "mimic-response": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/deep-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/deep-is": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
+      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/default-browser": {
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.4.0.tgz",
+      "integrity": "sha512-XDuvSq38Hr1MdN47EDvYtx3U0MTqpCEn+F6ft8z2vYDzMrvQhVp0ui9oQdqW3MvK3vqUETglt1tVGgjLuJ5izg==",
+      "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-data-property": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+      "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0",
+        "es-errors": "^1.3.0",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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/define-properties": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+      "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-data-property": "^1.0.1",
+        "has-property-descriptors": "^1.0.0",
+        "object-keys": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "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/eastasianwidth": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+      "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ecdsa-sig-formatter": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+      "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      }
+    },
+    "node_modules/editions": {
+      "version": "6.22.0",
+      "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz",
+      "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==",
+      "dev": true,
+      "license": "Artistic-2.0",
+      "dependencies": {
+        "version-range": "^4.15.0"
+      },
+      "engines": {
+        "ecmascript": ">= es5",
+        "node": ">=4"
+      },
+      "funding": {
+        "url": "https://bevry.me/fund"
+      }
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/encoding-sniffer": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz",
+      "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "iconv-lite": "^0.6.3",
+        "whatwg-encoding": "^3.1.1"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/encoding-sniffer?sponsor=1"
+      }
+    },
+    "node_modules/end-of-stream": {
+      "version": "1.4.5",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
+      "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "once": "^1.4.0"
+      }
+    },
+    "node_modules/entities": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/environment": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz",
+      "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/es-define-property": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+      "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-errors": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+      "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "node_modules/es-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/eslint": {
+      "version": "8.57.1",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
+      "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
+      "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@eslint-community/eslint-utils": "^4.2.0",
+        "@eslint-community/regexpp": "^4.6.1",
+        "@eslint/eslintrc": "^2.1.4",
+        "@eslint/js": "8.57.1",
+        "@humanwhocodes/config-array": "^0.13.0",
+        "@humanwhocodes/module-importer": "^1.0.1",
+        "@nodelib/fs.walk": "^1.2.8",
+        "@ungap/structured-clone": "^1.2.0",
+        "ajv": "^6.12.4",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.2.2",
+        "eslint-visitor-keys": "^3.4.3",
+        "espree": "^9.6.1",
+        "esquery": "^1.4.2",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "glob-parent": "^6.0.2",
+        "globals": "^13.19.0",
+        "graphemer": "^1.4.0",
+        "ignore": "^5.2.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "is-path-inside": "^3.0.3",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.3",
+        "strip-ansi": "^6.0.1",
+        "text-table": "^0.2.0"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "7.2.2",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+      "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.4.3",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+      "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/eslint/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/eslint/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/eslint/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/eslint/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/eslint/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/eslint/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/eslint/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.6.1",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "acorn": "^8.9.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.4.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/esquery": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz",
+      "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.10.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/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+      "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.8"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-levenshtein": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
+      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/fast-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+      "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fastify"
+        },
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/fastify"
+        }
+      ],
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/fastq": {
+      "version": "1.19.1",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+      "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fd-slicer": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
+      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "pend": "~1.2.0"
+      }
+    },
+    "node_modules/file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flat-cache": "^3.0.4"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+      "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/flat-cache": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+      "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "flatted": "^3.2.9",
+        "keyv": "^4.5.3",
+        "rimraf": "^3.0.2"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
+      "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.11",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
+      "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/foreground-child": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+      "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "cross-spawn": "^7.0.6",
+        "signal-exit": "^4.0.1"
+      },
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz",
+      "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "es-set-tostringtag": "^2.1.0",
+        "hasown": "^2.0.2",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/fs-extra": {
+      "version": "11.3.2",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz",
+      "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "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": "Glob versions prior to v9 are no longer supported",
+      "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/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/glob/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/glob/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/globals": {
+      "version": "13.24.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+      "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/globalthis": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
+      "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "define-properties": "^1.2.1",
+        "gopd": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/gopd": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+      "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/graphemer": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
+      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "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-property-descriptors": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+      "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-define-property": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "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.0.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz",
+      "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==",
+      "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.1",
+        "entities": "^6.0.0"
+      }
+    },
+    "node_modules/htmlparser2/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/http-proxy-agent": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+      "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "7.0.6",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+      "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "agent-base": "^7.1.2",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 14"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "BSD-3-Clause",
+      "optional": true
+    },
+    "node_modules/ignore": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz",
+      "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz",
+      "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/index-to-position": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz",
+      "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/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-ci": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
+      "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ci-info": "^2.0.0"
+      },
+      "bin": {
+        "is-ci": "bin.js"
+      }
+    },
+    "node_modules/is-docker": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+      "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-inside-container": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+      "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-docker": "^3.0.0"
+      },
+      "bin": {
+        "is-inside-container": "cli.js"
+      },
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-it-type": {
+      "version": "5.1.3",
+      "resolved": "https://registry.npmjs.org/is-it-type/-/is-it-type-5.1.3.tgz",
+      "integrity": "sha512-AX2uU0HW+TxagTgQXOJY7+2fbFHemC7YFBwN1XqD8qQMKdtfbOC8OC3fUb4s5NU59a3662Dzwto8tWDdZYRXxg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "globalthis": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-path-inside": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
+      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-wsl": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
+      "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-inside-container": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/istextorbinary": {
+      "version": "9.5.0",
+      "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz",
+      "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==",
+      "dev": true,
+      "license": "Artistic-2.0",
+      "dependencies": {
+        "binaryextensions": "^6.11.0",
+        "editions": "^6.21.0",
+        "textextensions": "^6.11.0"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "funding": {
+        "url": "https://bevry.me/fund"
+      }
+    },
+    "node_modules/jackspeak": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz",
+      "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/cliui": "^8.0.2"
+      },
+      "engines": {
+        "node": "20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/js-yaml": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz",
+      "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/json-buffer": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
+      "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonc-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz",
+      "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/jsonfile": {
+      "version": "6.2.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz",
+      "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonwebtoken": {
+      "version": "9.0.2",
+      "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+      "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jws": "^3.2.2",
+        "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": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
+      "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
+      "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": "3.2.2",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+      "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "jwa": "^1.4.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/keyv": {
+      "version": "4.5.4",
+      "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+      "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "json-buffer": "3.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/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "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/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.includes": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+      "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isinteger": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+      "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isnumber": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+      "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.isstring": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+      "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.once": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+      "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/lodash.truncate": {
+      "version": "4.4.2",
+      "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
+      "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/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/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+      "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "braces": "^3.0.3",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mimic-response": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
+      "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "9.0.3",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+      "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/minipass": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+      "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=16 || 14 >=14.17"
+      }
+    },
+    "node_modules/mkdirp-classic": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
+      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/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/natural-compare": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
+      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/node-abi": {
+      "version": "3.85.0",
+      "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz",
+      "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
+      "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/node-sarif-builder": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.3.0.tgz",
+      "integrity": "sha512-8taRy2nQs1xNs8iO2F0XbkZJEliiijpKgFVcyiwKjJ2+3X59LVI3wY84qRdJwRDpIo5GK8wvb1pxcJ+JVu3jrg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/sarif": "^2.1.7",
+        "fs-extra": "^11.1.1"
+      },
+      "engines": {
+        "node": ">=20"
+      }
+    },
+    "node_modules/normalize-package-data": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz",
+      "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "hosted-git-info": "^7.0.0",
+        "semver": "^7.3.5",
+        "validate-npm-package-license": "^3.0.4"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      }
+    },
+    "node_modules/normalize-package-data/node_modules/hosted-git-info": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz",
+      "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "lru-cache": "^10.0.1"
+      },
+      "engines": {
+        "node": "^16.14.0 || >=18.0.0"
+      }
+    },
+    "node_modules/normalize-package-data/node_modules/lru-cache": {
+      "version": "10.4.3",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+      "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.13.4",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
+      "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/object-keys": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.4"
+      }
+    },
+    "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/optionator": {
+      "version": "0.9.4",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+      "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.5"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/ovsx": {
+      "version": "0.10.7",
+      "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.7.tgz",
+      "integrity": "sha512-UjBQlB5xSDD+biAylCZ8Q/k3An9K3y9FYa+hT/HTbJkzOQP+gaNHX20CaOo4lrYT1iJXdiePH9zS2uvCXdDNDA==",
+      "dev": true,
+      "license": "EPL-2.0",
+      "dependencies": {
+        "@vscode/vsce": "^3.2.1",
+        "commander": "^6.2.1",
+        "follow-redirects": "^1.14.6",
+        "is-ci": "^2.0.0",
+        "leven": "^3.1.0",
+        "semver": "^7.6.0",
+        "tmp": "^0.2.3",
+        "yauzl-promise": "^4.0.0"
+      },
+      "bin": {
+        "ovsx": "lib/ovsx"
+      },
+      "engines": {
+        "node": ">= 20"
+      }
+    },
+    "node_modules/ovsx/node_modules/@vscode/vsce": {
+      "version": "3.7.0",
+      "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.7.0.tgz",
+      "integrity": "sha512-LY9r2T4joszRjz4d92ZPl6LTBUPS4IWH9gG/3JUv+1QyBJrveZlcVISuiaq0EOpmcgFh0GgVgKD4rD/21Tu8sA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@azure/identity": "^4.1.0",
+        "@secretlint/node": "^10.1.2",
+        "@secretlint/secretlint-formatter-sarif": "^10.1.2",
+        "@secretlint/secretlint-rule-no-dotenv": "^10.1.2",
+        "@secretlint/secretlint-rule-preset-recommend": "^10.1.2",
+        "@vscode/vsce-sign": "^2.0.0",
+        "azure-devops-node-api": "^12.5.0",
+        "chalk": "^4.1.2",
+        "cheerio": "^1.0.0-rc.9",
+        "cockatiel": "^3.1.2",
+        "commander": "^12.1.0",
+        "form-data": "^4.0.0",
+        "glob": "^11.0.0",
+        "hosted-git-info": "^4.0.2",
+        "jsonc-parser": "^3.2.0",
+        "leven": "^3.1.0",
+        "markdown-it": "^14.1.0",
+        "mime": "^1.3.4",
+        "minimatch": "^3.0.3",
+        "parse-semver": "^1.1.1",
+        "read": "^1.0.7",
+        "secretlint": "^10.1.2",
+        "semver": "^7.5.2",
+        "tmp": "^0.2.3",
+        "typed-rest-client": "^1.8.4",
+        "url-join": "^4.0.1",
+        "xml2js": "^0.5.0",
+        "yauzl": "^2.3.1",
+        "yazl": "^2.2.2"
+      },
+      "bin": {
+        "vsce": "vsce"
+      },
+      "engines": {
+        "node": ">= 20"
+      },
+      "optionalDependencies": {
+        "keytar": "^7.7.0"
+      }
+    },
+    "node_modules/ovsx/node_modules/@vscode/vsce/node_modules/commander": {
+      "version": "12.1.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
+      "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/ovsx/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/ovsx/node_modules/brace-expansion": {
+      "version": "1.1.12",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+      "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/ovsx/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/ovsx/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/ovsx/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ovsx/node_modules/glob": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz",
+      "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "foreground-child": "^3.3.1",
+        "jackspeak": "^4.1.1",
+        "minimatch": "^10.1.1",
+        "minipass": "^7.1.2",
+        "package-json-from-dist": "^1.0.0",
+        "path-scurry": "^2.0.0"
+      },
+      "bin": {
+        "glob": "dist/esm/bin.mjs"
+      },
+      "engines": {
+        "node": "20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/ovsx/node_modules/glob/node_modules/minimatch": {
+      "version": "10.1.1",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz",
+      "integrity": "sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "@isaacs/brace-expansion": "^5.0.0"
+      },
+      "engines": {
+        "node": "20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/ovsx/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ovsx/node_modules/linkify-it": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
+      "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "uc.micro": "^2.0.0"
+      }
+    },
+    "node_modules/ovsx/node_modules/markdown-it": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
+      "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "argparse": "^2.0.1",
+        "entities": "^4.4.0",
+        "linkify-it": "^5.0.0",
+        "mdurl": "^2.0.0",
+        "punycode.js": "^2.3.1",
+        "uc.micro": "^2.1.0"
+      },
+      "bin": {
+        "markdown-it": "bin/markdown-it.mjs"
+      }
+    },
+    "node_modules/ovsx/node_modules/mdurl": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
+      "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/ovsx/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/ovsx/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ovsx/node_modules/uc.micro": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
+      "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-map": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz",
+      "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/package-json-from-dist": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+      "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+      "dev": true,
+      "license": "BlueOak-1.0.0"
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz",
+      "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@babel/code-frame": "^7.26.2",
+        "index-to-position": "^1.1.0",
+        "type-fest": "^4.39.1"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parse-json/node_modules/type-fest": {
+      "version": "4.41.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+      "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/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-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "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/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-scurry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz",
+      "integrity": "sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==",
+      "dev": true,
+      "license": "BlueOak-1.0.0",
+      "dependencies": {
+        "lru-cache": "^11.0.0",
+        "minipass": "^7.1.2"
+      },
+      "engines": {
+        "node": "20 || >=22"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/path-scurry/node_modules/lru-cache": {
+      "version": "11.2.2",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.2.tgz",
+      "integrity": "sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": "20 || >=22"
+      }
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/pend": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
+      "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "dev": true,
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pluralize": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
+      "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/prebuild-install": {
+      "version": "7.1.3",
+      "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
+      "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
+      "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/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/pump": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
+      "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "end-of-stream": "^1.1.0",
+        "once": "^1.3.1"
+      }
+    },
+    "node_modules/punycode": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+      "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/punycode.js": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
+      "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.14.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
+      "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "side-channel": "^1.1.0"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/rc": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+      "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
+      "dev": true,
+      "license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
+      "optional": true,
+      "dependencies": {
+        "deep-extend": "^0.6.0",
+        "ini": "~1.3.0",
+        "minimist": "^1.2.0",
+        "strip-json-comments": "~2.0.1"
+      },
+      "bin": {
+        "rc": "cli.js"
+      }
+    },
+    "node_modules/rc-config-loader": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz",
+      "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "debug": "^4.3.4",
+        "js-yaml": "^4.1.0",
+        "json5": "^2.2.2",
+        "require-from-string": "^2.0.2"
+      }
+    },
+    "node_modules/rc/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/read": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
+      "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "mute-stream": "~0.0.4"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/read-pkg": {
+      "version": "9.0.1",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz",
+      "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/normalize-package-data": "^2.4.3",
+        "normalize-package-data": "^6.0.0",
+        "parse-json": "^8.0.0",
+        "type-fest": "^4.6.0",
+        "unicorn-magic": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/read-pkg/node_modules/type-fest": {
+      "version": "4.41.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+      "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+      "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "deprecated": "Rimraf versions prior to v4 are no longer supported",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/run-applescript": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+      "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT"
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/sax": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.3.tgz",
+      "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==",
+      "dev": true,
+      "license": "BlueOak-1.0.0"
+    },
+    "node_modules/secretlint": {
+      "version": "10.2.2",
+      "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz",
+      "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@secretlint/config-creator": "^10.2.2",
+        "@secretlint/formatter": "^10.2.2",
+        "@secretlint/node": "^10.2.2",
+        "@secretlint/profiler": "^10.2.2",
+        "debug": "^4.4.1",
+        "globby": "^14.1.0",
+        "read-pkg": "^9.0.1"
+      },
+      "bin": {
+        "secretlint": "bin/secretlint.js"
+      },
+      "engines": {
+        "node": ">=20.0.0"
+      }
+    },
+    "node_modules/secretlint/node_modules/globby": {
+      "version": "14.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz",
+      "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@sindresorhus/merge-streams": "^2.1.0",
+        "fast-glob": "^3.3.3",
+        "ignore": "^7.0.3",
+        "path-type": "^6.0.0",
+        "slash": "^5.1.0",
+        "unicorn-magic": "^0.3.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/secretlint/node_modules/ignore": {
+      "version": "7.0.5",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+      "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/secretlint/node_modules/path-type": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz",
+      "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/secretlint/node_modules/slash": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
+      "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.16"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/secretlint/node_modules/unicorn-magic": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+      "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/semver": {
+      "version": "7.7.3",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
+      "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
+      "license": "ISC",
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
+      "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3",
+        "side-channel-list": "^1.0.0",
+        "side-channel-map": "^1.0.1",
+        "side-channel-weakmap": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-list": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+      "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "es-errors": "^1.3.0",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-map": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
+      "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/side-channel-weakmap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+      "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "call-bound": "^1.0.2",
+        "es-errors": "^1.3.0",
+        "get-intrinsic": "^1.2.5",
+        "object-inspect": "^1.13.3",
+        "side-channel-map": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+      "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+      "dev": true,
+      "license": "ISC",
+      "engines": {
+        "node": ">=14"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/simple-concat": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
+      "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/simple-get": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
+      "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "decompress-response": "^6.0.0",
+        "once": "^1.3.1",
+        "simple-concat": "^1.0.0"
+      }
+    },
+    "node_modules/simple-invariant": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/simple-invariant/-/simple-invariant-2.0.1.tgz",
+      "integrity": "sha512-1sbhsxqI+I2tqlmjbz99GXNmZtr6tKIyEgGGnJw/MKGblalqk/XoOYYFJlBzTKZCxx8kLaD3FD5s9BEEjx5Pyg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/slash": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
+      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/slice-ansi": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
+      "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "astral-regex": "^2.0.0",
+        "is-fullwidth-code-point": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/slice-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/spdx-correct": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+      "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "spdx-expression-parse": "^3.0.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-exceptions": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+      "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+      "dev": true,
+      "license": "CC-BY-3.0"
+    },
+    "node_modules/spdx-expression-parse": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "spdx-exceptions": "^2.1.0",
+        "spdx-license-ids": "^3.0.0"
+      }
+    },
+    "node_modules/spdx-license-ids": {
+      "version": "3.0.22",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz",
+      "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==",
+      "dev": true,
+      "license": "CC0-1.0"
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
+      "dev": true,
+      "license": "BSD-3-Clause"
+    },
+    "node_modules/string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/string-width-cjs": {
+      "name": "string-width",
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi-cjs": {
+      "name": "strip-ansi",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/structured-source": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz",
+      "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "boundary": "^2.0.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "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/supports-hyperlinks": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz",
+      "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=14.18"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1"
+      }
+    },
+    "node_modules/supports-hyperlinks/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-hyperlinks/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/table": {
+      "version": "6.9.0",
+      "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz",
+      "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==",
+      "dev": true,
+      "license": "BSD-3-Clause",
+      "dependencies": {
+        "ajv": "^8.0.1",
+        "lodash.truncate": "^4.4.2",
+        "slice-ansi": "^4.0.0",
+        "string-width": "^4.2.3",
+        "strip-ansi": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/table/node_modules/ajv": {
+      "version": "8.17.1",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+      "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3",
+        "fast-uri": "^3.0.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/table/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/tar-fs": {
+      "version": "2.1.4",
+      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
+      "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "chownr": "^1.1.1",
+        "mkdirp-classic": "^0.5.2",
+        "pump": "^3.0.0",
+        "tar-stream": "^2.1.4"
+      }
+    },
+    "node_modules/tar-stream": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "bl": "^4.0.3",
+        "end-of-stream": "^1.4.1",
+        "fs-constants": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/terminal-link": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz",
+      "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-escapes": "^7.0.0",
+        "supports-hyperlinks": "^3.2.0"
+      },
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/textextensions": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz",
+      "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==",
+      "dev": true,
+      "license": "Artistic-2.0",
+      "dependencies": {
+        "editions": "^6.21.0"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "funding": {
+        "url": "https://bevry.me/fund"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.5",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz",
+      "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.14"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/ts-api-utils": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz",
+      "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=16"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.2.0"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.8.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+      "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+      "dev": true,
+      "license": "0BSD"
+    },
+    "node_modules/tunnel": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+      "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+      }
+    },
+    "node_modules/tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "license": "(MIT OR CC0-1.0)",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/typed-rest-client": {
+      "version": "1.8.11",
+      "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz",
+      "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "qs": "^6.9.1",
+        "tunnel": "0.0.6",
+        "underscore": "^1.12.1"
+      }
+    },
+    "node_modules/typescript": {
+      "version": "5.9.3",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "peer": true,
+      "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.7",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz",
+      "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/undici": {
+      "version": "7.16.0",
+      "resolved": "https://registry.npmjs.org/undici/-/undici-7.16.0.tgz",
+      "integrity": "sha512-QEg3HPMll0o3t2ourKwOeUAZ159Kn9mx5pnzHRQO8+Wixmh88YdZRiIwat0iNzNNXn0yoEtXJqFpyW7eM8BV7g==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=20.18.1"
+      }
+    },
+    "node_modules/undici-types": {
+      "version": "5.26.5",
+      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+      "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/unicorn-magic": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
+      "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
+      "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/url-join": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
+      "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/validate-npm-package-license": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "dependencies": {
+        "spdx-correct": "^3.0.0",
+        "spdx-expression-parse": "^3.0.0"
+      }
+    },
+    "node_modules/version-range": {
+      "version": "4.15.0",
+      "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz",
+      "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==",
+      "dev": true,
+      "license": "Artistic-2.0",
+      "engines": {
+        "node": ">=4"
+      },
+      "funding": {
+        "url": "https://bevry.me/fund"
+      }
+    },
+    "node_modules/vscode-jsonrpc": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz",
+      "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
+    "node_modules/vscode-languageclient": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz",
+      "integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==",
+      "license": "MIT",
+      "dependencies": {
+        "minimatch": "^5.1.0",
+        "semver": "^7.3.7",
+        "vscode-languageserver-protocol": "3.17.3"
+      },
+      "engines": {
+        "vscode": "^1.67.0"
+      }
+    },
+    "node_modules/vscode-languageclient/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/vscode-languageserver-protocol": {
+      "version": "3.17.3",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz",
+      "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==",
+      "license": "MIT",
+      "dependencies": {
+        "vscode-jsonrpc": "8.1.0",
+        "vscode-languageserver-types": "3.17.3"
+      }
+    },
+    "node_modules/vscode-languageserver-types": {
+      "version": "3.17.3",
+      "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
+      "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA==",
+      "license": "MIT"
+    },
+    "node_modules/whatwg-encoding": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+      "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "iconv-lite": "0.6.3"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/whatwg-mimetype": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+      "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=18"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/word-wrap": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+      "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/wrap-ansi": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+      "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^6.1.0",
+        "string-width": "^5.0.1",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs": {
+      "name": "wrap-ansi",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/wrap-ansi-cjs/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-regex": {
+      "version": "6.2.2",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+      "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "6.2.3",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+      "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/emoji-regex": {
+      "version": "9.2.2",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+      "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/wrap-ansi/node_modules/string-width": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+      "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "eastasianwidth": "^0.2.0",
+        "emoji-regex": "^9.2.2",
+        "strip-ansi": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/strip-ansi": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+      "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "ansi-regex": "^6.0.1"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+      }
+    },
+    "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/yauzl-promise": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-4.0.0.tgz",
+      "integrity": "sha512-/HCXpyHXJQQHvFq9noqrjfa/WpQC2XYs3vI7tBiAi4QiIU1knvYhZGaO1QPjwIVMdqflxbmwgMXtYeaRiAE0CA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@node-rs/crc32": "^1.7.0",
+        "is-it-type": "^5.1.2",
+        "simple-invariant": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=16"
+      }
+    },
+    "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"
+      }
+    },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    }
+  }
+}
diff --git a/plugin/package.json b/plugin/package.json
new file mode 100644
index 0000000..7a22063
--- /dev/null
+++ b/plugin/package.json
@@ -0,0 +1,201 @@
+{
+  "name": "isl-language-support",
+  "displayName": "ISL Language Support",
+  "description": "Comprehensive language support for ISL (Intuitive Scripting Language) - JSON transformation language",
+  "version": "1.1.0",
+  "publisher": "isl-team",
+  "icon": "images/icon.png",
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/intuit/isl"
+  },
+  "engines": {
+    "vscode": "^1.75.0"
+  },
+  "categories": [
+    "Programming Languages",
+    "Formatters",
+    "Linters"
+  ],
+  "keywords": [
+    "isl",
+    "json",
+    "transformation",
+    "scripting",
+    "jolt"
+  ],
+  "activationEvents": [
+    "onLanguage:isl",
+    "workspaceContains:**/*.isl"
+  ],
+  "main": "./out/extension.js",
+  "contributes": {
+    "languages": [
+      {
+        "id": "isl",
+        "aliases": [
+          "ISL",
+          "isl"
+        ],
+        "extensions": [
+          ".isl"
+        ],
+        "configuration": "./language-configuration.json",
+        "icon": {
+          "light": "./images/file-icon.svg",
+          "dark": "./images/file-icon.svg"
+        }
+      }
+    ],
+    "grammars": [
+      {
+        "language": "isl",
+        "scopeName": "source.isl",
+        "path": "./syntaxes/isl.tmLanguage.json"
+      }
+    ],
+    "configuration": {
+      "title": "ISL",
+      "properties": {
+        "isl.validation.enabled": {
+          "type": "boolean",
+          "default": true,
+          "description": "Enable/disable ISL validation"
+        },
+        "isl.formatting.enabled": {
+          "type": "boolean",
+          "default": true,
+          "description": "Enable/disable ISL formatting"
+        },
+        "isl.formatting.indentSize": {
+          "type": "number",
+          "default": 4,
+          "description": "Number of spaces for indentation"
+        },
+        "isl.formatting.useTabs": {
+          "type": "boolean",
+          "default": false,
+          "description": "Use tabs instead of spaces"
+        },
+        "isl.formatting.alignProperties": {
+          "type": "boolean",
+          "default": false,
+          "description": "Align object property colons"
+        },
+        "isl.linting.enabled": {
+          "type": "boolean",
+          "default": true,
+          "description": "Enable/disable ISL linting"
+        },
+        "isl.execution.islCommand": {
+          "type": "string",
+          "default": "isl",
+          "description": "Path to ISL command line tool (isl.sh or isl.bat)"
+        },
+        "isl.execution.javaHome": {
+          "type": "string",
+          "default": "",
+          "description": "Path to Java home directory (if not in PATH)"
+        },
+        "isl.trace.server": {
+          "type": "string",
+          "enum": [
+            "off",
+            "messages",
+            "verbose"
+          ],
+          "default": "off",
+          "description": "Traces the communication between VS Code and the language server"
+        }
+      }
+    },
+    "commands": [
+      {
+        "command": "isl.validate",
+        "title": "ISL: Validate Current File"
+      },
+      {
+        "command": "isl.run",
+        "title": "ISL: Run Transformation"
+      },
+      {
+        "command": "isl.runWithInput",
+        "title": "ISL: Run Transformation with Input File"
+      },
+      {
+        "command": "isl.format",
+        "title": "ISL: Format Document"
+      },
+      {
+        "command": "isl.showDocumentation",
+        "title": "ISL: Open Documentation"
+      }
+    ],
+    "menus": {
+      "editor/context": [
+        {
+          "when": "resourceLangId == isl",
+          "command": "isl.validate",
+          "group": "isl@1"
+        },
+        {
+          "when": "resourceLangId == isl",
+          "command": "isl.run",
+          "group": "isl@2"
+        },
+        {
+          "when": "resourceLangId == isl",
+          "command": "isl.runWithInput",
+          "group": "isl@3"
+        }
+      ],
+      "commandPalette": [
+        {
+          "command": "isl.validate",
+          "when": "resourceLangId == isl"
+        },
+        {
+          "command": "isl.run",
+          "when": "resourceLangId == isl"
+        },
+        {
+          "command": "isl.runWithInput",
+          "when": "resourceLangId == isl"
+        },
+        {
+          "command": "isl.format",
+          "when": "resourceLangId == isl"
+        }
+      ]
+    },
+    "snippets": [
+      {
+        "language": "isl",
+        "path": "./snippets/isl.json"
+      }
+    ]
+  },
+  "scripts": {
+    "vscode:prepublish": "npm run compile",
+    "compile": "tsc -p ./",
+    "watch": "tsc -watch -p ./",
+    "pretest": "npm run compile",
+    "lint": "eslint src --ext ts",
+    "package": "vsce package",
+    "publish": "vsce publish",
+    "publish:ovsx": "ovsx publish"
+  },
+  "devDependencies": {
+    "@types/node": "^18.0.0",
+    "@types/vscode": "^1.75.0",
+    "@typescript-eslint/eslint-plugin": "^6.0.0",
+    "@typescript-eslint/parser": "^6.0.0",
+    "@vscode/vsce": "^2.32.0",
+    "eslint": "^8.40.0",
+    "ovsx": "^0.10.7",
+    "typescript": "^5.0.0"
+  },
+  "dependencies": {
+    "vscode-languageclient": "^8.1.0"
+  }
+}
diff --git a/plugin/snippets/isl.json b/plugin/snippets/isl.json
new file mode 100644
index 0000000..cdfa6dc
--- /dev/null
+++ b/plugin/snippets/isl.json
@@ -0,0 +1,347 @@
+{
+  "ISL Function": {
+    "prefix": "fun",
+    "body": [
+      "fun ${1:functionName}(${2:\\$input}) {",
+      "\t${3:// function body}",
+      "\treturn {",
+      "\t\t${4:result}: ${5:value}",
+      "\t}",
+      "}"
+    ],
+    "description": "Create an ISL function"
+  },
+  "ISL Modifier Function": {
+    "prefix": "modifier",
+    "body": [
+      "modifier ${1:modifierName}(${2:\\$value}) {",
+      "\treturn ${3:\\$value}",
+      "}"
+    ],
+    "description": "Create an ISL modifier function"
+  },
+  "ISL Run Function": {
+    "prefix": "run",
+    "body": [
+      "fun run(${1:\\$input}) {",
+      "\t${2:// Transform input}",
+      "\t$0",
+      "}"
+    ],
+    "description": "Create an ISL run function (entry point)"
+  },
+  "ISL If Statement": {
+    "prefix": "if",
+    "body": [
+      "if (${1:condition})",
+      "\t${2:// true block}",
+      "else",
+      "\t${3:// false block}",
+      "endif"
+    ],
+    "description": "If-else statement"
+  },
+  "ISL If Expression": {
+    "prefix": "ife",
+    "body": [
+      "if (${1:condition}) ${2:trueValue} else ${3:falseValue} endif"
+    ],
+    "description": "Inline if expression"
+  },
+  "ISL Switch": {
+    "prefix": "switch",
+    "body": [
+      "switch (${1:\\$variable})",
+      "\t${2:value} -> ${3:result};",
+      "\telse -> ${4:default};",
+      "endswitch"
+    ],
+    "description": "Switch-case statement"
+  },
+  "ISL ForEach": {
+    "prefix": "foreach",
+    "body": [
+      "foreach ${1:\\$item} in ${2:\\$array}",
+      "\t{",
+      "\t\t${3:property}: ${4:\\$item.value}",
+      "\t}",
+      "endfor"
+    ],
+    "description": "ForEach loop"
+  },
+  "ISL Parallel ForEach": {
+    "prefix": "parallel",
+    "body": [
+      "parallel foreach ${1:\\$item} in ${2:\\$array}",
+      "\t{",
+      "\t\t${3:property}: ${4:\\$item.value}",
+      "\t}",
+      "endfor"
+    ],
+    "description": "Parallel foreach loop"
+  },
+  "ISL While Loop": {
+    "prefix": "while",
+    "body": [
+      "while (${1:condition})",
+      "\t${2:// loop body}",
+      "endwhile"
+    ],
+    "description": "While loop"
+  },
+  "ISL Import": {
+    "prefix": "import",
+    "body": [
+      "import ${1:ModuleName} from '${2:module.isl}';"
+    ],
+    "description": "Import statement"
+  },
+  "ISL Type Declaration": {
+    "prefix": "type",
+    "body": [
+      "type ${1:TypeName} as {",
+      "\t${2:property}: ${3:String}",
+      "};"
+    ],
+    "description": "Type declaration"
+  },
+  "ISL Variable": {
+    "prefix": "var",
+    "body": [
+      "\\$${1:name} = ${2:value};"
+    ],
+    "description": "Variable declaration"
+  },
+  "ISL Object": {
+    "prefix": "obj",
+    "body": [
+      "{",
+      "\t${1:property}: ${2:value}",
+      "}"
+    ],
+    "description": "Object literal"
+  },
+  "ISL String Interpolation": {
+    "prefix": "interp",
+    "body": [
+      "`${${1:\\$variable}}`"
+    ],
+    "description": "String interpolation"
+  },
+  "ISL Math Expression": {
+    "prefix": "math",
+    "body": [
+      "{{ ${1:expression} }}"
+    ],
+    "description": "Math expression"
+  },
+  "ISL Function Call": {
+    "prefix": "call",
+    "body": [
+      "@.${1:Service}.${2:Method}(${3:args})"
+    ],
+    "description": "Function call"
+  },
+  "ISL Filter": {
+    "prefix": "filter",
+    "body": [
+      "${1:\\$array} | filter(${2:condition})"
+    ],
+    "description": "Filter modifier"
+  },
+  "ISL Map": {
+    "prefix": "map",
+    "body": [
+      "${1:\\$array} | map(${2:expression})"
+    ],
+    "description": "Map modifier"
+  },
+  "ISL Date Now": {
+    "prefix": "now",
+    "body": [
+      "@.Date.Now()"
+    ],
+    "description": "Get current date/time"
+  },
+  "ISL Date Parse": {
+    "prefix": "dateparse",
+    "body": [
+      "${1:\\$dateString} | date.parse(\"${2:yyyy-MM-dd}\")"
+    ],
+    "description": "Parse date string"
+  },
+  "ISL Date Format": {
+    "prefix": "dateformat",
+    "body": [
+      "${1:\\$date} | to.string(\"${2:yyyy-MM-dd HH:mm:ss}\")"
+    ],
+    "description": "Format date"
+  },
+  "ISL Transform Object Keys": {
+    "prefix": "transformkeys",
+    "body": [
+      "foreach \\$key in ${1:\\$object} | keys",
+      "\t`\\${\\$key}`: ${1:\\$object}[\\$key]$0",
+      "endfor"
+    ],
+    "description": "Transform all keys of an object"
+  },
+  "ISL Safe Navigation": {
+    "prefix": "safe",
+    "body": [
+      "${1:\\$value} ?? ${2:defaultValue}"
+    ],
+    "description": "Null coalescing operator"
+  },
+  "ISL Array to Object": {
+    "prefix": "arrtoobj",
+    "body": [
+      "${1:\\$array} | map({",
+      "\t`\\${${2:\\$item.key}}`: ${3:\\$item.value}",
+      "})"
+    ],
+    "description": "Convert array to object"
+  },
+  "ISL Conditional Field": {
+    "prefix": "condfield",
+    "body": [
+      "if (${1:condition})",
+      "\t${2:fieldName}: ${3:value}",
+      "endif"
+    ],
+    "description": "Conditional object field"
+  },
+  "ISL Error Handling": {
+    "prefix": "errorhandle",
+    "body": [
+      "${1:\\$value} | default(${2:fallbackValue})"
+    ],
+    "description": "Provide default value on error"
+  },
+  "ISL Spread Object": {
+    "prefix": "spread",
+    "body": [
+      "{",
+      "\t...${1:\\$object},",
+      "\t${2:newField}: ${3:value}",
+      "}"
+    ],
+    "description": "Spread operator to merge objects"
+  },
+  "ISL Filter and Map": {
+    "prefix": "filtermap",
+    "body": [
+      "${1:\\$array}",
+      "\t| filter(${2:condition})",
+      "\t| map(${3:expression})"
+    ],
+    "description": "Filter then map array"
+  },
+  "ISL Reduce Sum": {
+    "prefix": "reducesum",
+    "body": [
+      "${1:\\$array} | reduce({{ \\$acc + \\$it }}, 0)"
+    ],
+    "description": "Reduce array to sum"
+  },
+  "ISL Template String": {
+    "prefix": "template",
+    "body": [
+      "`${${1:expression}}`"
+    ],
+    "description": "Template string with interpolation"
+  },
+  "ISL Multi-line String": {
+    "prefix": "multiline",
+    "body": [
+      "`${1:line1}",
+      "${2:line2}",
+      "${3:line3}`"
+    ],
+    "description": "Multi-line template string"
+  },
+  "ISL Nested Object": {
+    "prefix": "nested",
+    "body": [
+      "{",
+      "\t${1:field1}: {",
+      "\t\t${2:nested}: ${3:value}",
+      "\t}",
+      "}"
+    ],
+    "description": "Nested object structure"
+  },
+  "ISL Array Destructure": {
+    "prefix": "destruct",
+    "body": [
+      "\\$${1:first} = ${2:\\$array} | first;",
+      "\\$${3:last} = ${2:\\$array} | last;"
+    ],
+    "description": "Destructure array"
+  },
+  "ISL Chain Modifiers": {
+    "prefix": "chain",
+    "body": [
+      "${1:\\$value}",
+      "\t| ${2:modifier1}",
+      "\t| ${3:modifier2}",
+      "\t| ${4:modifier3}"
+    ],
+    "description": "Chain multiple modifiers"
+  },
+  "ISL Fallback Chain": {
+    "prefix": "fallback",
+    "body": [
+      "${1:\\$primary} ?? ${2:\\$secondary} ?? ${3:default}"
+    ],
+    "description": "Multiple fallback values"
+  },
+  "ISL Custom Object Key": {
+    "prefix": "dynamickey",
+    "body": [
+      "{",
+      "\t`\\${${1:expression}}`: ${2:value}",
+      "}"
+    ],
+    "description": "Object with dynamic key"
+  },
+  "ISL Validate and Transform": {
+    "prefix": "validate",
+    "body": [
+      "if (${1:\\$input.field} | isNotEmpty)",
+      "\t${2:result}: ${1:\\$input.field} | ${3:transform}",
+      "else",
+      "\t${2:result}: ${4:defaultValue}",
+      "endif"
+    ],
+    "description": "Validate before transforming"
+  },
+  "ISL Date Range": {
+    "prefix": "daterange",
+    "body": [
+      "\\$start = ${1:\\$date};",
+      "\\$end = ${1:\\$date} | date.add(${2:7}, \"${3:DAYS}\");"
+    ],
+    "description": "Create date range"
+  },
+  "ISL Group By": {
+    "prefix": "groupby",
+    "body": [
+      "foreach \\$item in ${1:\\$array}",
+      "\t\\$key = \\$item.${2:groupField};",
+      "\t\\$grouped[\\$key] = (\\$grouped[\\$key] ?? []) | push(\\$item);",
+      "endfor"
+    ],
+    "description": "Group array by field"
+  },
+  "ISL Batch Process": {
+    "prefix": "batch",
+    "body": [
+      "parallel foreach \\$item in ${1:\\$array}",
+      "\t@.This.${2:processFunction}(\\$item)",
+      "endfor"
+    ],
+    "description": "Parallel batch processing"
+  }
+}
+
diff --git a/plugin/src/codeactions.ts b/plugin/src/codeactions.ts
new file mode 100644
index 0000000..3b0013b
--- /dev/null
+++ b/plugin/src/codeactions.ts
@@ -0,0 +1,701 @@
+import * as vscode from 'vscode';
+
+export class IslCodeActionProvider implements vscode.CodeActionProvider {
+    
+    public static readonly providedCodeActionKinds = [
+        vscode.CodeActionKind.QuickFix,
+        vscode.CodeActionKind.Refactor,
+        vscode.CodeActionKind.RefactorExtract,
+        vscode.CodeActionKind.RefactorRewrite
+    ];
+    
+    provideCodeActions(
+        document: vscode.TextDocument,
+        range: vscode.Range | vscode.Selection,
+        context: vscode.CodeActionContext,
+        token: vscode.CancellationToken
+    ): vscode.CodeAction[] {
+        const actions: vscode.CodeAction[] = [];
+        
+        // Add quick fixes for diagnostics
+        for (const diagnostic of context.diagnostics) {
+            actions.push(...this.createQuickFixes(document, diagnostic));
+        }
+        
+        // Add refactoring actions when text is selected
+        if (!range.isEmpty) {
+            actions.push(...this.createRefactoringActions(document, range));
+        }
+        
+        // Add code improvements for current line
+        const line = document.lineAt(range.start.line);
+        actions.push(...this.createImprovementActions(document, line, range));
+        
+        return actions;
+    }
+    
+    private createQuickFixes(document: vscode.TextDocument, diagnostic: vscode.Diagnostic): vscode.CodeAction[] {
+        const actions: vscode.CodeAction[] = [];
+        const line = document.lineAt(diagnostic.range.start.line).text;
+        
+        // Fix typos in modifier names
+        if (diagnostic.message.includes('uppercase')) {
+            actions.push(this.createFix(
+                'Change to upperCase',
+                document,
+                diagnostic.range,
+                'upperCase',
+                diagnostic
+            ));
+        }
+        
+        if (diagnostic.message.includes('lowercase')) {
+            actions.push(this.createFix(
+                'Change to lowerCase',
+                document,
+                diagnostic.range,
+                'lowerCase',
+                diagnostic
+            ));
+        }
+        
+        // Suggest common typos
+        const typoSuggestions: { [key: string]: string } = {
+            'titlecase': 'titleCase',
+            'capitalize': 'capitalize',
+            'tostring': 'to.string',
+            'tonumber': 'to.number',
+            'todecimal': 'to.decimal',
+            'toboolean': 'to.boolean',
+            'dateparse': 'date.parse',
+            'dateadd': 'date.add',
+            'mathsum': 'Math.sum',
+            'mathavg': 'Math.average',
+            'mathmax': 'Math.max',
+            'mathmin': 'Math.min',
+        };
+        
+        const word = document.getText(diagnostic.range).toLowerCase();
+        if (typoSuggestions[word]) {
+            actions.push(this.createFix(
+                `Did you mean '${typoSuggestions[word]}'?`,
+                document,
+                diagnostic.range,
+                typoSuggestions[word],
+                diagnostic
+            ));
+        }
+        
+        // Fix missing return statement
+        if (diagnostic.message.includes('missing return')) {
+            const action = new vscode.CodeAction(
+                'Add return statement',
+                vscode.CodeActionKind.QuickFix
+            );
+            action.edit = new vscode.WorkspaceEdit();
+            const insertPosition = diagnostic.range.end;
+            action.edit.insert(document.uri, insertPosition, '\n    return {};\n');
+            action.diagnostics = [diagnostic];
+            action.isPreferred = true;
+            actions.push(action);
+        }
+        
+        // Fix unclosed braces
+        if (diagnostic.message.includes('unclosed') || diagnostic.message.includes('unbalanced')) {
+            const closingChar = diagnostic.message.includes('{') ? '}' : 
+                               diagnostic.message.includes('[') ? ']' : ')';
+            const action = new vscode.CodeAction(
+                `Add closing '${closingChar}'`,
+                vscode.CodeActionKind.QuickFix
+            );
+            action.edit = new vscode.WorkspaceEdit();
+            action.edit.insert(document.uri, diagnostic.range.end, closingChar);
+            action.diagnostics = [diagnostic];
+            action.isPreferred = true;
+            actions.push(action);
+        }
+
+        // Format long object declaration
+        if (diagnostic.code === 'format-object') {
+            const line = document.lineAt(diagnostic.range.start.line);
+            const action = new vscode.CodeAction(
+                'Format object on multiple lines',
+                vscode.CodeActionKind.QuickFix
+            );
+            action.command = {
+                command: 'isl.improvement.formatObject',
+                title: 'Format object on multiple lines',
+                arguments: [document, line.range]
+            };
+            action.diagnostics = [diagnostic];
+            action.isPreferred = true;
+            actions.push(action);
+        }
+
+        // Simplify string interpolation
+        if (diagnostic.code === 'simplify-interpolation') {
+            const text = document.getText(diagnostic.range);
+            // Extract the variable from ${$variable}
+            const match = text.match(/\$\{(\$[a-zA-Z_][a-zA-Z0-9_]*)\}/);
+            if (match) {
+                const variable = match[1];
+                const action = new vscode.CodeAction(
+                    `Simplify to ${variable}`,
+                    vscode.CodeActionKind.QuickFix
+                );
+                action.edit = new vscode.WorkspaceEdit();
+                action.edit.replace(document.uri, diagnostic.range, variable);
+                action.diagnostics = [diagnostic];
+                action.isPreferred = true;
+                actions.push(action);
+            }
+        }
+
+        // Use coalesce operator
+        if (diagnostic.code === 'use-coalesce-operator') {
+            const line = document.lineAt(diagnostic.range.start.line);
+            const action = new vscode.CodeAction(
+                'Use ?? operator instead',
+                vscode.CodeActionKind.QuickFix
+            );
+            action.command = {
+                command: 'isl.improvement.useCoalesceOperator',
+                title: 'Use ?? operator',
+                arguments: [document, line.range]
+            };
+            action.diagnostics = [diagnostic];
+            action.isPreferred = true;
+            actions.push(action);
+        }
+
+        // Use = instead of : for variable assignment
+        if (diagnostic.code === 'use-equals-assignment') {
+            // Single fix
+            const action = new vscode.CodeAction(
+                'Change : to =',
+                vscode.CodeActionKind.QuickFix
+            );
+            action.edit = new vscode.WorkspaceEdit();
+            action.edit.replace(document.uri, diagnostic.range, '=');
+            action.diagnostics = [diagnostic];
+            action.isPreferred = true;
+            actions.push(action);
+
+            // Fix all in file
+            const fixAllAction = new vscode.CodeAction(
+                'Change all : to = in file',
+                vscode.CodeActionKind.QuickFix
+            );
+            fixAllAction.edit = this.createFixAllColonAssignments(document);
+            fixAllAction.diagnostics = [diagnostic];
+            actions.push(fixAllAction);
+        }
+        
+        return actions;
+    }
+    
+    private createRefactoringActions(document: vscode.TextDocument, range: vscode.Range): vscode.CodeAction[] {
+        const actions: vscode.CodeAction[] = [];
+        const selectedText = document.getText(range);
+        
+        // Extract to variable
+        if (this.canExtractToVariable(selectedText)) {
+            const action = new vscode.CodeAction(
+                'Extract to variable',
+                vscode.CodeActionKind.RefactorExtract
+            );
+            action.command = {
+                command: 'isl.refactor.extractVariable',
+                title: 'Extract to variable',
+                arguments: [document, range]
+            };
+            actions.push(action);
+        }
+        
+        // Extract to function
+        if (this.canExtractToFunction(selectedText, document, range)) {
+            const action = new vscode.CodeAction(
+                'Extract to function',
+                vscode.CodeActionKind.RefactorExtract
+            );
+            action.command = {
+                command: 'isl.refactor.extractFunction',
+                title: 'Extract to function',
+                arguments: [document, range]
+            };
+            actions.push(action);
+        }
+        
+        // Convert to template string
+        if (selectedText.match(/\$\w+(\.\w+)*\s*\+\s*["']/)) {
+            const action = new vscode.CodeAction(
+                'Convert to template string',
+                vscode.CodeActionKind.RefactorRewrite
+            );
+            action.command = {
+                command: 'isl.refactor.toTemplateString',
+                title: 'Convert to template string',
+                arguments: [document, range]
+            };
+            actions.push(action);
+        }
+        
+        return actions;
+    }
+    
+    private createImprovementActions(document: vscode.TextDocument, line: vscode.TextLine, range: vscode.Range): vscode.CodeAction[] {
+        const actions: vscode.CodeAction[] = [];
+        const lineText = line.text;
+        
+        // Suggest simplifying string interpolation for simple variables
+        const unnecessaryInterpolation = /\$\{(\$[a-zA-Z_][a-zA-Z0-9_]*)\}/g;
+        let match;
+        while ((match = unnecessaryInterpolation.exec(lineText)) !== null) {
+            const fullMatch = match[0]; // ${$variable}
+            const variable = match[1];  // $variable
+            
+            // Only suggest if it's a simple variable (no dots)
+            if (!variable.includes('.')) {
+                const startPos = line.range.start.character + match.index;
+                const endPos = startPos + fullMatch.length;
+                const replaceRange = new vscode.Range(
+                    line.lineNumber,
+                    startPos,
+                    line.lineNumber,
+                    endPos
+                );
+                
+                const action = new vscode.CodeAction(
+                    `Simplify to ${variable} (remove unnecessary braces)`,
+                    vscode.CodeActionKind.RefactorRewrite
+                );
+                action.edit = new vscode.WorkspaceEdit();
+                action.edit.replace(document.uri, replaceRange, variable);
+                action.isPreferred = true;
+                actions.push(action);
+            }
+        }
+        
+        // Suggest using ?? instead of | default()
+        if (lineText.match(/\|\s*default\s*\(/)) {
+            const action = new vscode.CodeAction(
+                'Use ?? operator instead of default()',
+                vscode.CodeActionKind.QuickFix
+            );
+            action.command = {
+                command: 'isl.improvement.useCoalesceOperator',
+                title: 'Use ?? operator',
+                arguments: [document, line.range]
+            };
+            actions.push(action);
+        }
+        
+        // Suggest simplifying nested ifs
+        if (lineText.match(/^\s*if\s*\(/) && this.hasNestedIf(document, line.lineNumber)) {
+            const action = new vscode.CodeAction(
+                'Simplify nested conditions',
+                vscode.CodeActionKind.RefactorRewrite
+            );
+            action.command = {
+                command: 'isl.improvement.simplifyNestedIfs',
+                title: 'Simplify conditions',
+                arguments: [document, line.lineNumber]
+            };
+            actions.push(action);
+        }
+        
+        // Suggest using Math.sum instead of reduce
+        if (lineText.match(/\|\s*reduce\s*\(\s*\{\{\s*\$acc\s*\+\s*\$it\s*\}\}/)) {
+            const action = new vscode.CodeAction(
+                'Use Math.sum() instead of reduce',
+                vscode.CodeActionKind.QuickFix
+            );
+            action.command = {
+                command: 'isl.improvement.useMathSum',
+                title: 'Use Math.sum()',
+                arguments: [document, line.range]
+            };
+            action.isPreferred = true;
+            actions.push(action);
+        }
+        
+        // Suggest formatting long modifier chains
+        if (this.hasLongModifierChain(lineText)) {
+            const action = new vscode.CodeAction(
+                'Format modifier chain on multiple lines',
+                vscode.CodeActionKind.RefactorRewrite
+            );
+            action.command = {
+                command: 'isl.improvement.formatChain',
+                title: 'Format chain',
+                arguments: [document, line.range]
+            };
+            actions.push(action);
+        }
+        
+        // Suggest formatting long object declarations
+        if (this.hasLongObjectDeclaration(lineText)) {
+            const action = new vscode.CodeAction(
+                'Format object on multiple lines',
+                vscode.CodeActionKind.RefactorRewrite
+            );
+            action.command = {
+                command: 'isl.improvement.formatObject',
+                title: 'Format object',
+                arguments: [document, line.range]
+            };
+            actions.push(action);
+        }
+        
+        return actions;
+    }
+    
+    private createFix(
+        title: string,
+        document: vscode.TextDocument,
+        range: vscode.Range,
+        replacement: string,
+        diagnostic: vscode.Diagnostic
+    ): vscode.CodeAction {
+        const action = new vscode.CodeAction(title, vscode.CodeActionKind.QuickFix);
+        action.edit = new vscode.WorkspaceEdit();
+        action.edit.replace(document.uri, range, replacement);
+        action.diagnostics = [diagnostic];
+        action.isPreferred = true;
+        return action;
+    }
+    
+    private canExtractToVariable(text: string): boolean {
+        // Can extract expressions, not simple variables
+        return text.trim().length > 2 && 
+               !text.match(/^\$\w+$/) && 
+               (text.includes('|') || text.includes('{{') || text.includes('@.'));
+    }
+    
+    private canExtractToFunction(text: string, document: vscode.TextDocument, range: vscode.Range): boolean {
+        // Can extract multi-line blocks or complex expressions
+        const lines = text.split('\n');
+        return lines.length > 1 || this.canExtractToVariable(text);
+    }
+    
+    private hasNestedIf(document: vscode.TextDocument, lineNumber: number): boolean {
+        // Check if there's a nested if within the next few lines
+        for (let i = lineNumber + 1; i < Math.min(lineNumber + 10, document.lineCount); i++) {
+            const line = document.lineAt(i).text.trim();
+            if (line.startsWith('if (')) {
+                return true;
+            }
+            if (line.startsWith('endif')) {
+                return false;
+            }
+        }
+        return false;
+    }
+    
+    private hasLongModifierChain(line: string): boolean {
+        // Check if line has 3+ modifiers or is longer than 100 chars with modifiers
+        const pipeCount = (line.match(/\|/g) || []).length;
+        return pipeCount >= 3 || (pipeCount >= 2 && line.length > 100);
+    }
+    
+    private hasLongObjectDeclaration(line: string): boolean {
+        // Check if line has an object declaration that's too long
+        // Look for { ... } pattern with multiple properties
+        if (line.length < 100) {
+            return false;
+        }
+        
+        // Check if line contains object with multiple properties
+        const objectMatch = line.match(/\{[^}]+:[^}]+:[^}]+\}/);
+        return objectMatch !== null;
+    }
+
+    private createFixAllColonAssignments(document: vscode.TextDocument): vscode.WorkspaceEdit {
+        const edit = new vscode.WorkspaceEdit();
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            
+            // Skip comments
+            const commentIndex = Math.min(
+                line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+                line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+            );
+            const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+            // Check for variable assignment using : instead of =
+            // Match: $varName: (at the start of line, optionally with whitespace)
+            const colonAssignmentPattern = /^(\s*)(\$[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)(\s*)(:)/;
+            const match = codeOnlyLine.match(colonAssignmentPattern);
+
+            if (match) {
+                const colonPos = match[1].length + match[2].length + match[3].length;
+                const range = new vscode.Range(i, colonPos, i, colonPos + 1);
+                edit.replace(document.uri, range, '=');
+            }
+        }
+
+        return edit;
+    }
+}
+
+// Refactoring command implementations
+export async function extractVariable(document: vscode.TextDocument, range: vscode.Range) {
+    const selectedText = document.getText(range);
+    
+    const varName = await vscode.window.showInputBox({
+        prompt: 'Enter variable name',
+        value: 'extracted',
+        validateInput: (text) => {
+            if (!text.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) {
+                return 'Invalid variable name';
+            }
+            return null;
+        }
+    });
+    
+    if (!varName) {
+        return;
+    }
+    
+    const edit = new vscode.WorkspaceEdit();
+    
+    // Find the start of the statement/line to insert before it
+    const line = document.lineAt(range.start.line);
+    const indent = line.text.match(/^\s*/)?.[0] || '';
+    const insertPosition = new vscode.Position(range.start.line, 0);
+    
+    // Insert variable declaration
+    edit.insert(document.uri, insertPosition, `${indent}$${varName} = ${selectedText.trim()};\n`);
+    
+    // Replace selected text with variable reference
+    edit.replace(document.uri, range, `$${varName}`);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+export async function extractFunction(document: vscode.TextDocument, range: vscode.Range) {
+    const selectedText = document.getText(range);
+    
+    const funcName = await vscode.window.showInputBox({
+        prompt: 'Enter function name',
+        value: 'extracted',
+        validateInput: (text) => {
+            if (!text.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/)) {
+                return 'Invalid function name';
+            }
+            return null;
+        }
+    });
+    
+    if (!funcName) {
+        return;
+    }
+    
+    // Find variables used in selection
+    const variables = findVariablesInText(selectedText);
+    const params = variables.join(', ');
+    
+    const edit = new vscode.WorkspaceEdit();
+    
+    // Insert function at the top of the file
+    const funcDeclaration = `fun ${funcName}(${params}) {\n    return ${selectedText.trim()};\n}\n\n`;
+    edit.insert(document.uri, new vscode.Position(0, 0), funcDeclaration);
+    
+    // Replace selected text with function call
+    const args = variables.join(', ');
+    edit.replace(document.uri, range, `@.This.${funcName}(${args})`);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+export async function convertToTemplateString(document: vscode.TextDocument, range: vscode.Range) {
+    const selectedText = document.getText(range);
+    
+    // Convert string concatenation to template string
+    const converted = selectedText
+        .replace(/\$(\w+(?:\.\w+)*)\s*\+\s*["']([^"']*)["']/g, '`${$$$1}$2`')
+        .replace(/["']([^"']*)["']\s*\+\s*\$(\w+(?:\.\w+)*)/g, '`$1${$$$2}`')
+        .replace(/\$(\w+(?:\.\w+)*)/g, '${$$$1}');
+    
+    const edit = new vscode.WorkspaceEdit();
+    edit.replace(document.uri, range, converted);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+export async function useCoalesceOperator(document: vscode.TextDocument, range: vscode.Range) {
+    const lineText = document.getText(range);
+    
+    // Convert | default(value) to ?? value
+    const converted = lineText.replace(/\|\s*default\s*\(\s*([^)]+)\s*\)/g, '?? $1');
+    
+    const edit = new vscode.WorkspaceEdit();
+    edit.replace(document.uri, range, converted);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+export async function useMathSum(document: vscode.TextDocument, range: vscode.Range) {
+    const lineText = document.getText(range);
+    
+    // Convert reduce({{ $acc + $it }}, 0) to Math.sum(0)
+    const converted = lineText.replace(/\|\s*reduce\s*\(\s*\{\{\s*\$acc\s*\+\s*\$it\s*\}\}\s*,\s*(\d+)\s*\)/g, '| Math.sum($1)');
+    
+    const edit = new vscode.WorkspaceEdit();
+    edit.replace(document.uri, range, converted);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+export async function formatChain(document: vscode.TextDocument, range: vscode.Range) {
+    const lineText = document.getText(range);
+    
+    // Split long chains into multiple lines
+    const indent = lineText.match(/^\s*/)?.[0] || '';
+    const parts = lineText.split('|').map(p => p.trim()).filter(p => p);
+    
+    if (parts.length === 0) {
+        return;
+    }
+    
+    const firstPart = parts[0];
+    const modifiers = parts.slice(1);
+    
+    const formatted = `${indent}${firstPart}\n${modifiers.map(m => `${indent}    | ${m}`).join('\n')}`;
+    
+    const edit = new vscode.WorkspaceEdit();
+    edit.replace(document.uri, range, formatted);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+export async function formatObject(document: vscode.TextDocument, range: vscode.Range) {
+    const lineText = document.getText(range);
+    
+    // Find the opening brace
+    const openBraceMatch = lineText.match(/^(\s*)(.*?)(\{)/);
+    if (!openBraceMatch) {
+        return;
+    }
+    
+    const indent = openBraceMatch[1];
+    const beforeBrace = openBraceMatch[2];
+    
+    // Find matching closing brace (accounting for strings and nesting)
+    let depth = 0;
+    let inString = false;
+    let stringChar = '';
+    let objectStart = -1;
+    let objectEnd = -1;
+    
+    for (let i = 0; i < lineText.length; i++) {
+        const char = lineText[i];
+        const prevChar = i > 0 ? lineText[i - 1] : '';
+        
+        // Track string boundaries
+        if ((char === '"' || char === "'" || char === '`') && prevChar !== '\\') {
+            if (!inString) {
+                inString = true;
+                stringChar = char;
+            } else if (char === stringChar) {
+                inString = false;
+            }
+        }
+        
+        // Track braces outside of strings
+        if (!inString) {
+            if (char === '{') {
+                if (depth === 0) {
+                    objectStart = i;
+                }
+                depth++;
+            } else if (char === '}') {
+                depth--;
+                if (depth === 0) {
+                    objectEnd = i;
+                    break;
+                }
+            }
+        }
+    }
+    
+    if (objectStart === -1 || objectEnd === -1) {
+        return;
+    }
+    
+    const objectContent = lineText.substring(objectStart + 1, objectEnd);
+    const afterBrace = lineText.substring(objectEnd + 1);
+    
+    // Parse properties - reset tracking variables
+    const properties: string[] = [];
+    let currentProp = '';
+    depth = 0;
+    inString = false;
+    stringChar = '';
+    
+    for (let i = 0; i < objectContent.length; i++) {
+        const char = objectContent[i];
+        const prevChar = i > 0 ? objectContent[i - 1] : '';
+        
+        // Track string boundaries
+        if ((char === '"' || char === "'" || char === '`') && prevChar !== '\\') {
+            if (!inString) {
+                inString = true;
+                stringChar = char;
+            } else if (char === stringChar) {
+                inString = false;
+            }
+        }
+        
+        // Track nested braces/brackets
+        if (!inString) {
+            if (char === '{' || char === '[' || char === '(') {
+                depth++;
+            } else if (char === '}' || char === ']' || char === ')') {
+                depth--;
+            }
+        }
+        
+        // Split on comma at depth 0
+        if (char === ',' && depth === 0 && !inString) {
+            properties.push(currentProp.trim());
+            currentProp = '';
+        } else {
+            currentProp += char;
+        }
+    }
+    
+    // Add the last property
+    if (currentProp.trim()) {
+        properties.push(currentProp.trim());
+    }
+    
+    // Format as multi-line object
+    const formattedProperties = properties
+        .map(prop => `${indent}    ${prop}`)
+        .join(',\n');
+    
+    const formatted = `${indent}${beforeBrace}{\n${formattedProperties}\n${indent}}${afterBrace}`;
+    
+    const edit = new vscode.WorkspaceEdit();
+    edit.replace(document.uri, range, formatted);
+    
+    await vscode.workspace.applyEdit(edit);
+}
+
+function findVariablesInText(text: string): string[] {
+    const variables = new Set();
+    const varPattern = /\$([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)/g;
+    let match;
+    
+    while ((match = varPattern.exec(text)) !== null) {
+        variables.add('$' + match[1]);
+    }
+    
+    return Array.from(variables);
+}
+
+
diff --git a/plugin/src/codelens.ts b/plugin/src/codelens.ts
new file mode 100644
index 0000000..ad5ec49
--- /dev/null
+++ b/plugin/src/codelens.ts
@@ -0,0 +1,337 @@
+import * as vscode from 'vscode';
+import * as path from 'path';
+import * as fs from 'fs';
+
+export class IslCodeLensProvider implements vscode.CodeLensProvider {
+    private _onDidChangeCodeLenses: vscode.EventEmitter = new vscode.EventEmitter();
+    public readonly onDidChangeCodeLenses: vscode.Event = this._onDidChangeCodeLenses.event;
+
+    constructor() {}
+
+    public provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken): vscode.CodeLens[] | Thenable {
+        const codeLenses: vscode.CodeLens[] = [];
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        // Find all function declarations
+        const functionPattern = /^\s*(fun|modifier)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/;
+        const functions: { name: string, type: string, line: number, params: string }[] = [];
+
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            const match = line.match(functionPattern);
+
+            if (match) {
+                const funcType = match[1]; // 'fun' or 'modifier'
+                const funcName = match[2];
+                const params = match[3].trim();
+
+                functions.push({ name: funcName, type: funcType, line: i, params });
+            }
+        }
+
+        // Add CodeLens for each function
+        for (const func of functions) {
+            const range = new vscode.Range(func.line, 0, func.line, lines[func.line].length);
+            
+            // Count usages
+            const usageCount = this.countUsages(text, func.name, func.type);
+            
+            // Add "Run" button
+            const runCommand: vscode.Command = {
+                title: `▶ Run`,
+                command: 'isl.runFunction',
+                arguments: [document.uri, func.name, func.params]
+            };
+            codeLenses.push(new vscode.CodeLens(range, runCommand));
+            
+            // Add usage count
+            if (usageCount > 0) {
+                const usageCommand: vscode.Command = {
+                    title: `📊 ${usageCount} ${usageCount === 1 ? 'usage' : 'usages'}`,
+                    command: 'isl.showUsages',
+                    arguments: [document.uri, func.name, func.type]
+                };
+                codeLenses.push(new vscode.CodeLens(range, usageCommand));
+            } else if (func.name !== 'run') {
+                // Show "No usages" for functions other than 'run'
+                const noUsageCommand: vscode.Command = {
+                    title: `⚠️ No usages found`,
+                    command: '',
+                    tooltip: 'This function is not being called anywhere'
+                };
+                codeLenses.push(new vscode.CodeLens(range, noUsageCommand));
+            }
+            
+            // Add test button if not a run function
+            if (func.name !== 'run') {
+                const testCommand: vscode.Command = {
+                    title: `🧪 Test`,
+                    command: 'isl.testFunction',
+                    arguments: [document.uri, func.name, func.params],
+                    tooltip: `Test ${func.name} with sample data`
+                };
+                codeLenses.push(new vscode.CodeLens(range, testCommand));
+            }
+        }
+
+        return codeLenses;
+    }
+    
+    private countUsages(text: string, functionName: string, functionType: string): number {
+        let count = 0;
+        
+        if (functionType === 'fun') {
+            // Count @.This.functionName() calls
+            const functionCallPattern = new RegExp(`@\\.This\\.${functionName}\\s*\\(`, 'g');
+            const matches = text.match(functionCallPattern);
+            count += matches ? matches.length : 0;
+        } else if (functionType === 'modifier') {
+            // Count | functionName usages
+            const modifierPattern = new RegExp(`\\|\\s*${functionName}(?:\\s*\\(|\\s|$)`, 'g');
+            const matches = text.match(modifierPattern);
+            count += matches ? matches.length : 0;
+        }
+        
+        return count;
+    }
+
+    public resolveCodeLens(codeLens: vscode.CodeLens, token: vscode.CancellationToken): vscode.CodeLens | Thenable {
+        return codeLens;
+    }
+
+    public refresh(): void {
+        this._onDidChangeCodeLenses.fire();
+    }
+}
+
+export async function runIslFunction(uri: vscode.Uri, functionName: string, params: string, context: vscode.ExtensionContext) {
+    const document = await vscode.workspace.openTextDocument(uri);
+    const filePath = uri.fsPath;
+
+    // Parse parameters to create input JSON
+    const paramList = params
+        .split(',')
+        .map(p => p.trim())
+        .filter(p => p.length > 0)
+        .map(p => {
+            // Extract parameter name (remove type annotations if present)
+            const paramName = p.split(':')[0].trim().replace('$', '');
+            return paramName;
+        });
+
+    // Create input JSON based on parameters
+    let inputJson = '{}';
+    if (paramList.length > 0) {
+        // Prompt user for input values
+        const userInput = await vscode.window.showInputBox({
+            prompt: `Enter input JSON for ${functionName}(${params})`,
+            placeHolder: createSampleInput(paramList),
+            value: createSampleInput(paramList),
+            ignoreFocusOut: true
+        });
+
+        if (userInput === undefined) {
+            return; // User cancelled
+        }
+
+        inputJson = userInput;
+    }
+
+    // Save document if dirty
+    if (document.isDirty) {
+        await document.save();
+    }
+
+    // Find Java
+    const javaPath = await findJava();
+    if (!javaPath) {
+        vscode.window.showErrorMessage(
+            'Java not found. Please install Java 11+ or configure isl.execution.javaHome',
+            'Open Settings'
+        ).then(selection => {
+            if (selection === 'Open Settings') {
+                vscode.commands.executeCommand('workbench.action.openSettings', 'isl.execution.javaHome');
+            }
+        });
+        return;
+    }
+
+    // Get embedded JAR path
+    const jarPath = path.join(context.extensionPath, 'lib', 'isl-cmd-all.jar');
+    
+    if (!fs.existsSync(jarPath)) {
+        vscode.window.showErrorMessage(
+            'ISL runtime not found in extension. The extension may be corrupted. Please reinstall.'
+        );
+        return;
+    }
+
+    // Create terminal
+    const isWindows = process.platform === 'win32';
+    const shellPath = isWindows ? 'powershell.exe' : undefined;
+    
+    const terminal = vscode.window.createTerminal({
+        name: `ISL: ${functionName}`,
+        cwd: path.dirname(filePath),
+        shellPath: shellPath
+    });
+
+    terminal.show();
+
+    // Write input to temporary file
+    const tempDir = path.join(path.dirname(filePath), '.isl-temp');
+    if (!fs.existsSync(tempDir)) {
+        fs.mkdirSync(tempDir, { recursive: true });
+    }
+
+    const tempInputFile = path.join(tempDir, `input-${functionName}.json`);
+    fs.writeFileSync(tempInputFile, inputJson);
+
+    // Build command
+    let command: string;
+
+    if (isWindows) {
+        // PowerShell command
+        const javaCmd = escapeForPowerShell(javaPath);
+        const jarFile = escapeForPowerShell(jarPath);
+        const islFile = escapeForPowerShell(filePath);
+        const inputFile = escapeForPowerShell(tempInputFile);
+        
+        command = `& "${javaCmd}" -jar "${jarFile}" transform "${islFile}" -i "${inputFile}" --function ${functionName} --pretty`;
+    } else {
+        // Unix/Mac command
+        const javaCmd = escapeForBash(javaPath);
+        const jarFile = escapeForBash(jarPath);
+        const islFile = escapeForBash(filePath);
+        const inputFile = escapeForBash(tempInputFile);
+        
+        command = `"${javaCmd}" -jar "${jarFile}" transform "${islFile}" -i "${inputFile}" --function ${functionName} --pretty`;
+    }
+
+    terminal.sendText(command);
+
+    // Show notification
+    vscode.window.showInformationMessage(`Running ${functionName}...`);
+
+    // Clean up temp file after a delay
+    setTimeout(() => {
+        try {
+            if (fs.existsSync(tempInputFile)) {
+                fs.unlinkSync(tempInputFile);
+            }
+        } catch (e) {
+            // Ignore cleanup errors
+        }
+    }, 10000);
+}
+
+async function findJava(): Promise {
+    // Check configured JAVA_HOME
+    const config = vscode.workspace.getConfiguration('isl.execution');
+    const configuredJavaHome = config.get('javaHome');
+    
+    if (configuredJavaHome) {
+        const javaPath = path.join(configuredJavaHome, 'bin', process.platform === 'win32' ? 'java.exe' : 'java');
+        if (fs.existsSync(javaPath)) {
+            return javaPath;
+        }
+    }
+
+    // Check JAVA_HOME environment variable
+    const javaHome = process.env.JAVA_HOME;
+    if (javaHome) {
+        const javaPath = path.join(javaHome, 'bin', process.platform === 'win32' ? 'java.exe' : 'java');
+        if (fs.existsSync(javaPath)) {
+            return javaPath;
+        }
+    }
+
+    // Try java in PATH
+    return process.platform === 'win32' ? 'java.exe' : 'java';
+}
+
+function escapeForPowerShell(filepath: string): string {
+    // For PowerShell, escape single quotes
+    return filepath.replace(/'/g, "''");
+}
+
+function escapeForBash(filepath: string): string {
+    // For bash, escape special characters
+    return filepath.replace(/(["\s'$`\\])/g, '\\$1');
+}
+
+function createSampleInput(paramNames: string[]): string {
+    if (paramNames.length === 0) {
+        return '{}';
+    }
+
+    const inputObj: any = {};
+    for (const param of paramNames) {
+        // Create sample values based on parameter names
+        const paramLower = param.toLowerCase();
+        if (paramLower.includes('id')) {
+            inputObj[param] = 123;
+        } else if (paramLower.includes('name')) {
+            inputObj[param] = 'Sample Name';
+        } else if (paramLower.includes('email')) {
+            inputObj[param] = 'user@example.com';
+        } else if (paramLower.includes('price') || paramLower.includes('amount')) {
+            inputObj[param] = 99.99;
+        } else if (paramLower.includes('count') || paramLower.includes('quantity')) {
+            inputObj[param] = 1;
+        } else if (paramLower.includes('active') || paramLower.includes('enabled')) {
+            inputObj[param] = true;
+        } else if (paramLower.includes('date')) {
+            inputObj[param] = '2024-01-15';
+        } else if (paramLower.includes('items') || paramLower.includes('list') || paramLower.includes('array')) {
+            inputObj[param] = [];
+        } else if (paramLower.includes('input') || paramLower.includes('data')) {
+            inputObj[param] = { value: 'example' };
+        } else {
+            inputObj[param] = 'value';
+        }
+    }
+
+    return JSON.stringify(inputObj, null, 2);
+}
+
+export async function showUsages(uri: vscode.Uri, functionName: string, functionType: string) {
+    const document = await vscode.workspace.openTextDocument(uri);
+    const text = document.getText();
+    const locations: vscode.Location[] = [];
+    
+    const lines = text.split('\n');
+    
+    for (let i = 0; i < lines.length; i++) {
+        const line = lines[i];
+        let match;
+        
+        if (functionType === 'fun') {
+            const pattern = new RegExp(`@\\.This\\.${functionName}\\s*\\(`, 'g');
+            while ((match = pattern.exec(line)) !== null) {
+                const startPos = new vscode.Position(i, match.index);
+                const endPos = new vscode.Position(i, match.index + match[0].length);
+                locations.push(new vscode.Location(uri, new vscode.Range(startPos, endPos)));
+            }
+        } else if (functionType === 'modifier') {
+            const pattern = new RegExp(`\\|\\s*${functionName}(?:\\s*\\(|\\s|$)`, 'g');
+            while ((match = pattern.exec(line)) !== null) {
+                const startPos = new vscode.Position(i, match.index);
+                const endPos = new vscode.Position(i, match.index + match[0].length);
+                locations.push(new vscode.Location(uri, new vscode.Range(startPos, endPos)));
+            }
+        }
+    }
+    
+    if (locations.length > 0) {
+        vscode.commands.executeCommand('editor.action.showReferences', uri, locations[0].range.start, locations);
+    } else {
+        vscode.window.showInformationMessage(`No usages found for ${functionName}`);
+    }
+}
+
+export async function testFunction(uri: vscode.Uri, functionName: string, params: string, context: vscode.ExtensionContext) {
+    // Same as runFunction but with test data
+    await runIslFunction(uri, functionName, params, context);
+}
diff --git a/plugin/src/completion.ts b/plugin/src/completion.ts
new file mode 100644
index 0000000..ecc59d6
--- /dev/null
+++ b/plugin/src/completion.ts
@@ -0,0 +1,686 @@
+import * as vscode from 'vscode';
+import { IslExtensionsManager, IslFunctionDefinition, IslModifierDefinition } from './extensions';
+
+export class IslCompletionProvider implements vscode.CompletionItemProvider {
+    
+    constructor(private extensionsManager: IslExtensionsManager) {}
+    
+    async provideCompletionItems(
+        document: vscode.TextDocument,
+        position: vscode.Position,
+        token: vscode.CancellationToken,
+        context: vscode.CompletionContext
+    ): Promise {
+        const linePrefix = document.lineAt(position).text.substr(0, position.character);
+        
+        // Load custom extensions
+        const extensions = await this.extensionsManager.getExtensionsForDocument(document);
+        
+        // Check for pagination cursor property access: $cursor.
+        const paginationPropertyMatch = linePrefix.match(/\$([a-zA-Z_][a-zA-Z0-9_]*)\.(\w*)$/);
+        if (paginationPropertyMatch) {
+            const varName = paginationPropertyMatch[1];
+            const paginationType = this.getPaginationType(document, varName);
+            if (paginationType) {
+                return this.getPaginationPropertyCompletions(paginationType);
+            }
+        }
+        
+        // Check for @.This. - show functions from current file + custom extensions
+        if (linePrefix.match(/@\.This\.[\w]*$/)) {
+            return this.getFunctionsFromDocument(document, extensions);
+        }
+        // Provide different completions based on context
+        else if (linePrefix.endsWith('@.')) {
+            return this.getServiceCompletions();
+        } else if (linePrefix.match(/\|\s*[\w.]*$/)) {
+            return this.getModifierCompletions(extensions);
+        } else if (linePrefix.match(/\$\w*$/)) {
+            return this.getVariableCompletions(document);
+        } else {
+            return this.getKeywordCompletions();
+        }
+    }
+
+    private getFunctionsFromDocument(document: vscode.TextDocument, extensions: import('./extensions').IslExtensions): vscode.CompletionItem[] {
+        const functions: vscode.CompletionItem[] = [];
+        const text = document.getText();
+        const lines = text.split('\n');
+        
+        // Find all function and modifier declarations
+        const functionPattern = /^\s*(fun|modifier)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/;
+        
+        for (let i = 0; i < lines.length; i++) {
+            const match = lines[i].match(functionPattern);
+            if (match) {
+                const funcType = match[1]; // 'fun' or 'modifier'
+                const funcName = match[2];
+                const params = match[3].trim();
+                
+                const item = new vscode.CompletionItem(funcName, vscode.CompletionItemKind.Function);
+                item.detail = `${funcType} ${funcName}(${params})`;
+                
+                // Extract parameter names for snippet
+                const paramNames = params
+                    .split(',')
+                    .map(p => p.trim())
+                    .filter(p => p.length > 0)
+                    .map((p, idx) => {
+                        // Extract just the parameter name (remove type annotations if present)
+                        const paramName = p.split(':')[0].trim();
+                        return `\${${idx + 1}:${paramName}}`;
+                    });
+                
+                // Create snippet with parameters
+                if (paramNames.length > 0) {
+                    item.insertText = new vscode.SnippetString(`${funcName}(${paramNames.join(', ')})`);
+                } else {
+                    item.insertText = new vscode.SnippetString(`${funcName}()`);
+                }
+                
+                // Add documentation from comments above function
+                const docs = this.getDocumentationForFunction(lines, i);
+                if (docs) {
+                    item.documentation = new vscode.MarkdownString(docs);
+                }
+                
+                functions.push(item);
+            }
+        }
+        
+        // Add custom functions from extensions
+        for (const [name, funcDef] of extensions.functions) {
+            const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Function);
+            item.detail = this.formatFunctionSignature(funcDef);
+            
+            // Create snippet with parameters
+            const paramSnippets = funcDef.parameters.map((param, idx) => {
+                return `\${${idx + 1}:${param.name}}`;
+            });
+            
+            if (paramSnippets.length > 0) {
+                item.insertText = new vscode.SnippetString(`${name}(${paramSnippets.join(', ')})`);
+            } else {
+                item.insertText = new vscode.SnippetString(`${name}()`);
+            }
+            
+            // Add documentation
+            item.documentation = this.formatFunctionDocumentation(funcDef);
+            
+            // Mark as custom extension
+            item.tags = [vscode.CompletionItemTag.Deprecated]; // Using this as a visual indicator
+            
+            functions.push(item);
+        }
+        
+        return functions;
+    }
+
+    private formatFunctionSignature(func: IslFunctionDefinition): string {
+        const params = func.parameters.map(p => {
+            let result = `${p.name}`;
+            if (p.type) {
+                result += `: ${p.type}`;
+            }
+            if (p.optional) {
+                result += '?';
+            }
+            return result;
+        }).join(', ');
+        
+        return `function ${func.name}(${params})${func.returns?.type ? ': ' + func.returns.type : ''} (custom)`;
+    }
+
+    private formatFunctionDocumentation(func: IslFunctionDefinition): vscode.MarkdownString {
+        const md = new vscode.MarkdownString();
+        md.isTrusted = true;
+        
+        if (func.description) {
+            md.appendMarkdown(`${func.description}\n\n`);
+        }
+        
+        if (func.parameters.length > 0) {
+            md.appendMarkdown('**Parameters:**\n');
+            for (const param of func.parameters) {
+                const optional = param.optional ? ' (optional)' : '';
+                const type = param.type ? `: ${param.type}` : '';
+                const desc = param.description ? ` - ${param.description}` : '';
+                md.appendMarkdown(`- \`${param.name}${type}\`${optional}${desc}\n`);
+            }
+            md.appendMarkdown('\n');
+        }
+        
+        if (func.returns) {
+            md.appendMarkdown('**Returns:**');
+            if (func.returns.type) {
+                md.appendMarkdown(` \`${func.returns.type}\``);
+            }
+            if (func.returns.description) {
+                md.appendMarkdown(` - ${func.returns.description}`);
+            }
+            md.appendMarkdown('\n\n');
+        }
+        
+        if (func.examples && func.examples.length > 0) {
+            md.appendMarkdown('**Examples:**\n');
+            for (const example of func.examples) {
+                md.appendMarkdown('```isl\n' + example + '\n```\n');
+            }
+        }
+        
+        md.appendMarkdown('\n*Custom function from .islextensions*');
+        
+        return md;
+    }
+
+    private getDocumentationForFunction(lines: string[], functionLineIndex: number): string | undefined {
+        // Look for comments immediately above the function
+        const docs: string[] = [];
+        for (let i = functionLineIndex - 1; i >= 0; i--) {
+            const line = lines[i].trim();
+            if (line.startsWith('//')) {
+                docs.unshift(line.substring(2).trim());
+            } else if (line.startsWith('#')) {
+                docs.unshift(line.substring(1).trim());
+            } else if (line === '') {
+                // Allow blank lines
+                continue;
+            } else {
+                // Stop at first non-comment, non-blank line
+                break;
+            }
+        }
+        return docs.length > 0 ? docs.join('\n') : undefined;
+    }
+
+    private getKeywordCompletions(): vscode.CompletionItem[] {
+        const keywords = [
+            { label: 'fun', kind: vscode.CompletionItemKind.Keyword, detail: 'Function declaration', insertText: 'fun ${1:name}(${2:\\$param}) {\n\t${3:// body}\n\treturn ${4:value}\n}' },
+            { label: 'modifier', kind: vscode.CompletionItemKind.Keyword, detail: 'Modifier function', insertText: 'modifier ${1:name}(${2:\\$value}) {\n\treturn ${3:\\$value}\n}' },
+            { label: 'if', kind: vscode.CompletionItemKind.Keyword, detail: 'If statement', insertText: 'if (${1:condition})\n\t${2:// true block}\nendif' },
+            { label: 'ifelse', kind: vscode.CompletionItemKind.Keyword, detail: 'If-else statement', insertText: 'if (${1:condition})\n\t${2:// true block}\nelse\n\t${3:// false block}\nendif' },
+            { label: 'foreach', kind: vscode.CompletionItemKind.Keyword, detail: 'ForEach loop', insertText: 'foreach ${1:\\$item} in ${2:\\$array}\n\t${3:// loop body}\nendfor' },
+            { label: 'while', kind: vscode.CompletionItemKind.Keyword, detail: 'While loop', insertText: 'while (${1:condition})\n\t${2:// loop body}\nendwhile' },
+            { label: 'switch', kind: vscode.CompletionItemKind.Keyword, detail: 'Switch statement', insertText: 'switch (${1:\\$var})\n\t${2:value} -> ${3:result};\n\telse -> ${4:default};\nendswitch' },
+            { label: 'return', kind: vscode.CompletionItemKind.Keyword, detail: 'Return statement', insertText: 'return ${1:value}' },
+            { label: 'import', kind: vscode.CompletionItemKind.Keyword, detail: 'Import module', insertText: 'import ${1:Module} from \'${2:file.isl}\';' },
+            { label: 'type', kind: vscode.CompletionItemKind.Keyword, detail: 'Type declaration', insertText: 'type ${1:TypeName} as {\n\t${2:prop}: ${3:String}\n};' },
+            { label: 'parallel', kind: vscode.CompletionItemKind.Keyword, detail: 'Parallel execution', insertText: 'parallel ' },
+            { label: 'cache', kind: vscode.CompletionItemKind.Keyword, detail: 'Cache function result', insertText: 'cache ' },
+        ];
+
+        return keywords.map(k => {
+            const item = new vscode.CompletionItem(k.label, k.kind);
+            item.detail = k.detail;
+            if (k.insertText) {
+                item.insertText = new vscode.SnippetString(k.insertText);
+            }
+            return item;
+        });
+    }
+
+    private getServiceCompletions(): vscode.CompletionItem[] {
+        const services = [
+            { 
+                label: 'This', 
+                methods: [''], 
+                detail: 'Call functions in current script',
+                documentation: 'Provides access to functions defined in the current ISL file.\n\nType `@.This.` to see available functions.'
+            },
+            { 
+                label: 'Date', 
+                methods: ['Now()', 'parse(format)', 'fromEpochSeconds(seconds)', 'fromEpochMillis(millis)'], 
+                detail: 'Date/time operations',
+                documentation: 'Date and time operations (UTC).\n\n**Methods:**\n- `Now()` - Current date/time\n- `parse(string, format)` - Parse date\n- `fromEpochSeconds(seconds)`\n- `fromEpochMillis(millis)`'
+            },
+            { 
+                label: 'Math', 
+                methods: ['sum(initial)', 'average()', 'mean()', 'min()', 'max()', 'mod(divisor)', 'sqrt()', 'clamp(min, max)', 'round()', 'floor()', 'ceil()', 'abs()', 'RandInt(min, max)', 'RandFloat()', 'RandDouble()'], 
+                detail: 'Math operations',
+                documentation: 'Mathematical operations on arrays and numbers.\n\nUse with arrays: `$total: $prices | Math.sum(0)`\n\nRandom numbers: `Math.RandInt(1, 100)`'
+            },
+            { 
+                label: 'String', 
+                methods: ['concat(...)', 'join(array, sep)', 'split(str, sep)', 'replace(str, find, replace)'], 
+                detail: 'String operations',
+                documentation: 'String manipulation functions.'
+            },
+            { 
+                label: 'Array', 
+                methods: ['concat(...)', 'slice(start, end)', 'reverse()', 'flatten()', 'range(start, count, increment)'], 
+                detail: 'Array operations',
+                documentation: 'Array manipulation functions.\n\n`Array.range(0, 10, 1)` creates array [0..9]'
+            },
+            { 
+                label: 'Json', 
+                methods: ['parse(string)', 'stringify(object)'], 
+                detail: 'JSON operations',
+                documentation: 'JSON parsing and serialization.\n\n```isl\n$obj: @.Json.parse($jsonString);\n```'
+            },
+            { 
+                label: 'Xml', 
+                methods: ['parse(string)', 'toXml(object, rootName)'], 
+                detail: 'XML operations',
+                documentation: 'XML parsing and generation.\n\nAttributes use @ prefix, text uses #text'
+            },
+            { 
+                label: 'Csv', 
+                methods: ['parse(string)', 'parsemultiline(string, options)'], 
+                detail: 'CSV operations',
+                documentation: 'CSV parsing.\n\n```isl\n$data: @.Csv.parsemultiline($csvText);\n```'
+            },
+            { 
+                label: 'Crypto', 
+                methods: ['md5(string)', 'sha1(string)', 'sha256(string)', 'base64encode(string)', 'base64decode(string)'], 
+                detail: 'Cryptography functions',
+                documentation: 'Cryptographic and encoding functions.'
+            },
+        ];
+
+        return services.map(s => {
+            const item = new vscode.CompletionItem(s.label, vscode.CompletionItemKind.Class);
+            item.detail = s.detail;
+            item.documentation = new vscode.MarkdownString(s.documentation);
+            item.insertText = s.label;
+            return item;
+        });
+    }
+
+    private getModifierCompletions(extensions: import('./extensions').IslExtensions): vscode.CompletionItem[] {
+        const modifiers = [
+            // Type conversions
+            { label: 'to.string', detail: 'Convert to string', insertText: 'to.string', kind: vscode.CompletionItemKind.Method, docs: 'Converts value to string.\n\nFor dates: `to.string(format)`' },
+            { label: 'to.number', detail: 'Convert to number', insertText: 'to.number', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.decimal', detail: 'Convert to decimal', insertText: 'to.decimal', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.boolean', detail: 'Convert to boolean', insertText: 'to.boolean', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.array', detail: 'Convert to array', insertText: 'to.array', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.object', detail: 'Convert to object', insertText: 'to.object', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.json', detail: 'Convert to JSON string', insertText: 'to.json', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.yaml', detail: 'Convert to YAML string', insertText: 'to.yaml', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.csv', detail: 'Convert to CSV string', insertText: 'to.csv', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.xml', detail: 'Convert to XML', insertText: 'to.xml("${1:root}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.hex', detail: 'Convert to hex string', insertText: 'to.hex', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.bytes', detail: 'Convert to byte array', insertText: 'to.bytes', kind: vscode.CompletionItemKind.Method },
+            { label: 'to.epochmillis', detail: 'Convert date to epoch milliseconds', insertText: 'to.epochmillis', kind: vscode.CompletionItemKind.Method },
+            
+            // String modifiers
+            { label: 'trim', detail: 'Trim whitespace', insertText: 'trim', kind: vscode.CompletionItemKind.Method },
+            { label: 'trimStart', detail: 'Trim start whitespace', insertText: 'trimStart', kind: vscode.CompletionItemKind.Method },
+            { label: 'trimEnd', detail: 'Trim end whitespace', insertText: 'trimEnd', kind: vscode.CompletionItemKind.Method },
+            { label: 'upperCase', detail: 'Convert to uppercase', insertText: 'upperCase', kind: vscode.CompletionItemKind.Method },
+            { label: 'lowerCase', detail: 'Convert to lowercase', insertText: 'lowerCase', kind: vscode.CompletionItemKind.Method },
+            { label: 'capitalize', detail: 'Capitalize first letter', insertText: 'capitalize', kind: vscode.CompletionItemKind.Method },
+            { label: 'titleCase', detail: 'Convert to title case', insertText: 'titleCase', kind: vscode.CompletionItemKind.Method },
+            { label: 'camelCase', detail: 'Convert to camelCase', insertText: 'camelCase', kind: vscode.CompletionItemKind.Method },
+            { label: 'snakeCase', detail: 'Convert to snake_case', insertText: 'snakeCase', kind: vscode.CompletionItemKind.Method },
+            { label: 'left', detail: 'Get left N characters', insertText: 'left(${1:length})', kind: vscode.CompletionItemKind.Method },
+            { label: 'right', detail: 'Get right N characters', insertText: 'right(${1:length})', kind: vscode.CompletionItemKind.Method },
+            { label: 'cap', detail: 'Cap string at length (alias for left)', insertText: 'cap(${1:length})', kind: vscode.CompletionItemKind.Method },
+            { label: 'split', detail: 'Split string', insertText: 'split("${1:,}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'replace', detail: 'Replace string', insertText: 'replace("${1:find}", "${2:replace}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'remove', detail: 'Remove substring', insertText: 'remove("${1:text}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'substring', detail: 'Get substring', insertText: 'substring(${1:start}, ${2:end})', kind: vscode.CompletionItemKind.Method },
+            { label: 'substringUpto', detail: 'Substring up to delimiter', insertText: 'substringUpto("${1:delimiter}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'substringAfter', detail: 'Substring after delimiter', insertText: 'substringAfter("${1:delimiter}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'truncate', detail: 'Truncate string', insertText: 'truncate(${1:length}, "${2:...}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'padStart', detail: 'Pad start', insertText: 'padStart(${1:length}, "${2: }")', kind: vscode.CompletionItemKind.Method },
+            { label: 'padEnd', detail: 'Pad end', insertText: 'padEnd(${1:length}, "${2: }")', kind: vscode.CompletionItemKind.Method },
+            { label: 'concat', detail: 'Concatenate strings', insertText: 'concat(${1:\\$other}, "${2:delimiter}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'append', detail: 'Append strings', insertText: 'append(${1:\\$value})', kind: vscode.CompletionItemKind.Method },
+            { label: 'reverse', detail: 'Reverse string/array', insertText: 'reverse', kind: vscode.CompletionItemKind.Method },
+            { label: 'sanitizeTid', detail: 'Sanitize UUID/TID', insertText: 'sanitizeTid', kind: vscode.CompletionItemKind.Method },
+            
+            // Array modifiers
+            { label: 'filter', detail: 'Filter array', insertText: 'filter(${1:\\$fit.${2:condition}})', kind: vscode.CompletionItemKind.Method, docs: 'Filters array based on condition.\n\nUse $fit or $ for current item being filtered.\n\nExample: `$active: $items | filter($fit.active)`' },
+            { label: 'map', detail: 'Map array', insertText: 'map(${1:\\$.${2:property}})', kind: vscode.CompletionItemKind.Method, docs: 'Transforms each element.\n\nUse $ for current item.\n\nExample: `$names: $users | map($.name)`' },
+            { label: 'reduce', detail: 'Reduce array', insertText: 'reduce({{ \\$acc + \\$it }}, ${1:0})', kind: vscode.CompletionItemKind.Method, docs: 'Reduces array to single value.\n\nUse $acc (accumulator) and $it (current item).\n\nExample: `$sum: $numbers | reduce({{ $acc + $it }}, 0)`' },
+            { label: 'sort', detail: 'Sort array/object', insertText: 'sort', kind: vscode.CompletionItemKind.Method },
+            { label: 'unique', detail: 'Get unique values', insertText: 'unique', kind: vscode.CompletionItemKind.Method },
+            { label: 'slice', detail: 'Slice array', insertText: 'slice(${1:start}, ${2:end})', kind: vscode.CompletionItemKind.Method },
+            { label: 'length', detail: 'Get length', insertText: 'length', kind: vscode.CompletionItemKind.Method },
+            { label: 'first', detail: 'Get first element', insertText: 'first', kind: vscode.CompletionItemKind.Method },
+            { label: 'last', detail: 'Get last element', insertText: 'last', kind: vscode.CompletionItemKind.Method },
+            { label: 'take', detail: 'Take first N elements', insertText: 'take(${1:n})', kind: vscode.CompletionItemKind.Method },
+            { label: 'drop', detail: 'Drop first N elements', insertText: 'drop(${1:n})', kind: vscode.CompletionItemKind.Method },
+            { label: 'at', detail: 'Get element at index', insertText: 'at(${1:index})', kind: vscode.CompletionItemKind.Method, docs: 'Supports negative indices: `at(-1)` gets last element' },
+            { label: 'indexOf', detail: 'Find index of element', insertText: 'indexOf(${1:element})', kind: vscode.CompletionItemKind.Method },
+            { label: 'lastIndexOf', detail: 'Find last index of element', insertText: 'lastIndexOf(${1:element})', kind: vscode.CompletionItemKind.Method },
+            { label: 'isEmpty', detail: 'Check if empty', insertText: 'isEmpty', kind: vscode.CompletionItemKind.Method },
+            { label: 'isNotEmpty', detail: 'Check if not empty', insertText: 'isNotEmpty', kind: vscode.CompletionItemKind.Method },
+            { label: 'push', detail: 'Add item to array', insertText: 'push(${1:item})', kind: vscode.CompletionItemKind.Method },
+            { label: 'pushItems', detail: 'Push full array to end', insertText: 'pushItems(${1:\\$otherArray})', kind: vscode.CompletionItemKind.Method, docs: 'Appends all items from the provided array to the end of the input array.\n\nExample: `$items | pushItems($moreItems)`' },
+            { label: 'pop', detail: 'Remove last item', insertText: 'pop', kind: vscode.CompletionItemKind.Method },
+            { label: 'chunk', detail: 'Split into chunks', insertText: 'chunk(${1:size})', kind: vscode.CompletionItemKind.Method },
+            
+            // Date modifiers
+            { label: 'date.parse', detail: 'Parse date', insertText: 'date.parse("${1:yyyy-MM-dd}")', kind: vscode.CompletionItemKind.Method, docs: 'Parses date string.\n\nOptional locale: `date.parse(format, {locale: "en_US"})`' },
+            { label: 'date.add', detail: 'Add to date', insertText: 'date.add(${1:value}, "${2:DAYS}")', kind: vscode.CompletionItemKind.Method, docs: 'Units: YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS' },
+            { label: 'date.part', detail: 'Get date part', insertText: 'date.part("${1:YEAR}")', kind: vscode.CompletionItemKind.Method, docs: 'Parts: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DAYOFYEAR, DAYOFWEEK' },
+            { label: 'date.fromEpochSeconds', detail: 'From epoch seconds', insertText: 'date.fromEpochSeconds', kind: vscode.CompletionItemKind.Method },
+            { label: 'date.fromEpochMillis', detail: 'From epoch milliseconds', insertText: 'date.fromEpochMillis', kind: vscode.CompletionItemKind.Method },
+            
+            // JSON/XML/CSV modifiers
+            { label: 'json.parse', detail: 'Parse JSON', insertText: 'json.parse', kind: vscode.CompletionItemKind.Method },
+            { label: 'yaml.parse', detail: 'Parse YAML', insertText: 'yaml.parse', kind: vscode.CompletionItemKind.Method },
+            { label: 'xml.parse', detail: 'Parse XML', insertText: 'xml.parse', kind: vscode.CompletionItemKind.Method },
+            { label: 'csv.parsemultiline', detail: 'Parse CSV', insertText: 'csv.parsemultiline', kind: vscode.CompletionItemKind.Method, docs: 'Options: {headers: true, separator: ",", skipLines: 0}' },
+            { label: 'csv.findrow', detail: 'Find CSV row', insertText: 'csv.findrow', kind: vscode.CompletionItemKind.Method },
+            { label: 'html.escape', detail: 'Escape HTML entities', insertText: 'html.escape', kind: vscode.CompletionItemKind.Method },
+            { label: 'html.unescape', detail: 'Unescape HTML entities', insertText: 'html.unescape', kind: vscode.CompletionItemKind.Method },
+            
+            // Math modifiers
+            { label: 'Math.sum', detail: 'Sum values', insertText: 'Math.sum(${1:0})', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.average', detail: 'Average values', insertText: 'Math.average', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.mean', detail: 'Mean of values', insertText: 'Math.mean', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.min', detail: 'Minimum value', insertText: 'Math.min', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.max', detail: 'Maximum value', insertText: 'Math.max', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.mod', detail: 'Modulo operation', insertText: 'Math.mod(${1:divisor})', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.sqrt', detail: 'Square root', insertText: 'Math.sqrt', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.round', detail: 'Round number', insertText: 'Math.round', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.floor', detail: 'Round down', insertText: 'Math.floor', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.ceil', detail: 'Round up', insertText: 'Math.ceil', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.abs', detail: 'Absolute value', insertText: 'Math.abs', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.clamp', detail: 'Clamp value', insertText: 'Math.clamp(${1:min}, ${2:max})', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.RandInt', detail: 'Random integer', insertText: 'Math.RandInt(${1:min}, ${2:max})', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.RandFloat', detail: 'Random float', insertText: 'Math.RandFloat', kind: vscode.CompletionItemKind.Method },
+            { label: 'Math.RandDouble', detail: 'Random double', insertText: 'Math.RandDouble', kind: vscode.CompletionItemKind.Method },
+            { label: 'negate', detail: 'Negate number', insertText: 'negate', kind: vscode.CompletionItemKind.Method },
+            { label: 'absolute', detail: 'Absolute value', insertText: 'absolute', kind: vscode.CompletionItemKind.Method },
+            { label: 'precision', detail: 'Set decimal precision', insertText: 'precision(${1:2})', kind: vscode.CompletionItemKind.Method },
+            { label: 'round.up', detail: 'Round up', insertText: 'round.up', kind: vscode.CompletionItemKind.Method },
+            { label: 'round.down', detail: 'Round down', insertText: 'round.down', kind: vscode.CompletionItemKind.Method },
+            { label: 'round.half', detail: 'Round half', insertText: 'round.half', kind: vscode.CompletionItemKind.Method },
+            
+            // Object modifiers
+            { label: 'keys', detail: 'Get object keys', insertText: 'keys', kind: vscode.CompletionItemKind.Method },
+            { label: 'kv', detail: 'Key-value pairs', insertText: 'kv', kind: vscode.CompletionItemKind.Method, docs: 'Converts object to [{key, value}] array' },
+            { label: 'delete', detail: 'Delete property', insertText: 'delete("${1:property}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'select', detail: 'Select by JSON path', insertText: 'select("${1:path}")', kind: vscode.CompletionItemKind.Method, docs: 'Example: select("user.address.city")' },
+            { label: 'getProperty', detail: 'Get property (case-insensitive)', insertText: 'getProperty("${1:name}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'setProperty', detail: 'Set property', insertText: 'setProperty("${1:name}", ${2:value})', kind: vscode.CompletionItemKind.Method },
+            { label: 'merge', detail: 'Merge objects', insertText: 'merge(${1:\\$other})', kind: vscode.CompletionItemKind.Method },
+            { label: 'pick', detail: 'Pick properties', insertText: 'pick("${1:prop1}", "${2:prop2}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'omit', detail: 'Omit properties', insertText: 'omit("${1:prop1}", "${2:prop2}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'rename', detail: 'Rename property', insertText: 'rename("${1:oldName}", "${2:newName}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'has', detail: 'Check if has property', insertText: 'has("${1:property}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'default', detail: 'Default value if null/empty', insertText: 'default(${1:value})', kind: vscode.CompletionItemKind.Method },
+            
+            // Regex modifiers
+            { label: 'regex.find', detail: 'Find regex matches', insertText: 'regex.find("${1:pattern}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'regex.matches', detail: 'Test regex match', insertText: 'regex.matches("${1:pattern}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'regex.replace', detail: 'Replace with regex', insertText: 'regex.replace("${1:pattern}", "${2:replacement}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'regex.replacefirst', detail: 'Replace first match', insertText: 'regex.replacefirst("${1:pattern}", "${2:replacement}")', kind: vscode.CompletionItemKind.Method },
+            
+            // Encoding modifiers
+            { label: 'encode.base64', detail: 'Base64 encode', insertText: 'encode.base64', kind: vscode.CompletionItemKind.Method },
+            { label: 'encode.base64url', detail: 'Base64 URL encode', insertText: 'encode.base64url', kind: vscode.CompletionItemKind.Method },
+            { label: 'encode.path', detail: 'URL path encode', insertText: 'encode.path', kind: vscode.CompletionItemKind.Method },
+            { label: 'encode.query', detail: 'URL query encode', insertText: 'encode.query', kind: vscode.CompletionItemKind.Method },
+            { label: 'decode.base64', detail: 'Base64 decode', insertText: 'decode.base64', kind: vscode.CompletionItemKind.Method },
+            { label: 'decode.base64url', detail: 'Base64 URL decode', insertText: 'decode.base64url', kind: vscode.CompletionItemKind.Method },
+            { label: 'decode.query', detail: 'URL query decode', insertText: 'decode.query', kind: vscode.CompletionItemKind.Method },
+            { label: 'hex.tobinary', detail: 'Convert hex to binary', insertText: 'hex.tobinary', kind: vscode.CompletionItemKind.Method },
+            { label: 'join.string', detail: 'Join array to string', insertText: 'join.string("${1:,}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'join.path', detail: 'Join for URL path', insertText: 'join.path("${1:&}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'join.query', detail: 'Join for URL query', insertText: 'join.query("${1:&}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'email.parse', detail: 'Parse email addresses', insertText: 'email.parse', kind: vscode.CompletionItemKind.Method },
+            
+            // Compression modifiers
+            { label: 'gzip', detail: 'GZip compress', insertText: 'gzip', kind: vscode.CompletionItemKind.Method },
+            { label: 'gunzip', detail: 'GZip decompress', insertText: 'gunzip', kind: vscode.CompletionItemKind.Method },
+            { label: 'gunzipToByte', detail: 'GZip decompress to bytes', insertText: 'gunzipToByte', kind: vscode.CompletionItemKind.Method },
+            
+            // Type checking
+            { label: 'typeof', detail: 'Get type of value', insertText: 'typeof', kind: vscode.CompletionItemKind.Method },
+            
+            // Legacy/Common
+            { label: 'contains', detail: 'Check if contains', insertText: 'contains("${1:value}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'startsWith', detail: 'Check if starts with', insertText: 'startsWith("${1:prefix}")', kind: vscode.CompletionItemKind.Method },
+            { label: 'endsWith', detail: 'Check if ends with', insertText: 'endsWith("${1:suffix}")', kind: vscode.CompletionItemKind.Method },
+        ];
+
+        const completionItems = modifiers.map(m => {
+            const item = new vscode.CompletionItem(m.label, m.kind);
+            item.detail = m.detail;
+            item.insertText = new vscode.SnippetString(m.insertText);
+            if (m.docs) {
+                item.documentation = new vscode.MarkdownString(m.docs);
+            }
+            return item;
+        });
+
+        // Add custom modifiers from extensions
+        for (const [name, modDef] of extensions.modifiers) {
+            const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Method);
+            item.detail = this.formatModifierSignature(modDef);
+            
+            // Create snippet with parameters
+            const paramSnippets = modDef.parameters.map((param, idx) => {
+                if (param.defaultValue) {
+                    return `\${${idx + 1}:${param.defaultValue}}`;
+                }
+                return `\${${idx + 1}:${param.name}}`;
+            });
+            
+            if (paramSnippets.length > 0) {
+                item.insertText = new vscode.SnippetString(`${name}(${paramSnippets.join(', ')})`);
+            } else {
+                item.insertText = new vscode.SnippetString(name);
+            }
+            
+            // Add documentation
+            item.documentation = this.formatModifierDocumentation(modDef);
+            
+            completionItems.push(item);
+        }
+
+        return completionItems;
+    }
+
+    private formatModifierSignature(mod: IslModifierDefinition): string {
+        if (mod.parameters.length === 0) {
+            return `modifier ${mod.name} (custom)`;
+        }
+        
+        const params = mod.parameters.map(p => {
+            let result = `${p.name}`;
+            if (p.type) {
+                result += `: ${p.type}`;
+            }
+            if (p.optional) {
+                result += '?';
+            }
+            return result;
+        }).join(', ');
+        
+        return `modifier ${mod.name}(${params})${mod.returns?.type ? ': ' + mod.returns.type : ''} (custom)`;
+    }
+
+    private formatModifierDocumentation(mod: IslModifierDefinition): vscode.MarkdownString {
+        const md = new vscode.MarkdownString();
+        md.isTrusted = true;
+        
+        if (mod.description) {
+            md.appendMarkdown(`${mod.description}\n\n`);
+        }
+        
+        if (mod.parameters.length > 0) {
+            md.appendMarkdown('**Parameters:**\n');
+            for (const param of mod.parameters) {
+                const optional = param.optional ? ' (optional)' : '';
+                const type = param.type ? `: ${param.type}` : '';
+                const desc = param.description ? ` - ${param.description}` : '';
+                const defaultVal = param.defaultValue ? ` (default: ${param.defaultValue})` : '';
+                md.appendMarkdown(`- \`${param.name}${type}\`${optional}${defaultVal}${desc}\n`);
+            }
+            md.appendMarkdown('\n');
+        }
+        
+        if (mod.returns) {
+            md.appendMarkdown('**Returns:**');
+            if (mod.returns.type) {
+                md.appendMarkdown(` \`${mod.returns.type}\``);
+            }
+            if (mod.returns.description) {
+                md.appendMarkdown(` - ${mod.returns.description}`);
+            }
+            md.appendMarkdown('\n\n');
+        }
+        
+        if (mod.examples && mod.examples.length > 0) {
+            md.appendMarkdown('**Examples:**\n');
+            for (const example of mod.examples) {
+                md.appendMarkdown('```isl\n' + example + '\n```\n');
+            }
+        }
+        
+        md.appendMarkdown('\n*Custom modifier from .islextensions*');
+        
+        return md;
+    }
+
+    private getVariableCompletions(document: vscode.TextDocument): vscode.CompletionItem[] {
+        const variables: Map = new Map();
+        const text = document.getText();
+        
+        // Find all variable declarations and usages
+        const varPattern = /\$([a-zA-Z_][a-zA-Z0-9_]*)/g;
+        let match;
+        
+        while ((match = varPattern.exec(text)) !== null) {
+            const varName = match[1];
+            if (!variables.has(varName)) {
+                const item = new vscode.CompletionItem('$' + varName, vscode.CompletionItemKind.Variable);
+                item.detail = 'Variable';
+                item.insertText = '$' + varName; // Include $ in the insert text
+                item.filterText = varName; // Filter without $ for better matching
+                variables.set(varName, item);
+            }
+        }
+
+        // Also add common input variable
+        if (!variables.has('input')) {
+            const inputItem = new vscode.CompletionItem('$input', vscode.CompletionItemKind.Variable);
+            inputItem.detail = 'Input parameter';
+            inputItem.insertText = '$input';
+            inputItem.filterText = 'input';
+            variables.set('input', inputItem);
+        }
+
+        return Array.from(variables.values());
+    }
+    
+    private getPaginationType(document: vscode.TextDocument, varName: string): string | null {
+        const text = document.getText();
+        const lines = text.split('\n');
+        
+        // Look for @.Pagination.[Type]( $varName, ... )
+        for (const line of lines) {
+            const cursorMatch = line.match(/@\.Pagination\.Cursor\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (cursorMatch && cursorMatch[1] === varName) {
+                return 'Cursor';
+            }
+            
+            const offsetMatch = line.match(/@\.Pagination\.Offset\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (offsetMatch && offsetMatch[1] === varName) {
+                return 'Offset';
+            }
+            
+            const pageMatch = line.match(/@\.Pagination\.Page\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (pageMatch && pageMatch[1] === varName) {
+                return 'Page';
+            }
+            
+            const keysetMatch = line.match(/@\.Pagination\.Keyset\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (keysetMatch && keysetMatch[1] === varName) {
+                return 'Keyset';
+            }
+            
+            const dateMatch = line.match(/@\.Pagination\.Date\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (dateMatch && dateMatch[1] === varName) {
+                return 'Date';
+            }
+        }
+        
+        return null;
+    }
+    
+    private getPaginationPropertyCompletions(paginationType: string): vscode.CompletionItem[] {
+        if (paginationType === 'Cursor') {
+            return [
+                this.createPaginationProperty(
+                    'current',
+                    'The value of the current cursor for the current page',
+                    'On the first loop this is null.'
+                ),
+                this.createPaginationProperty(
+                    'next',
+                    'The next value for the cursor on the next loop',
+                    'This needs to be set in the loop. If this value is the same as the previous value (e.g. value was not set) or the value is null, the pagination loop exits.'
+                )
+            ];
+        } else if (paginationType === 'Page') {
+            return [
+                this.createPaginationProperty(
+                    'startIndex',
+                    'The starting index as declared in the pagination',
+                    'Default is 0. This is the value passed in the pagination configuration.'
+                ),
+                this.createPaginationProperty(
+                    'pageSize',
+                    'Size of the page as declared in the pagination',
+                    'Default is 100. This is the value passed in the pagination configuration.'
+                ),
+                this.createPaginationProperty(
+                    'page',
+                    'Index of the current page',
+                    'Starting at startIndex. Increments with each iteration of the pagination loop.'
+                ),
+                this.createPaginationProperty(
+                    'fromOffset',
+                    'Start offset for the current page',
+                    'Calculated as: page * pageSize'
+                ),
+                this.createPaginationProperty(
+                    'toOffset',
+                    'End offset for the current page',
+                    'Calculated as: (page + 1) * pageSize'
+                ),
+                this.createPaginationProperty(
+                    'hasMorePages',
+                    'Whether there are more pages to fetch',
+                    'Set to false by default. In order to continue the pagination loop this needs to be set to true.'
+                )
+            ];
+        } else if (paginationType === 'Date') {
+            return [
+                this.createPaginationProperty(
+                    'startDate',
+                    'Start date of the current period',
+                    'The beginning of the current pagination period based on the duration.'
+                ),
+                this.createPaginationProperty(
+                    'endDate',
+                    'End date of the current period',
+                    'The end of the current pagination period based on the duration.'
+                ),
+                this.createPaginationProperty(
+                    'page',
+                    'Zero-based page index for the current page',
+                    'Increments with each iteration: 0, 1, 2, ...'
+                )
+            ];
+        }
+        
+        // Placeholder for other pagination types (Offset, Keyset)
+        return [];
+    }
+    
+    private createPaginationProperty(name: string, detail: string, docs: string): vscode.CompletionItem {
+        const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Property);
+        item.detail = detail;
+        item.documentation = new vscode.MarkdownString(docs);
+        item.insertText = name;
+        return item;
+    }
+}
diff --git a/plugin/src/definition.ts b/plugin/src/definition.ts
new file mode 100644
index 0000000..e658b92
--- /dev/null
+++ b/plugin/src/definition.ts
@@ -0,0 +1,102 @@
+import * as vscode from 'vscode';
+
+export class IslDefinitionProvider implements vscode.DefinitionProvider {
+    
+    provideDefinition(
+        document: vscode.TextDocument,
+        position: vscode.Position,
+        token: vscode.CancellationToken
+    ): vscode.Definition | undefined {
+        const range = document.getWordRangeAtPosition(position);
+        if (!range) {
+            return undefined;
+        }
+
+        const word = document.getText(range);
+        const line = document.lineAt(position.line).text;
+
+        // Check if this is a function call
+        if (line.includes('@.This.' + word)) {
+            return this.findFunctionDefinition(word, document);
+        }
+
+        // Check if this is a type reference
+        if (this.isTypeReference(word, line)) {
+            return this.findTypeDefinition(word, document);
+        }
+
+        // Check if this is an import reference
+        if (this.isImportReference(word, line)) {
+            return this.findImportedFile(word, document);
+        }
+
+        return undefined;
+    }
+
+    private findFunctionDefinition(functionName: string, document: vscode.TextDocument): vscode.Location | undefined {
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        // Look for function declaration
+        const functionPattern = new RegExp(`^\\s*(fun|modifier)\\s+${functionName}\\s*\\(`);
+
+        for (let i = 0; i < lines.length; i++) {
+            if (functionPattern.test(lines[i])) {
+                const position = new vscode.Position(i, 0);
+                return new vscode.Location(document.uri, position);
+            }
+        }
+
+        return undefined;
+    }
+
+    private isTypeReference(word: string, line: string): boolean {
+        // Check if word appears after a colon (type annotation)
+        return line.includes(': ' + word) || line.includes(':' + word);
+    }
+
+    private findTypeDefinition(typeName: string, document: vscode.TextDocument): vscode.Location | undefined {
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        // Look for type declaration
+        const typePattern = new RegExp(`^\\s*type\\s+${typeName}\\s+(as|from)`);
+
+        for (let i = 0; i < lines.length; i++) {
+            if (typePattern.test(lines[i])) {
+                const position = new vscode.Position(i, 0);
+                return new vscode.Location(document.uri, position);
+            }
+        }
+
+        return undefined;
+    }
+
+    private isImportReference(word: string, line: string): boolean {
+        // Check if word appears in import statement or is being used as imported module
+        return line.includes('import ' + word) || line.includes('@.' + word);
+    }
+
+    private findImportedFile(moduleName: string, document: vscode.TextDocument): vscode.Location | undefined {
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        // Look for import statement
+        const importPattern = new RegExp(`import\\s+${moduleName}\\s+from\\s+['"]([^'"]+)['"]`);
+
+        for (let i = 0; i < lines.length; i++) {
+            const match = lines[i].match(importPattern);
+            if (match) {
+                const importPath = match[1];
+                // Resolve relative path
+                const currentDir = vscode.Uri.joinPath(document.uri, '..');
+                const importedFileUri = vscode.Uri.joinPath(currentDir, importPath);
+                
+                return new vscode.Location(importedFileUri, new vscode.Position(0, 0));
+            }
+        }
+
+        return undefined;
+    }
+}
+
diff --git a/plugin/src/executor.ts b/plugin/src/executor.ts
new file mode 100644
index 0000000..7846cca
--- /dev/null
+++ b/plugin/src/executor.ts
@@ -0,0 +1,169 @@
+import * as vscode from 'vscode';
+import * as cp from 'child_process';
+import * as path from 'path';
+import * as fs from 'fs';
+
+export class IslExecutor {
+    private outputChannel: vscode.OutputChannel;
+
+    constructor() {
+        this.outputChannel = vscode.window.createOutputChannel('ISL');
+    }
+
+    public async run(document: vscode.TextDocument): Promise {
+        // Prompt for input data
+        const inputJson = await vscode.window.showInputBox({
+            prompt: 'Enter input JSON (or leave empty for empty object)',
+            placeHolder: '{"key": "value"}',
+            value: '{}'
+        });
+
+        if (inputJson === undefined) {
+            return; // User cancelled
+        }
+
+        await this.executeIsl(document, inputJson);
+    }
+
+    public async runWithInput(document: vscode.TextDocument): Promise {
+        // Prompt for input file
+        const files = await vscode.window.showOpenDialog({
+            canSelectMany: false,
+            filters: { 'JSON Files': ['json'] },
+            openLabel: 'Select Input JSON File'
+        });
+
+        if (!files || files.length === 0) {
+            return; // User cancelled
+        }
+
+        const inputFile = files[0].fsPath;
+        
+        try {
+            const inputJson = fs.readFileSync(inputFile, 'utf8');
+            await this.executeIsl(document, inputJson);
+        } catch (error) {
+            vscode.window.showErrorMessage(`Failed to read input file: ${error}`);
+        }
+    }
+
+    private async executeIsl(document: vscode.TextDocument, inputJson: string): Promise {
+        // Save document if it has unsaved changes
+        if (document.isDirty) {
+            await document.save();
+        }
+
+        const config = vscode.workspace.getConfiguration('isl.execution');
+        let islCommand = config.get('islCommand', 'isl');
+        const javaHome = config.get('javaHome', '');
+
+        // Check if we should use the local isl.sh or isl.bat
+        const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri);
+        if (workspaceFolder) {
+            const islSh = path.join(workspaceFolder.uri.fsPath, 'isl.sh');
+            const islBat = path.join(workspaceFolder.uri.fsPath, 'isl.bat');
+            
+            if (process.platform === 'win32' && fs.existsSync(islBat)) {
+                islCommand = islBat;
+            } else if (fs.existsSync(islSh)) {
+                islCommand = islSh;
+            }
+        }
+
+        // Prepare environment
+        const env = { ...process.env };
+        if (javaHome) {
+            env.JAVA_HOME = javaHome;
+            env.PATH = `${path.join(javaHome, 'bin')}${path.delimiter}${env.PATH}`;
+        }
+
+        this.outputChannel.clear();
+        this.outputChannel.show();
+        this.outputChannel.appendLine('=== ISL Execution ===');
+        this.outputChannel.appendLine(`Script: ${document.fileName}`);
+        this.outputChannel.appendLine(`Input: ${inputJson}`);
+        this.outputChannel.appendLine('');
+
+        // Create temporary files for input
+        const tempDir = path.join(path.dirname(document.fileName), '.isl-temp');
+        if (!fs.existsSync(tempDir)) {
+            fs.mkdirSync(tempDir, { recursive: true });
+        }
+
+        const tempInputFile = path.join(tempDir, 'input.json');
+        fs.writeFileSync(tempInputFile, inputJson);
+
+        try {
+            // Execute ISL command
+            const args = [document.fileName, '-i', tempInputFile];
+            
+            this.outputChannel.appendLine(`Command: ${islCommand} ${args.join(' ')}`);
+            this.outputChannel.appendLine('');
+
+            const result = await this.execPromise(islCommand, args, { env, cwd: path.dirname(document.fileName) });
+
+            this.outputChannel.appendLine('=== Output ===');
+            this.outputChannel.appendLine(result.stdout);
+
+            if (result.stderr) {
+                this.outputChannel.appendLine('');
+                this.outputChannel.appendLine('=== Errors/Warnings ===');
+                this.outputChannel.appendLine(result.stderr);
+            }
+
+            // Try to parse and format output JSON
+            try {
+                const output = JSON.parse(result.stdout);
+                const formatted = JSON.stringify(output, null, 2);
+                
+                // Show formatted output in new editor
+                const doc = await vscode.workspace.openTextDocument({
+                    content: formatted,
+                    language: 'json'
+                });
+                await vscode.window.showTextDocument(doc, { preview: false, viewColumn: vscode.ViewColumn.Beside });
+            } catch (e) {
+                // Output is not valid JSON, just show it as is
+            }
+
+        } catch (error: any) {
+            this.outputChannel.appendLine('=== Execution Failed ===');
+            this.outputChannel.appendLine(error.message);
+            if (error.stdout) {
+                this.outputChannel.appendLine('');
+                this.outputChannel.appendLine('=== Stdout ===');
+                this.outputChannel.appendLine(error.stdout);
+            }
+            if (error.stderr) {
+                this.outputChannel.appendLine('');
+                this.outputChannel.appendLine('=== Stderr ===');
+                this.outputChannel.appendLine(error.stderr);
+            }
+            vscode.window.showErrorMessage('ISL execution failed. Check output for details.');
+        } finally {
+            // Cleanup temp files
+            try {
+                fs.unlinkSync(tempInputFile);
+                fs.rmdirSync(tempDir);
+            } catch (e) {
+                // Ignore cleanup errors
+            }
+        }
+    }
+
+    private execPromise(command: string, args: string[], options: cp.ExecFileOptions): Promise<{ stdout: string, stderr: string }> {
+        return new Promise((resolve, reject) => {
+            cp.execFile(command, args, options, (error, stdout, stderr) => {
+                const stdoutStr = stdout ? stdout.toString() : '';
+                const stderrStr = stderr ? stderr.toString() : '';
+                
+                if (error) {
+                    reject({ message: error.message, stdout: stdoutStr, stderr: stderrStr });
+                } else {
+                    resolve({ stdout: stdoutStr, stderr: stderrStr });
+                }
+            });
+        });
+    }
+}
+
diff --git a/plugin/src/extension.ts b/plugin/src/extension.ts
new file mode 100644
index 0000000..21b53e8
--- /dev/null
+++ b/plugin/src/extension.ts
@@ -0,0 +1,260 @@
+import * as vscode from 'vscode';
+import { IslDocumentFormatter } from './formatter';
+import { IslValidator } from './validator';
+import { IslExecutor } from './executor';
+import { IslCompletionProvider } from './completion';
+import { IslHoverProvider } from './hover';
+import { IslDefinitionProvider } from './definition';
+import { IslCodeLensProvider, runIslFunction, showUsages, testFunction } from './codelens';
+import { IslSignatureHelpProvider } from './signature';
+import { IslInlayHintsProvider } from './inlayhints';
+import { IslCodeActionProvider, extractVariable, extractFunction, convertToTemplateString, useCoalesceOperator, useMathSum, formatChain, formatObject } from './codeactions';
+import { IslDocumentHighlightProvider } from './highlights';
+import { IslExtensionsManager } from './extensions';
+
+export function activate(context: vscode.ExtensionContext) {
+    console.log('ISL Language Support is now active');
+
+    const documentSelector: vscode.DocumentSelector = [
+        { scheme: 'file', language: 'isl' },
+        { scheme: 'untitled', language: 'isl' }
+    ];
+
+    // Initialize extensions manager
+    const extensionsManager = new IslExtensionsManager();
+    context.subscriptions.push(extensionsManager);
+
+    // Register formatter
+    const formatter = new IslDocumentFormatter();
+    context.subscriptions.push(
+        vscode.languages.registerDocumentFormattingEditProvider(documentSelector, formatter),
+        vscode.languages.registerDocumentRangeFormattingEditProvider(documentSelector, formatter)
+    );
+
+    // Register validator
+    const validator = new IslValidator(extensionsManager);
+    context.subscriptions.push(validator);
+
+    // Validate on open, save, and change
+    context.subscriptions.push(
+        vscode.workspace.onDidOpenTextDocument(doc => {
+            if (doc.languageId === 'isl') {
+                validator.validate(doc);
+            }
+        }),
+        vscode.workspace.onDidSaveTextDocument(doc => {
+            if (doc.languageId === 'isl') {
+                validator.validate(doc);
+            }
+        }),
+        vscode.workspace.onDidChangeTextDocument(event => {
+            if (event.document.languageId === 'isl') {
+                validator.validateDebounced(event.document);
+            }
+        })
+    );
+
+    // Validate all open ISL documents on activation
+    vscode.workspace.textDocuments.forEach(doc => {
+        if (doc.languageId === 'isl') {
+            validator.validate(doc);
+        }
+    });
+
+    // Register completion provider
+    const completionProvider = new IslCompletionProvider(extensionsManager);
+    context.subscriptions.push(
+        vscode.languages.registerCompletionItemProvider(documentSelector, completionProvider, '$', '@', '.', '|')
+    );
+
+    // Register hover provider
+    const hoverProvider = new IslHoverProvider(extensionsManager);
+    context.subscriptions.push(
+        vscode.languages.registerHoverProvider(documentSelector, hoverProvider)
+    );
+
+    // Watch for extensions file changes and revalidate
+    extensionsManager.onDidChange((uri) => {
+        // Revalidate all open ISL documents
+        vscode.workspace.textDocuments.forEach(doc => {
+            if (doc.languageId === 'isl') {
+                validator.validate(doc);
+            }
+        });
+        vscode.window.showInformationMessage('ISL extensions reloaded');
+    });
+
+    // Register definition provider
+    const definitionProvider = new IslDefinitionProvider();
+    context.subscriptions.push(
+        vscode.languages.registerDefinitionProvider(documentSelector, definitionProvider)
+    );
+
+    // Register signature help provider
+    const signatureHelpProvider = new IslSignatureHelpProvider();
+    context.subscriptions.push(
+        vscode.languages.registerSignatureHelpProvider(
+            documentSelector,
+            signatureHelpProvider,
+            '(', ',', ' '
+        )
+    );
+
+    // Register inlay hints provider
+    const inlayHintsProvider = new IslInlayHintsProvider();
+    context.subscriptions.push(
+        vscode.languages.registerInlayHintsProvider(documentSelector, inlayHintsProvider)
+    );
+
+    // Register document highlight provider for control flow keyword matching
+    const highlightProvider = new IslDocumentHighlightProvider();
+    context.subscriptions.push(
+        vscode.languages.registerDocumentHighlightProvider(documentSelector, highlightProvider)
+    );
+
+    // Register code action provider
+    const codeActionProvider = new IslCodeActionProvider();
+    context.subscriptions.push(
+        vscode.languages.registerCodeActionsProvider(
+            documentSelector,
+            codeActionProvider,
+            {
+                providedCodeActionKinds: IslCodeActionProvider.providedCodeActionKinds
+            }
+        )
+    );
+
+    // Register CodeLens provider for "Run" buttons
+    const codeLensProvider = new IslCodeLensProvider();
+    context.subscriptions.push(
+        vscode.languages.registerCodeLensProvider(documentSelector, codeLensProvider)
+    );
+
+    // Register executor
+    const executor = new IslExecutor();
+
+    // Register commands
+    context.subscriptions.push(
+        vscode.commands.registerCommand('isl.validate', async () => {
+            const editor = vscode.window.activeTextEditor;
+            if (editor && editor.document.languageId === 'isl') {
+                await validator.validate(editor.document);
+                vscode.window.showInformationMessage('ISL validation complete');
+            }
+        }),
+
+        vscode.commands.registerCommand('isl.run', async () => {
+            const editor = vscode.window.activeTextEditor;
+            if (editor && editor.document.languageId === 'isl') {
+                await executor.run(editor.document);
+            }
+        }),
+
+        vscode.commands.registerCommand('isl.runWithInput', async () => {
+            const editor = vscode.window.activeTextEditor;
+            if (editor && editor.document.languageId === 'isl') {
+                await executor.runWithInput(editor.document);
+            }
+        }),
+
+        vscode.commands.registerCommand('isl.format', async () => {
+            const editor = vscode.window.activeTextEditor;
+            if (editor && editor.document.languageId === 'isl') {
+                await vscode.commands.executeCommand('editor.action.formatDocument');
+            }
+        }),
+
+        vscode.commands.registerCommand('isl.showDocumentation', () => {
+            vscode.env.openExternal(vscode.Uri.parse('https://intuit.github.io/isl/'));
+        }),
+
+        vscode.commands.registerCommand('isl.runFunction', async (uri: vscode.Uri, functionName: string, params: string) => {
+            await runIslFunction(uri, functionName, params, context);
+        }),
+
+        vscode.commands.registerCommand('isl.showUsages', async (uri: vscode.Uri, functionName: string, functionType: string) => {
+            await showUsages(uri, functionName, functionType);
+        }),
+
+        vscode.commands.registerCommand('isl.testFunction', async (uri: vscode.Uri, functionName: string, params: string) => {
+            await testFunction(uri, functionName, params, context);
+        }),
+
+        // Refactoring commands
+        vscode.commands.registerCommand('isl.refactor.extractVariable', extractVariable),
+        vscode.commands.registerCommand('isl.refactor.extractFunction', extractFunction),
+        vscode.commands.registerCommand('isl.refactor.toTemplateString', convertToTemplateString),
+
+        // Improvement commands
+        vscode.commands.registerCommand('isl.improvement.useCoalesceOperator', useCoalesceOperator),
+        vscode.commands.registerCommand('isl.improvement.useMathSum', useMathSum),
+        vscode.commands.registerCommand('isl.improvement.formatChain', formatChain),
+        vscode.commands.registerCommand('isl.improvement.formatObject', formatObject)
+    );
+
+    // Enhanced status bar item
+    const statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
+    context.subscriptions.push(statusBarItem);
+
+    // Update status bar
+    function updateStatusBar() {
+        const editor = vscode.window.activeTextEditor;
+        if (editor && editor.document.languageId === 'isl') {
+            const document = editor.document;
+            const text = document.getText();
+            
+            // Count functions and modifiers
+            const functionCount = (text.match(/^\s*(fun|modifier)\s+/gm) || []).length;
+            
+            // Get diagnostics count
+            const diagnostics = vscode.languages.getDiagnostics(document.uri);
+            const errorCount = diagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Error).length;
+            const warningCount = diagnostics.filter(d => d.severity === vscode.DiagnosticSeverity.Warning).length;
+            
+            // Build status text
+            let statusText = '$(check) ISL';
+            if (functionCount > 0) {
+                statusText += ` | ${functionCount} ${functionCount === 1 ? 'function' : 'functions'}`;
+            }
+            
+            if (errorCount > 0) {
+                statusText += ` | $(error) ${errorCount}`;
+            } else if (warningCount > 0) {
+                statusText += ` | $(warning) ${warningCount}`;
+            } else {
+                statusText += ` | $(pass) Valid`;
+            }
+            
+            statusBarItem.text = statusText;
+            statusBarItem.tooltip = `ISL Language Support\n${functionCount} functions\n${errorCount} errors, ${warningCount} warnings`;
+            statusBarItem.command = 'isl.showDocumentation';
+            statusBarItem.show();
+        } else {
+            statusBarItem.hide();
+        }
+    }
+
+    // Update status bar on various events
+    context.subscriptions.push(
+        vscode.window.onDidChangeActiveTextEditor(updateStatusBar),
+        vscode.workspace.onDidChangeTextDocument(e => {
+            if (e.document.languageId === 'isl') {
+                updateStatusBar();
+            }
+        }),
+        vscode.languages.onDidChangeDiagnostics(e => {
+            const editor = vscode.window.activeTextEditor;
+            if (editor && e.uris.some(uri => uri.toString() === editor.document.uri.toString())) {
+                updateStatusBar();
+            }
+        })
+    );
+
+    // Initial status bar update
+    updateStatusBar();
+}
+
+export function deactivate() {
+    console.log('ISL Language Support is now deactivated');
+}
+
diff --git a/plugin/src/extensions.ts b/plugin/src/extensions.ts
new file mode 100644
index 0000000..bc3a5cb
--- /dev/null
+++ b/plugin/src/extensions.ts
@@ -0,0 +1,255 @@
+import * as vscode from 'vscode';
+import * as path from 'path';
+import * as fs from 'fs';
+
+export interface IslParameter {
+    name: string;
+    type?: string;
+    description?: string;
+    optional?: boolean;
+    defaultValue?: string;
+}
+
+export interface IslFunctionDefinition {
+    name: string;
+    description?: string;
+    parameters: IslParameter[];
+    returns?: {
+        type?: string;
+        description?: string;
+    };
+    examples?: string[];
+}
+
+export interface IslModifierDefinition {
+    name: string;
+    description?: string;
+    parameters: IslParameter[];
+    returns?: {
+        type?: string;
+        description?: string;
+    };
+    examples?: string[];
+}
+
+export interface IslExtensions {
+    functions: Map;
+    modifiers: Map;
+}
+
+/**
+ * Manages loading and caching of custom ISL extensions from .islextensions files
+ */
+export class IslExtensionsManager {
+    private extensionsCache: Map = new Map();
+    private fileWatcher: vscode.FileSystemWatcher | undefined;
+    private onDidChangeEmitter = new vscode.EventEmitter();
+    
+    /**
+     * Event fired when an .islextensions file changes
+     */
+    public readonly onDidChange = this.onDidChangeEmitter.event;
+
+    constructor() {
+        this.setupFileWatcher();
+    }
+
+    /**
+     * Sets up file watcher for .islextensions files
+     */
+    private setupFileWatcher() {
+        // Watch for .islextensions files in the workspace
+        this.fileWatcher = vscode.workspace.createFileSystemWatcher('**/.islextensions');
+        
+        this.fileWatcher.onDidCreate(uri => {
+            console.log('ISL extensions file created:', uri.fsPath);
+            this.invalidateCache(uri);
+            this.onDidChangeEmitter.fire(uri);
+        });
+        
+        this.fileWatcher.onDidChange(uri => {
+            console.log('ISL extensions file changed:', uri.fsPath);
+            this.invalidateCache(uri);
+            this.onDidChangeEmitter.fire(uri);
+        });
+        
+        this.fileWatcher.onDidDelete(uri => {
+            console.log('ISL extensions file deleted:', uri.fsPath);
+            this.invalidateCache(uri);
+            this.onDidChangeEmitter.fire(uri);
+        });
+    }
+
+    /**
+     * Invalidates the cache for a specific extensions file
+     */
+    private invalidateCache(uri: vscode.Uri) {
+        const workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
+        if (workspaceFolder) {
+            this.extensionsCache.delete(workspaceFolder.uri.fsPath);
+        }
+    }
+
+    /**
+     * Gets extensions for a given document's workspace
+     */
+    public async getExtensionsForDocument(document: vscode.TextDocument): Promise {
+        const workspaceFolder = vscode.workspace.getWorkspaceFolder(document.uri);
+        if (!workspaceFolder) {
+            return this.createEmptyExtensions();
+        }
+
+        // Check cache first
+        const cached = this.extensionsCache.get(workspaceFolder.uri.fsPath);
+        if (cached) {
+            return cached;
+        }
+
+        // Load extensions file
+        const extensions = await this.loadExtensionsForWorkspace(workspaceFolder);
+        this.extensionsCache.set(workspaceFolder.uri.fsPath, extensions);
+        return extensions;
+    }
+
+    /**
+     * Loads extensions from .islextensions file in the workspace
+     */
+    private async loadExtensionsForWorkspace(workspaceFolder: vscode.WorkspaceFolder): Promise {
+        const extensionsPath = path.join(workspaceFolder.uri.fsPath, '.islextensions');
+        
+        try {
+            if (!fs.existsSync(extensionsPath)) {
+                return this.createEmptyExtensions();
+            }
+
+            const content = fs.readFileSync(extensionsPath, 'utf-8');
+            return this.parseExtensionsFile(content, extensionsPath);
+        } catch (error) {
+            console.error('Error loading ISL extensions:', error);
+            vscode.window.showWarningMessage(`Failed to load .islextensions file: ${error instanceof Error ? error.message : String(error)}`);
+            return this.createEmptyExtensions();
+        }
+    }
+
+    /**
+     * Parses the .islextensions file content
+     */
+    private parseExtensionsFile(content: string, filePath: string): IslExtensions {
+        const extensions = this.createEmptyExtensions();
+
+        try {
+            const data = JSON.parse(content);
+
+            // Parse functions
+            if (data.functions && Array.isArray(data.functions)) {
+                for (const func of data.functions) {
+                    if (!func.name || typeof func.name !== 'string') {
+                        console.warn('Skipping function without name in .islextensions');
+                        continue;
+                    }
+
+                    const functionDef: IslFunctionDefinition = {
+                        name: func.name,
+                        description: func.description || func.desc || '',
+                        parameters: this.parseParameters(func.parameters || func.params || []),
+                        returns: func.returns ? {
+                            type: func.returns.type,
+                            description: func.returns.description || func.returns.desc
+                        } : undefined,
+                        examples: Array.isArray(func.examples) ? func.examples : undefined
+                    };
+
+                    extensions.functions.set(func.name, functionDef);
+                }
+            }
+
+            // Parse modifiers
+            if (data.modifiers && Array.isArray(data.modifiers)) {
+                for (const mod of data.modifiers) {
+                    if (!mod.name || typeof mod.name !== 'string') {
+                        console.warn('Skipping modifier without name in .islextensions');
+                        continue;
+                    }
+
+                    const modifierDef: IslModifierDefinition = {
+                        name: mod.name,
+                        description: mod.description || mod.desc || '',
+                        parameters: this.parseParameters(mod.parameters || mod.params || []),
+                        returns: mod.returns ? {
+                            type: mod.returns.type,
+                            description: mod.returns.description || mod.returns.desc
+                        } : undefined,
+                        examples: Array.isArray(mod.examples) ? mod.examples : undefined
+                    };
+
+                    extensions.modifiers.set(mod.name, modifierDef);
+                }
+            }
+
+            console.log(`Loaded ${extensions.functions.size} custom functions and ${extensions.modifiers.size} custom modifiers from ${filePath}`);
+        } catch (error) {
+            console.error('Error parsing .islextensions file:', error);
+            throw new Error(`Failed to parse .islextensions: ${error instanceof Error ? error.message : String(error)}`);
+        }
+
+        return extensions;
+    }
+
+    /**
+     * Parses parameter definitions
+     */
+    private parseParameters(params: any[]): IslParameter[] {
+        if (!Array.isArray(params)) {
+            return [];
+        }
+
+        return params.map(param => {
+            // Support both object and string formats
+            if (typeof param === 'string') {
+                return { name: param };
+            }
+
+            return {
+                name: param.name || '',
+                type: param.type,
+                description: param.description || param.desc,
+                optional: param.optional === true,
+                defaultValue: param.default || param.defaultValue
+            };
+        });
+    }
+
+    /**
+     * Creates an empty extensions object
+     */
+    private createEmptyExtensions(): IslExtensions {
+        return {
+            functions: new Map(),
+            modifiers: new Map()
+        };
+    }
+
+    /**
+     * Reloads all cached extensions
+     */
+    public async reloadAll(): Promise {
+        this.extensionsCache.clear();
+        
+        // Reload for all open ISL documents
+        for (const document of vscode.workspace.textDocuments) {
+            if (document.languageId === 'isl') {
+                await this.getExtensionsForDocument(document);
+            }
+        }
+    }
+
+    /**
+     * Disposes the manager and cleans up resources
+     */
+    public dispose() {
+        this.fileWatcher?.dispose();
+        this.onDidChangeEmitter.dispose();
+        this.extensionsCache.clear();
+    }
+}
+
diff --git a/plugin/src/formatter.ts b/plugin/src/formatter.ts
new file mode 100644
index 0000000..7838782
--- /dev/null
+++ b/plugin/src/formatter.ts
@@ -0,0 +1,765 @@
+import * as vscode from 'vscode';
+
+export class IslDocumentFormatter implements vscode.DocumentFormattingEditProvider, vscode.DocumentRangeFormattingEditProvider {
+    
+    provideDocumentFormattingEdits(
+        document: vscode.TextDocument,
+        options: vscode.FormattingOptions,
+        token: vscode.CancellationToken
+    ): vscode.TextEdit[] {
+        const config = vscode.workspace.getConfiguration('isl.formatting');
+        if (!config.get('enabled', true)) {
+            return [];
+        }
+
+        const fullRange = new vscode.Range(
+            document.positionAt(0),
+            document.positionAt(document.getText().length)
+        );
+        
+        const formatted = this.formatIslCode(document.getText(), options);
+        return [vscode.TextEdit.replace(fullRange, formatted)];
+    }
+
+    provideDocumentRangeFormattingEdits(
+        document: vscode.TextDocument,
+        range: vscode.Range,
+        options: vscode.FormattingOptions,
+        token: vscode.CancellationToken
+    ): vscode.TextEdit[] {
+        const config = vscode.workspace.getConfiguration('isl.formatting');
+        if (!config.get('enabled', true)) {
+            return [];
+        }
+
+        const text = document.getText(range);
+        const formatted = this.formatIslCode(text, options);
+        return [vscode.TextEdit.replace(range, formatted)];
+    }
+
+    private formatIslCode(code: string, options: vscode.FormattingOptions): string {
+        const config = vscode.workspace.getConfiguration('isl.formatting');
+        const indentSize = config.get('indentSize', 4);
+        const useTabs = config.get('useTabs', false);
+        const indentChar = useTabs ? '\t' : ' '.repeat(indentSize);
+        const alignProperties = config.get('alignProperties', false);
+
+        let formatted = '';
+        let indentLevel = 0;
+        let openInlineControlFlow: string[] = []; // Track stack of open inline control flow types
+
+        const lines = code.split('\n');
+        
+        // First pass: identify lines that are inside multi-line backtick strings
+        const isInsideMultiLineString: boolean[] = new Array(lines.length).fill(false);
+        let inMultiLineString = false;
+        let backtickCount = 0;
+        
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            
+            // Count backticks in this line (excluding escaped ones)
+            let tempBacktickCount = 0;
+            for (let j = 0; j < line.length; j++) {
+                if (line[j] === '`' && (j === 0 || line[j - 1] !== '\\')) {
+                    tempBacktickCount++;
+                }
+            }
+            
+            // Track if we're entering or exiting a multi-line string
+            if (!inMultiLineString && tempBacktickCount % 2 === 1) {
+                // Started a string on this line, check if it closes on same line
+                inMultiLineString = true;
+                backtickCount = tempBacktickCount;
+            } else if (inMultiLineString) {
+                // We're inside a multi-line string
+                isInsideMultiLineString[i] = true;
+                backtickCount += tempBacktickCount;
+                
+                // If we now have an even number of backticks, the string is closed
+                if (backtickCount % 2 === 0) {
+                    inMultiLineString = false;
+                    backtickCount = 0;
+                }
+            }
+        }
+        
+        // Process lines: normalize pipe spacing but don't split chains
+        const processedLines: string[] = [];
+        for (let i = 0; i < lines.length; i++) {
+            // If this line is inside a multi-line string, preserve it as-is (only trim trailing spaces)
+            if (isInsideMultiLineString[i]) {
+                processedLines.push(lines[i].trimEnd());
+                continue;
+            }
+            
+            let line = lines[i].trim();
+            
+            // Normalize pipe spacing (ensure space after pipe)
+            line = this.normalizePipeSpacing(line);
+            
+            // Normalize function/modifier declaration parameter spacing
+            line = this.normalizeFunctionParameters(line);
+            
+            // Normalize control flow statement parameter spacing
+            line = this.normalizeControlFlowParameters(line);
+            
+            // Collapse empty objects and arrays
+            line = this.collapseEmptyBrackets(line);
+            
+            // Normalize property assignments (key: value)
+            line = this.normalizePropertyAssignments(line);
+            
+            // Normalize variable assignments (= with spaces)
+            line = this.normalizeVariableAssignments(line);
+            
+            // Normalize function calls with object parameters
+            line = this.normalizeFunctionObjectParameters(line);
+            
+            processedLines.push(line);
+        }
+
+        // Indent and format
+        for (let i = 0; i < processedLines.length; i++) {
+            const trimmedLine = processedLines[i];
+
+            // If this line is inside a multi-line string, preserve it as-is
+            if (isInsideMultiLineString[i]) {
+                formatted += trimmedLine + '\n';
+                continue;
+            }
+
+            // Reset indent to 0 for function/modifier declarations (always start at column zero)
+            if (trimmedLine.match(/^(fun|modifier)\s/)) {
+                indentLevel = 0;
+            }
+
+            // Handle line comments
+            if (trimmedLine.startsWith('//') || trimmedLine.startsWith('#')) {
+                formatted += indentChar.repeat(indentLevel) + trimmedLine + '\n';
+                continue;
+            }
+
+            // Skip empty lines but preserve them
+            if (trimmedLine === '') {
+                formatted += '\n';
+                continue;
+            }
+
+            // Adjust indent for closing braces/brackets
+            if (trimmedLine.match(/^[\}\]\)]/) && indentLevel > 0) {
+                indentLevel--;
+            }
+            
+            // If line ends with }; or }], and we have open inline control flow,
+            // this closes the inline expression - decrease indent
+            // BUT: for switch statements, }; only closes a case, not the switch itself
+            if ((trimmedLine.match(/^[\}\]].*;$/) || trimmedLine.match(/^[\}\]],$/)) && openInlineControlFlow.length > 0) {
+                const topControlFlow = openInlineControlFlow[openInlineControlFlow.length - 1];
+                // Only close if it's NOT a switch statement
+                if (topControlFlow !== 'switch') {
+                    if (indentLevel > 0) {
+                        indentLevel--;
+                        openInlineControlFlow.pop();
+                    }
+                }
+            }
+            
+            // Check if this line completes an inline if/switch with 'else' but no explicit end keyword
+            // Pattern: ] else value, or ) else value, etc. (ends with terminator)
+            // This closes the inline control flow
+            if (openInlineControlFlow.length > 0 && trimmedLine.match(/\s+else\s+[^,;]+[,;]$/)) {
+                if (indentLevel > 0) {
+                    indentLevel--;
+                    openInlineControlFlow.pop();
+                }
+            }
+
+            // Special handling for control flow endings
+            if (trimmedLine.match(/^(endif|endfor|endwhile|endswitch)/)) {
+                if (indentLevel > 0) indentLevel--;
+                if (openInlineControlFlow.length > 0) openInlineControlFlow.pop();
+            }
+
+            // Handle 'else' - decrease then increase indent
+            if (trimmedLine === 'else' && indentLevel > 0) {
+                indentLevel--;
+                formatted += indentChar.repeat(indentLevel) + trimmedLine + '\n';
+                indentLevel++;
+                continue;
+            }
+
+            // Check if this line is a continuation of a modifier chain (starts with |)
+            const isModifierContinuation = trimmedLine.startsWith('|');
+            const extraIndent = isModifierContinuation ? 1 : 0;
+
+            // Add indentation (with extra indent for modifier continuations)
+            formatted += indentChar.repeat(indentLevel + extraIndent) + trimmedLine;
+
+            // Adjust indent for opening braces/brackets
+            if (trimmedLine.match(/[\{\[\(]$/)) {
+                indentLevel++;
+            }
+
+            // Special handling for control flow beginnings (but not fun/modifier)
+            // Check for both block statements (start of line) and inline statements (after : or = or ->)
+            // Match either space or opening paren after keyword: if( or if (
+            const blockControlFlow = trimmedLine.match(/^(if|foreach|while|switch|parallel)[\s(]/);
+            const inlineControlFlow = trimmedLine.match(/[=:>]\s*(if|foreach|while|switch)[\s(]/);
+            
+            if (blockControlFlow || inlineControlFlow) {
+                if (!trimmedLine.includes('endif') && !trimmedLine.includes('endfor') && 
+                    !trimmedLine.includes('endwhile') && !trimmedLine.includes('endswitch')) {
+                    // Don't increase indent if line ends with { (brace handles it)
+                    // Don't increase indent if inline expression is complete on one line (; or , at end)
+                    const endsWithBrace = trimmedLine.endsWith('{');
+                    const endsWithTerminator = trimmedLine.endsWith(';') || trimmedLine.endsWith(',');
+                    
+                    // For inline expressions: if they end with a terminator, they're complete
+                    // For block expressions: they never end with terminators, so this won't affect them
+                    const isCompleteLine = inlineControlFlow && endsWithTerminator;
+                    
+                    if (!endsWithBrace && !isCompleteLine) {
+                        indentLevel++;
+                        // Track open inline control flow type (will be closed by }; or endif)
+                        if (inlineControlFlow) {
+                            // Extract the control flow type from the match
+                            const controlFlowType = inlineControlFlow[0].match(/(if|foreach|while|switch)/)?.[1] || 'unknown';
+                            openInlineControlFlow.push(controlFlowType);
+                        }
+                    }
+                }
+            }
+            
+            // Note: fun/modifier declarations don't increase indent themselves
+            // The opening { (whether on same line or next line) handles the indentation
+
+            // Add newline
+            if (i < processedLines.length - 1) {
+                formatted += '\n';
+            }
+        }
+
+        // Align properties if enabled
+        if (alignProperties) {
+            formatted = this.alignObjectProperties(formatted);
+        }
+
+        return formatted;
+    }
+    
+    private normalizePipeSpacing(line: string): string {
+        // Skip comments and strings
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+        
+        // Replace | with | (with space) but be careful with strings
+        // This regex finds pipes that are not inside strings
+        let result = '';
+        let inString = false;
+        let stringChar = '';
+        let i = 0;
+        
+        while (i < line.length) {
+            const char = line[i];
+            const nextChar = line[i + 1] || '';
+            
+            // Track string boundaries
+            if ((char === '"' || char === "'" || char === '`') && (i === 0 || line[i - 1] !== '\\')) {
+                if (!inString) {
+                    inString = true;
+                    stringChar = char;
+                } else if (char === stringChar) {
+                    inString = false;
+                    stringChar = '';
+                }
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // If we find a pipe outside of strings
+            if (char === '|' && !inString) {
+                // Add pipe with space after
+                result += '| ';
+                // Skip any existing spaces after the pipe
+                while (i + 1 < line.length && line[i + 1] === ' ') {
+                    i++;
+                }
+                i++;
+                continue;
+            }
+            
+            result += char;
+            i++;
+        }
+        
+        return result;
+    }
+
+    private normalizeFunctionParameters(line: string): string {
+        // Skip comments
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+
+        // Match function/modifier declarations: fun name(...) or modifier name(...)
+        const functionMatch = line.match(/^(fun|modifier)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(([^)]*)\)/);
+        if (!functionMatch) {
+            return line;
+        }
+
+        const keyword = functionMatch[1];     // 'fun' or 'modifier'
+        const name = functionMatch[2];        // function name
+        const params = functionMatch[3];      // parameters inside ()
+        const afterParams = line.substring(functionMatch[0].length); // everything after )
+
+        // Trim the parameters
+        const trimmedParams = params.trim();
+
+        // If no parameters, no spaces
+        if (trimmedParams === '') {
+            return `${keyword} ${name}()${afterParams}`;
+        }
+
+        // If there are parameters, add spaces after ( and before )
+        // Also normalize spaces around commas
+        const normalizedParams = trimmedParams
+            .split(',')
+            .map(p => p.trim())
+            .join(', ');
+
+        return `${keyword} ${name}( ${normalizedParams} )${afterParams}`;
+    }
+
+    private normalizeControlFlowParameters(line: string): string {
+        // Skip comments
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+
+        // Normalize if, switch, while, foreach statements
+        // Pattern: keyword( condition ) or keyword ( condition )
+        const keywords = ['if', 'switch', 'while'];
+        
+        for (const keyword of keywords) {
+            // Match keyword followed by parentheses
+            const regex = new RegExp(`\\b(${keyword})\\s*\\(([^)]*)\\)`, 'g');
+            line = line.replace(regex, (match, kw, content) => {
+                const trimmedContent = content.trim();
+                // If no content, no spaces: if()
+                if (trimmedContent === '') {
+                    return `${kw}()`;
+                }
+                // Otherwise add spaces: if ( condition )
+                return `${kw} ( ${trimmedContent} )`;
+            });
+        }
+
+        return line;
+    }
+    
+    private collapseEmptyBrackets(line: string): string {
+        // Skip comments
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+        
+        let result = '';
+        let inString = false;
+        let stringChar = '';
+        let i = 0;
+        
+        while (i < line.length) {
+            const char = line[i];
+            
+            // Track string boundaries
+            if ((char === '"' || char === "'" || char === '`') && (i === 0 || line[i - 1] !== '\\')) {
+                if (!inString) {
+                    inString = true;
+                    stringChar = char;
+                } else if (char === stringChar) {
+                    inString = false;
+                    stringChar = '';
+                }
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // If we're in a string, just copy the character
+            if (inString) {
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // Check for empty objects or arrays
+            if (char === '{' || char === '[') {
+                const closingChar = char === '{' ? '}' : ']';
+                let j = i + 1;
+                
+                // Skip whitespace
+                while (j < line.length && (line[j] === ' ' || line[j] === '\t')) {
+                    j++;
+                }
+                
+                // Check if next non-whitespace char is the closing bracket
+                if (j < line.length && line[j] === closingChar) {
+                    // Collapse: output {}, []
+                    result += char + closingChar;
+                    i = j + 1;
+                    continue;
+                }
+            }
+            
+            result += char;
+            i++;
+        }
+        
+        return result;
+    }
+    
+    private alignObjectProperties(code: string): string {
+        const lines = code.split('\n');
+        const result: string[] = [];
+        let inObject = false;
+        let objectLines: { indent: string, key: string, value: string, fullLine: string }[] = [];
+        
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            const trimmed = line.trim();
+            
+            // Detect object start
+            if (trimmed === '{' || trimmed.endsWith('{')) {
+                if (objectLines.length > 0) {
+                    // Flush previous object
+                    result.push(...this.alignLines(objectLines));
+                    objectLines = [];
+                }
+                result.push(line);
+                inObject = true;
+                continue;
+            }
+            
+            // Detect object end
+            if (trimmed === '}' || trimmed.startsWith('}')) {
+                if (objectLines.length > 0) {
+                    result.push(...this.alignLines(objectLines));
+                    objectLines = [];
+                }
+                result.push(line);
+                inObject = false;
+                continue;
+            }
+            
+            // Collect object properties
+            if (inObject && trimmed.match(/^[a-zA-Z_`\$"][^:]*:\s*.+/)) {
+                const match = line.match(/^(\s*)([a-zA-Z_`\$"][^:]*):\s*(.+)/);
+                if (match) {
+                    objectLines.push({
+                        indent: match[1],
+                        key: match[2],
+                        value: match[3],
+                        fullLine: line
+                    });
+                    continue;
+                }
+            }
+            
+            // Not an object property - flush and add
+            if (objectLines.length > 0) {
+                result.push(...this.alignLines(objectLines));
+                objectLines = [];
+            }
+            result.push(line);
+        }
+        
+        // Flush remaining
+        if (objectLines.length > 0) {
+            result.push(...this.alignLines(objectLines));
+        }
+        
+        return result.join('\n');
+    }
+    
+    private alignLines(lines: { indent: string, key: string, value: string }[]): string[] {
+        if (lines.length === 0) {
+            return [];
+        }
+        
+        // Find max key length
+        const maxKeyLength = Math.max(...lines.map(l => l.key.length));
+        
+        // Align all lines
+        return lines.map(l => {
+            const padding = ' '.repeat(maxKeyLength - l.key.length);
+            return `${l.indent}${l.key}:${padding} ${l.value}`;
+        });
+    }
+    
+    /**
+     * Rule 1: For property assignments using :, colon should be next to property with one space before value
+     * Example: name: "value" (not name : "value" or name:"value")
+     */
+    private normalizePropertyAssignments(line: string): string {
+        // Skip comments
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+        
+        let result = '';
+        let inString = false;
+        let stringChar = '';
+        let i = 0;
+        
+        while (i < line.length) {
+            const char = line[i];
+            
+            // Track string boundaries
+            if ((char === '"' || char === "'" || char === '`') && (i === 0 || line[i - 1] !== '\\')) {
+                if (!inString) {
+                    inString = true;
+                    stringChar = char;
+                } else if (char === stringChar) {
+                    inString = false;
+                    stringChar = '';
+                }
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // If we're in a string, just copy the character
+            if (inString) {
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // Look for : used in property assignments
+            if (char === ':') {
+                // Check if this looks like a property assignment (not a ternary operator)
+                // Property assignments have an identifier before the colon
+                let j = result.length - 1;
+                
+                // Skip trailing spaces before colon
+                while (j >= 0 && result[j] === ' ') {
+                    result = result.substring(0, j);
+                    j--;
+                }
+                
+                // Check if there's an identifier before (property name)
+                const beforeColon = result.match(/[a-zA-Z_$][a-zA-Z0-9_]*$/);
+                if (beforeColon) {
+                    // This looks like a property assignment
+                    // Add colon without space, then ensure one space after
+                    result += ': ';
+                    i++;
+                    
+                    // Skip any existing spaces after the colon
+                    while (i < line.length && line[i] === ' ') {
+                        i++;
+                    }
+                    continue;
+                }
+            }
+            
+            result += char;
+            i++;
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Rule 2: For variable assignments using =, ensure spaces on both sides
+     * Example: $var = value (not $var=value or $var =value)
+     */
+    private normalizeVariableAssignments(line: string): string {
+        // Skip comments
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+        
+        let result = '';
+        let inString = false;
+        let stringChar = '';
+        let i = 0;
+        
+        while (i < line.length) {
+            const char = line[i];
+            const nextChar = line[i + 1] || '';
+            
+            // Track string boundaries
+            if ((char === '"' || char === "'" || char === '`') && (i === 0 || line[i - 1] !== '\\')) {
+                if (!inString) {
+                    inString = true;
+                    stringChar = char;
+                } else if (char === stringChar) {
+                    inString = false;
+                    stringChar = '';
+                }
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // If we're in a string, just copy the character
+            if (inString) {
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // Look for = (but not ==, !=, >=, <=, =>)
+            if (char === '=' && nextChar !== '=' && (i === 0 || line[i - 1] !== '!' && line[i - 1] !== '>' && line[i - 1] !== '<' && line[i - 1] !== '=')) {
+                // Not an arrow function (=>)
+                if (nextChar !== '>') {
+                    // Remove trailing spaces before =
+                    while (result.length > 0 && result[result.length - 1] === ' ') {
+                        result = result.substring(0, result.length - 1);
+                    }
+                    
+                    // Add = with spaces on both sides
+                    result += ' = ';
+                    i++;
+                    
+                    // Skip any existing spaces after =
+                    while (i < line.length && line[i] === ' ') {
+                        i++;
+                    }
+                    continue;
+                }
+            }
+            
+            result += char;
+            i++;
+        }
+        
+        return result;
+    }
+    
+    /**
+     * Rule 3: For function calls with object {} as first parameter, keep braces next to parentheses
+     * Example: @.source.name({ key: value }) (not @.source.name( { key: value } ))
+     */
+    private normalizeFunctionObjectParameters(line: string): string {
+        // Skip comments
+        if (line.trim().startsWith('//') || line.trim().startsWith('#')) {
+            return line;
+        }
+        
+        let result = '';
+        let inString = false;
+        let stringChar = '';
+        let i = 0;
+        
+        while (i < line.length) {
+            const char = line[i];
+            
+            // Track string boundaries
+            if ((char === '"' || char === "'" || char === '`') && (i === 0 || line[i - 1] !== '\\')) {
+                if (!inString) {
+                    inString = true;
+                    stringChar = char;
+                } else if (char === stringChar) {
+                    inString = false;
+                    stringChar = '';
+                }
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // If we're in a string, just copy the character
+            if (inString) {
+                result += char;
+                i++;
+                continue;
+            }
+            
+            // Look for opening parenthesis that's part of a function call
+            if (char === '(' && i > 0) {
+                // Check if this is preceded by an identifier (function name)
+                let j = i - 1;
+                while (j >= 0 && line[j] === ' ') {
+                    j--;
+                }
+                
+                const beforeParen = line.substring(0, j + 1);
+                const isAfterIdentifier = /[a-zA-Z_$\.]$/.test(beforeParen);
+                
+                if (isAfterIdentifier) {
+                    result += '(';
+                    i++;
+                    
+                    // Temporarily skip spaces to check what's next
+                    let tempI = i;
+                    while (tempI < line.length && line[tempI] === ' ') {
+                        tempI++;
+                    }
+                    
+                    // Check if the first parameter is an object {
+                    if (tempI < line.length && line[tempI] === '{') {
+                        // Skip the spaces (move i forward)
+                        i = tempI;
+                        // Find matching closing }
+                        let depth = 1;
+                        let k = i + 1;
+                        let tempInString = false;
+                        let tempStringChar = '';
+                        
+                        while (k < line.length && depth > 0) {
+                            const c = line[k];
+                            
+                            // Track strings
+                            if ((c === '"' || c === "'" || c === '`') && (k === 0 || line[k - 1] !== '\\')) {
+                                if (!tempInString) {
+                                    tempInString = true;
+                                    tempStringChar = c;
+                                } else if (c === tempStringChar) {
+                                    tempInString = false;
+                                    tempStringChar = '';
+                                }
+                            }
+                            
+                            if (!tempInString) {
+                                if (c === '{') depth++;
+                                if (c === '}') depth--;
+                            }
+                            k++;
+                        }
+                        
+                        if (depth === 0) {
+                            // Extract the object content
+                            const objectContent = line.substring(i, k);
+                            result += objectContent;
+                            i = k;
+                            
+                            // Skip spaces after }
+                            while (i < line.length && line[i] === ' ') {
+                                i++;
+                            }
+                            
+                            // If next char is ), add it without space
+                            if (i < line.length && line[i] === ')') {
+                                result += ')';
+                                i++;
+                            }
+                            continue;
+                        }
+                    }
+                    continue;
+                }
+            }
+            
+            result += char;
+            i++;
+        }
+        
+        return result;
+    }
+}
+
diff --git a/plugin/src/highlights.ts b/plugin/src/highlights.ts
new file mode 100644
index 0000000..5dbc7d1
--- /dev/null
+++ b/plugin/src/highlights.ts
@@ -0,0 +1,260 @@
+import * as vscode from 'vscode';
+
+export class IslDocumentHighlightProvider implements vscode.DocumentHighlightProvider {
+    
+    provideDocumentHighlights(
+        document: vscode.TextDocument,
+        position: vscode.Position,
+        token: vscode.CancellationToken
+    ): vscode.DocumentHighlight[] | undefined {
+        const wordRange = document.getWordRangeAtPosition(position);
+        if (!wordRange) {
+            return undefined;
+        }
+
+        const word = document.getText(wordRange);
+
+        // Check if the word is a control flow keyword
+        const controlFlowPairs: { [key: string]: { match: string, isOpening: boolean } } = {
+            'if': { match: 'endif', isOpening: true },
+            'endif': { match: 'if', isOpening: false },
+            'else': { match: 'if', isOpening: false }, // else matches with if
+            'foreach': { match: 'endfor', isOpening: true },
+            'endfor': { match: 'foreach', isOpening: false },
+            'while': { match: 'endwhile', isOpening: true },
+            'endwhile': { match: 'while', isOpening: false },
+            'switch': { match: 'endswitch', isOpening: true },
+            'endswitch': { match: 'switch', isOpening: false }
+        };
+
+        if (!controlFlowPairs[word]) {
+            return undefined;
+        }
+
+        const { match: matchingKeyword, isOpening } = controlFlowPairs[word];
+        
+        // Special handling for if/else/endif - highlight all three
+        if (word === 'if' || word === 'else' || word === 'endif') {
+            return this.findIfElseEndifHighlights(document, position.line, word);
+        }
+        
+        // Find the matching keyword for other control flow
+        const matchPosition = this.findMatchingKeyword(
+            document,
+            position.line,
+            word,
+            matchingKeyword,
+            isOpening
+        );
+
+        if (!matchPosition) {
+            return undefined;
+        }
+
+        // Return highlights for both keywords
+        return [
+            new vscode.DocumentHighlight(wordRange, vscode.DocumentHighlightKind.Text),
+            new vscode.DocumentHighlight(
+                new vscode.Range(
+                    matchPosition,
+                    new vscode.Position(matchPosition.line, matchPosition.character + matchingKeyword.length)
+                ),
+                vscode.DocumentHighlightKind.Text
+            )
+        ];
+    }
+
+    private findMatchingKeyword(
+        document: vscode.TextDocument,
+        startLine: number,
+        keyword: string,
+        matchKeyword: string,
+        searchForward: boolean
+    ): vscode.Position | undefined {
+        const text = document.getText();
+        const lines = text.split('\n');
+        let depth = 0;
+
+        const increment = searchForward ? 1 : -1;
+        const start = searchForward ? startLine : startLine;
+        const end = searchForward ? lines.length : -1;
+
+        for (let i = start; searchForward ? i < end : i > end; i += increment) {
+            const line = lines[i];
+            
+            // Skip comments
+            const commentIndex = Math.min(
+                line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+                line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+            );
+            const codeLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+            // Find keywords in this line
+            const keywordRegex = new RegExp(`\\b${keyword}\\b`, 'g');
+            const matchKeywordRegex = new RegExp(`\\b${matchKeyword}\\b`, 'g');
+
+            let match;
+
+            // For the first line (where cursor is), skip the current keyword position
+            const currentLineMatches: Array<{ keyword: string, index: number }> = [];
+
+            // Find all opening keywords
+            while ((match = keywordRegex.exec(codeLine)) !== null) {
+                if (i !== startLine) { // Not on the same line as cursor
+                    currentLineMatches.push({ keyword: keyword, index: match.index });
+                }
+            }
+
+            // Find all closing keywords
+            while ((match = matchKeywordRegex.exec(codeLine)) !== null) {
+                currentLineMatches.push({ keyword: matchKeyword, index: match.index });
+            }
+
+            // Sort by index
+            currentLineMatches.sort((a, b) => a.index - b.index);
+
+            // Process matches
+            for (const m of currentLineMatches) {
+                if (m.keyword === keyword) {
+                    depth++;
+                } else if (m.keyword === matchKeyword) {
+                    if (depth === 0) {
+                        // Found the match!
+                        return new vscode.Position(i, m.index);
+                    }
+                    depth--;
+                }
+            }
+        }
+
+        return undefined;
+    }
+
+    private findIfElseEndifHighlights(
+        document: vscode.TextDocument,
+        startLine: number,
+        word: string
+    ): vscode.DocumentHighlight[] | undefined {
+        const text = document.getText();
+        const lines = text.split('\n');
+        const highlights: vscode.DocumentHighlight[] = [];
+        let depth = 0;
+        let foundIf = false;
+        let ifPosition: vscode.Position | undefined;
+
+        // Search backwards to find the matching 'if' if we're on 'else' or 'endif'
+        if (word === 'else' || word === 'endif') {
+            for (let i = startLine; i >= 0; i--) {
+                const line = lines[i];
+                const commentIndex = Math.min(
+                    line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+                    line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+                );
+                const codeLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+                // Count endif keywords (increase depth when going backwards)
+                const endifMatches = codeLine.match(/\bendif\b/g);
+                if (endifMatches && i !== startLine) {
+                    depth += endifMatches.length;
+                }
+
+                // Count if keywords (decrease depth when going backwards)
+                const ifMatches = Array.from(codeLine.matchAll(/\bif[\s(]/g));
+                for (const match of ifMatches) {
+                    if (depth === 0) {
+                        ifPosition = new vscode.Position(i, match.index);
+                        foundIf = true;
+                        break;
+                    }
+                    depth--;
+                }
+
+                if (foundIf) break;
+            }
+
+            if (!ifPosition) {
+                return undefined;
+            }
+        } else {
+            // We're on 'if', use current position
+            const currentLine = lines[startLine];
+            const ifMatch = currentLine.match(/\bif[\s(]/);
+            if (ifMatch) {
+                ifPosition = new vscode.Position(startLine, ifMatch.index!);
+            } else {
+                return undefined;
+            }
+        }
+
+        // Now search forward from the 'if' position to find 'else' and 'endif'
+        depth = 0;
+        let elsePosition: vscode.Position | undefined;
+        let endifPosition: vscode.Position | undefined;
+
+        for (let i = ifPosition.line; i < lines.length; i++) {
+            const line = lines[i];
+            const commentIndex = Math.min(
+                line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+                line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+            );
+            const codeLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+            // Count if keywords (increase depth)
+            const ifMatches = Array.from(codeLine.matchAll(/\bif[\s(]/g));
+            for (const match of ifMatches) {
+                if (i !== ifPosition.line) {
+                    depth++;
+                }
+            }
+
+            // Look for 'else' at the same depth
+            if (depth === 0 && !elsePosition) {
+                const elseMatch = codeLine.match(/\belse\b/);
+                if (elseMatch && i !== ifPosition.line) {
+                    elsePosition = new vscode.Position(i, elseMatch.index!);
+                }
+            }
+
+            // Count endif keywords (decrease depth)
+            const endifMatch = codeLine.match(/\bendif\b/);
+            if (endifMatch) {
+                if (depth === 0) {
+                    endifPosition = new vscode.Position(i, endifMatch.index!);
+                    break;
+                }
+                depth--;
+            }
+        }
+
+        // Add highlights
+        if (ifPosition) {
+            highlights.push(
+                new vscode.DocumentHighlight(
+                    new vscode.Range(ifPosition, new vscode.Position(ifPosition.line, ifPosition.character + 2)),
+                    vscode.DocumentHighlightKind.Text
+                )
+            );
+        }
+
+        if (elsePosition) {
+            highlights.push(
+                new vscode.DocumentHighlight(
+                    new vscode.Range(elsePosition, new vscode.Position(elsePosition.line, elsePosition.character + 4)),
+                    vscode.DocumentHighlightKind.Text
+                )
+            );
+        }
+
+        if (endifPosition) {
+            highlights.push(
+                new vscode.DocumentHighlight(
+                    new vscode.Range(endifPosition, new vscode.Position(endifPosition.line, endifPosition.character + 5)),
+                    vscode.DocumentHighlightKind.Text
+                )
+            );
+        }
+
+        return highlights.length > 0 ? highlights : undefined;
+    }
+}
+
diff --git a/plugin/src/hover.ts b/plugin/src/hover.ts
new file mode 100644
index 0000000..69ea681
--- /dev/null
+++ b/plugin/src/hover.ts
@@ -0,0 +1,586 @@
+import * as vscode from 'vscode';
+import { IslExtensionsManager } from './extensions';
+
+export class IslHoverProvider implements vscode.HoverProvider {
+    
+    constructor(private extensionsManager: IslExtensionsManager) {}
+    
+    async provideHover(
+        document: vscode.TextDocument,
+        position: vscode.Position,
+        token: vscode.CancellationToken
+    ): Promise {
+        const range = document.getWordRangeAtPosition(position);
+        if (!range) {
+            return undefined;
+        }
+
+        const word = document.getText(range);
+        const line = document.lineAt(position.line).text;
+
+        // Load custom extensions
+        const extensions = await this.extensionsManager.getExtensionsForDocument(document);
+
+        // Check what kind of token we're hovering over
+        if (this.isKeyword(word)) {
+            return this.getKeywordHover(word);
+        } else if (line.includes('@.' + word)) {
+            return this.getServiceHover(word);
+        } else if (this.isModifier(word, line)) {
+            // Check if it's a custom modifier first
+            if (extensions.modifiers.has(word)) {
+                return this.getCustomModifierHover(extensions.modifiers.get(word)!);
+            }
+            return this.getModifierHover(word, line);
+        } else if (line.includes('$' + word)) {
+            return this.getVariableHover(word, document);
+        } else if (line.includes('@.This.' + word) || line.match(new RegExp(`@\\.${word}\\s*\\(`))) {
+            // Check if it's a custom function
+            if (extensions.functions.has(word)) {
+                return this.getCustomFunctionHover(extensions.functions.get(word)!);
+            }
+        }
+
+        return undefined;
+    }
+
+    private getCustomFunctionHover(func: import('./extensions').IslFunctionDefinition): vscode.Hover {
+        const md = new vscode.MarkdownString();
+        md.isTrusted = true;
+        
+        // Build signature
+        const params = func.parameters.map(p => {
+            let result = `${p.name}`;
+            if (p.type) {
+                result += `: ${p.type}`;
+            }
+            if (p.optional) {
+                result += '?';
+            }
+            return result;
+        }).join(', ');
+        
+        const returnType = func.returns?.type ? `: ${func.returns.type}` : '';
+        md.appendMarkdown(`**\`${func.name}(${params})${returnType}\`** *(custom function)*\n\n`);
+        
+        if (func.description) {
+            md.appendMarkdown(`${func.description}\n\n`);
+        }
+        
+        if (func.parameters.length > 0) {
+            md.appendMarkdown('**Parameters:**\n');
+            for (const param of func.parameters) {
+                const optional = param.optional ? ' (optional)' : '';
+                const type = param.type ? `: ${param.type}` : '';
+                const desc = param.description ? ` - ${param.description}` : '';
+                md.appendMarkdown(`- \`${param.name}${type}\`${optional}${desc}\n`);
+            }
+            md.appendMarkdown('\n');
+        }
+        
+        if (func.returns) {
+            md.appendMarkdown('**Returns:**');
+            if (func.returns.type) {
+                md.appendMarkdown(` \`${func.returns.type}\``);
+            }
+            if (func.returns.description) {
+                md.appendMarkdown(` - ${func.returns.description}`);
+            }
+            md.appendMarkdown('\n\n');
+        }
+        
+        if (func.examples && func.examples.length > 0) {
+            md.appendMarkdown('**Examples:**\n');
+            for (const example of func.examples) {
+                md.appendMarkdown('```isl\n' + example + '\n```\n');
+            }
+        }
+        
+        md.appendMarkdown('\n---\n*Defined in .islextensions*');
+        
+        return new vscode.Hover(md);
+    }
+
+    private getCustomModifierHover(mod: import('./extensions').IslModifierDefinition): vscode.Hover {
+        const md = new vscode.MarkdownString();
+        md.isTrusted = true;
+        
+        // Build signature
+        if (mod.parameters.length > 0) {
+            const params = mod.parameters.map(p => {
+                let result = `${p.name}`;
+                if (p.type) {
+                    result += `: ${p.type}`;
+                }
+                if (p.optional) {
+                    result += '?';
+                }
+                return result;
+            }).join(', ');
+            
+            const returnType = mod.returns?.type ? `: ${mod.returns.type}` : '';
+            md.appendMarkdown(`**\`${mod.name}(${params})${returnType}\`** *(custom modifier)*\n\n`);
+        } else {
+            md.appendMarkdown(`**\`${mod.name}\`** *(custom modifier)*\n\n`);
+        }
+        
+        if (mod.description) {
+            md.appendMarkdown(`${mod.description}\n\n`);
+        }
+        
+        if (mod.parameters.length > 0) {
+            md.appendMarkdown('**Parameters:**\n');
+            for (const param of mod.parameters) {
+                const optional = param.optional ? ' (optional)' : '';
+                const type = param.type ? `: ${param.type}` : '';
+                const desc = param.description ? ` - ${param.description}` : '';
+                const defaultVal = param.defaultValue ? ` (default: ${param.defaultValue})` : '';
+                md.appendMarkdown(`- \`${param.name}${type}\`${optional}${defaultVal}${desc}\n`);
+            }
+            md.appendMarkdown('\n');
+        }
+        
+        if (mod.returns) {
+            md.appendMarkdown('**Returns:**');
+            if (mod.returns.type) {
+                md.appendMarkdown(` \`${mod.returns.type}\``);
+            }
+            if (mod.returns.description) {
+                md.appendMarkdown(` - ${mod.returns.description}`);
+            }
+            md.appendMarkdown('\n\n');
+        }
+        
+        if (mod.examples && mod.examples.length > 0) {
+            md.appendMarkdown('**Examples:**\n');
+            for (const example of mod.examples) {
+                md.appendMarkdown('```isl\n' + example + '\n```\n');
+            }
+        }
+        
+        md.appendMarkdown('\n---\n*Defined in .islextensions*');
+        
+        return new vscode.Hover(md);
+    }
+
+    private isKeyword(word: string): boolean {
+        const keywords = ['fun', 'modifier', 'if', 'else', 'endif', 'foreach', 'endfor', 'while', 'endwhile', 
+                         'switch', 'endswitch', 'return', 'import', 'type', 'as', 'from', 'in', 'cache', 'parallel',
+                         'filter', 'map', 'and', 'or', 'not', 'contains', 'startsWith', 'endsWith', 'matches', 'is'];
+        return keywords.includes(word);
+    }
+
+    private isModifier(word: string, line: string): boolean {
+        return line.includes('|') && (line.includes(word + '(') || line.includes(word + ' ') || 
+               line.includes('| ' + word) || line.includes('|' + word) || 
+               new RegExp(`\\|\\s*${word}\\b`).test(line));
+    }
+
+    private getKeywordHover(word: string): vscode.Hover {
+        const docs: { [key: string]: string } = {
+            'fun': '**Function Declaration**\n\nDefines a function that can be called within ISL.\n\n```isl\nfun myFunction($param) {\n    return $param | upperCase\n}\n\n// Call it:\n$result: @.This.myFunction($value);\n```',
+            'modifier': '**Modifier Function**\n\nDefines a custom modifier that can be used with the pipe operator.\n\n```isl\nmodifier double($value) {\n    return {{ $value * 2 }}\n}\n\n// Use it:\n$result: $input | double;\n```',
+            'if': '**If Statement**\n\nConditional execution based on a boolean expression.\n\n```isl\nif ($value > 10)\n    result: "high"\nelse\n    result: "low"\nendif\n```\n\n**Inline if expression:**\n```isl\n$status: if ($active) "active" else "inactive" endif;\n```',
+            'foreach': '**ForEach Loop**\n\nIterates over an array and transforms each element.\n\n```isl\nforeach $item in $array\n    { id: $item.id, name: $item.name }\nendfor\n```\n\n**With filtering:**\n```isl\nforeach $item in $array | filter($item.active)\n    $item.name | upperCase\nendfor\n```',
+            'while': '**While Loop**\n\nRepeats a block while a condition is true. Max 50 iterations by default.\n\n```isl\n$counter = 0;\nwhile ($counter < 10)\n    $counter = {{ $counter + 1 }}\nendwhile\n```\n\n**With options:**\n```isl\nwhile ($condition, {maxLoops: 100})\n    // statements\nendwhile\n```',
+            'switch': '**Switch Statement**\n\nMatches a value against multiple cases.\n\n```isl\nswitch ($status)\n    "active" -> "Active";\n    "pending" -> "Pending";\n    /^temp.*/ -> "Temporary";\n    < 100 -> "Low";\n    else -> "Unknown";\nendswitch\n```',
+            'return': '**Return Statement**\n\nReturns a value from a function. Functions must always return a value.\n\n```isl\nfun calculate($x) {\n    return {{ $x * 2 }}\n}\n```\n\n**Note:** Use `return {};` to return empty object, not `return;`',
+            'import': '**Import Statement**\n\nImports functions and types from another ISL file.\n\n```isl\nimport Common from \'common.isl\';\nimport Utils from \'../utils.isl\';\n\n$result: @.Common.someFunction();\n$value: $input | Common.someModifier;\n```',
+            'type': '**Type Declaration**\n\nDefines a custom type for validation.\n\n```isl\ntype Address as { \n    street: String, \n    city: String,\n    zip: String \n};\n\ntype User as {\n    name: String,\n    address: Address\n};\n```',
+            'parallel': '**Parallel Execution**\n\nExecutes a foreach loop in parallel for better performance.\n\n```isl\nparallel foreach $item in $array\n    @.Service.process($item)\nendfor\n\nparallel {threads: 10} foreach $item in $largeArray\n    // processing\nendfor\n```',
+            'cache': '**Cache Decorator**\n\nCaches the result of a function call based on parameters.\n\n```isl\ncache fun expensiveOperation($param) {\n    // result is cached\n    return @.Service.slowCall($param)\n}\n```',
+            'filter': '**Filter Modifier**\n\nFilters an array based on a condition.\n\n```isl\n$active: $items | filter($item.status == "active");\n$highValue: $orders | filter($order.total > 1000);\n```',
+            'map': '**Map Modifier**\n\nTransforms each element of an array.\n\n```isl\n$names: $users | map($user.name);\n$totals: $orders | map({{ $order.qty * $order.price }});\n```',
+        };
+
+        const markdown = new vscode.MarkdownString(docs[word] || `**${word}**\n\nISL keyword`);
+        markdown.isTrusted = true;
+        return new vscode.Hover(markdown);
+    }
+
+    private getServiceHover(word: string): vscode.Hover {
+        const services: { [key: string]: string } = {
+            'Date': '**Date Service**\n\nDate and time operations (all times in UTC).\n\n**Methods:**\n- `Now()` - Get current date/time\n- `parse(string, format, {locale})` - Parse date string\n- `fromEpochSeconds(seconds)` - Create from epoch seconds\n- `fromEpochMillis(millis)` - Create from epoch milliseconds\n\n**Example:**\n```isl\n$now: @.Date.Now();\n$parsed: @.Date.parse("2024-01-15", "yyyy-MM-dd");\n```',
+            'Math': '**Math Service**\n\nMathematical operations on arrays and numbers.\n\n**Methods:**\n- `sum(initial)` - Sum array values\n- `average()` - Calculate average\n- `min()` - Find minimum\n- `max()` - Find maximum  \n- `clamp(min, max)` - Clamp value to range\n- `round()`, `floor()`, `ceil()` - Rounding\n- `abs()` - Absolute value\n\n**Example:**\n```isl\n$total: $prices | Math.sum(0);\n$clamped: $value | Math.clamp(0, 100);\n```',
+            'This': '**This Service**\n\nCalls functions defined in the current ISL script.\n\n**Example:**\n```isl\nfun helper($x) {\n    return $x | upperCase\n}\n\nfun run($input) {\n    result: @.This.helper($input.name)\n}\n```',
+            'String': '**String Service**\n\nString manipulation functions.\n\n**Methods:**\n- `concat(strings...)` - Concatenate strings\n- `join(array, separator)` - Join array to string\n- `split(string, separator)` - Split string to array\n- `replace(string, find, replace)` - Replace text\n- `substring(string, start, end)` - Get substring',
+            'Array': '**Array Service**\n\nArray manipulation functions.\n\n**Methods:**\n- `concat(arrays...)` - Concatenate arrays\n- `slice(start, end)` - Get array slice\n- `reverse()` - Reverse array\n- `flatten()` - Flatten nested arrays',
+            'Json': '**JSON Service**\n\nJSON parsing and serialization.\n\n**Methods:**\n- `parse(string)` - Parse JSON string to object\n- `stringify(object)` - Convert object to JSON string\n\n**Example:**\n```isl\n$obj: @.Json.parse($jsonString);\n$json: @.Json.stringify($object);\n```',
+            'Xml': '**XML Service**\n\nXML parsing and generation.\n\n**Methods:**\n- `parse(string)` - Parse XML string to JSON object\n- `toXml(object, rootName)` - Convert JSON object to XML\n\n**Note:** Attributes use @ prefix, text content uses #text\n\n**Example:**\n```isl\n$obj: @.Xml.parse($xmlString);\n$xml: @.Xml.toXml($object, "root");\n```',
+            'Csv': '**CSV Service**\n\nCSV parsing.\n\n**Methods:**\n- `parse(string)` - Parse single line CSV\n- `parsemultiline(string, options)` - Parse multi-line CSV\n\n**Options:** `{headers: true, separator: ",", skipLines: 0}`\n\n**Example:**\n```isl\n$data: @.Csv.parsemultiline($csvText);\n```',
+            'Crypto': '**Crypto Service**\n\nCryptographic and encoding functions.\n\n**Methods:**\n- `md5(string)` - MD5 hash\n- `sha1(string)` - SHA-1 hash\n- `sha256(string)` - SHA-256 hash\n- `base64encode(string)` - Base64 encode\n- `base64decode(string)` - Base64 decode\n\n**Example:**\n```isl\n$hash: @.Crypto.sha256($password);\n$encoded: @.Crypto.base64encode($data);\n```',
+        };
+
+        const markdown = new vscode.MarkdownString(services[word] || `**@.${word}**\n\nISL service`);
+        markdown.isTrusted = true;
+        return new vscode.Hover(markdown);
+    }
+
+    private getModifierHover(word: string, line: string): vscode.Hover {
+        const modifiers: { [key: string]: { desc: string, signature?: string, example?: string } } = {
+            // String modifiers
+            'trim': { 
+                desc: 'Removes leading and trailing whitespace from a string.',
+                signature: 'trim',
+                example: '$name: $input.name | trim;'
+            },
+            'upperCase': { 
+                desc: 'Converts a string to uppercase.',
+                signature: 'upperCase',
+                example: '$code: $input.status | upperCase; // "ACTIVE"'
+            },
+            'lowerCase': { 
+                desc: 'Converts a string to lowercase.',
+                signature: 'lowerCase',
+                example: '$email: $input.email | lowerCase;'
+            },
+            'capitalize': { 
+                desc: 'Capitalizes the first letter of a string.',
+                signature: 'capitalize',
+                example: '$name: "john" | capitalize; // "John"'
+            },
+            'titleCase': { 
+                desc: 'Converts a string to title case (capitalizes each word).',
+                signature: 'titleCase',
+                example: '$title: "hello world" | titleCase; // "Hello World"'
+            },
+            'split': { 
+                desc: 'Splits a string into an array using a delimiter.',
+                signature: 'split(delimiter)',
+                example: '$tags: "red,blue,green" | split(","); // ["red", "blue", "green"]'
+            },
+            'replace': { 
+                desc: 'Replaces occurrences of a substring with another string.',
+                signature: 'replace(find, replaceWith)',
+                example: '$text: $input | replace("old", "new");'
+            },
+            'substring': { 
+                desc: 'Extracts a portion of a string.',
+                signature: 'substring(start, end)',
+                example: '$code: $input | substring(0, 5);'
+            },
+            'truncate': { 
+                desc: 'Truncates a string to a maximum length with optional suffix.',
+                signature: 'truncate(maxLength, suffix)',
+                example: '$short: $longText | truncate(100, "...");'
+            },
+            'padStart': { 
+                desc: 'Pads the start of a string to a target length.',
+                signature: 'padStart(length, padString)',
+                example: '$id: $number | to.string | padStart(8, "0"); // "00000123"'
+            },
+            'padEnd': { 
+                desc: 'Pads the end of a string to a target length.',
+                signature: 'padEnd(length, padString)',
+                example: '$code: $text | padEnd(10, " ");'
+            },
+            
+            // Array modifiers
+            'filter': { 
+                desc: 'Filters an array based on a condition. Use $ or $it for current item.',
+                signature: 'filter(condition)',
+                example: '$active: $items | filter($item.status == "active");\n$highValue: $nums | filter($ > 100);'
+            },
+            'map': { 
+                desc: 'Transforms each element of an array. Use $ or $it for current item.',
+                signature: 'map(expression)',
+                example: '$names: $users | map($user.name);\n$doubled: $numbers | map({{ $ * 2 }});'
+            },
+            'reduce': { 
+                desc: 'Reduces an array to a single value. Use $acc for accumulator, $it for current item.',
+                signature: 'reduce(expression, initialValue)',
+                example: '$sum: [1, 2, 3] | reduce({{ $acc + $it }}, 0); // 6'
+            },
+            'length': { 
+                desc: 'Returns the length of a string or array.',
+                signature: 'length',
+                example: '$count: $array | length;\n$size: $text | length;'
+            },
+            'sort': { 
+                desc: 'Sorts an array in ascending order.',
+                signature: 'sort',
+                example: '$sorted: $numbers | sort;'
+            },
+            'reverse': { 
+                desc: 'Reverses the order of elements in an array.',
+                signature: 'reverse',
+                example: '$reversed: $array | reverse;'
+            },
+            'unique': { 
+                desc: 'Returns unique values from an array, removing duplicates.',
+                signature: 'unique',
+                example: '$uniqueTags: $tags | unique;'
+            },
+            'flatten': { 
+                desc: 'Flattens nested arrays into a single array.',
+                signature: 'flatten',
+                example: '$flat: [[1,2], [3,4]] | flatten; // [1,2,3,4]'
+            },
+            'first': { 
+                desc: 'Returns the first element of an array.',
+                signature: 'first',
+                example: '$firstItem: $array | first;'
+            },
+            'last': { 
+                desc: 'Returns the last element of an array.',
+                signature: 'last',
+                example: '$lastItem: $array | last;'
+            },
+            'at': { 
+                desc: 'Returns the element at a specific index (supports negative indices).',
+                signature: 'at(index)',
+                example: '$second: $array | at(1);\n$lastItem: $array | at(-1);'
+            },
+            'isEmpty': { 
+                desc: 'Returns true if array or string is empty.',
+                signature: 'isEmpty',
+                example: 'if ($array | isEmpty) ... endif'
+            },
+            'isNotEmpty': { 
+                desc: 'Returns true if array or string is not empty.',
+                signature: 'isNotEmpty',
+                example: 'if ($array | isNotEmpty) ... endif'
+            },
+            'push': { 
+                desc: 'Adds an item to the end of an array.',
+                signature: 'push(item)',
+                example: '$newArray: $array | push($newItem);'
+            },
+            'pop': { 
+                desc: 'Removes and returns the last element from an array.',
+                signature: 'pop',
+                example: '$item: $array | pop;'
+            },
+            
+            // Type conversion modifiers
+            'to': { 
+                desc: 'Type conversion namespace.',
+                signature: 'to.string | to.number | to.decimal | to.boolean | to.array | to.json | to.xml',
+                example: '$id: $input.id | to.string;\n$price: $input.price | to.decimal;'
+            },
+            'string': { 
+                desc: 'Converts value to string. Also used for date formatting.',
+                signature: 'to.string or to.string(format) for dates',
+                example: '$id: $num | to.string;\n$date: $timestamp | to.string("yyyy-MM-dd");'
+            },
+            'number': { 
+                desc: 'Converts value to integer number.',
+                signature: 'to.number',
+                example: '$count: $input.count | to.number;'
+            },
+            'decimal': { 
+                desc: 'Converts value to decimal number.',
+                signature: 'to.decimal',
+                example: '$price: $input.price | to.decimal;'
+            },
+            'boolean': { 
+                desc: 'Converts value to boolean.',
+                signature: 'to.boolean',
+                example: '$active: $input.active | to.boolean;'
+            },
+            'array': { 
+                desc: 'Converts value to array.',
+                signature: 'to.array',
+                example: '$items: $single | to.array;'
+            },
+            'json': { 
+                desc: 'Converts object to JSON string.',
+                signature: 'to.json',
+                example: '$jsonStr: $object | to.json;'
+            },
+            'toxml': { 
+                desc: 'Converts object to XML string.',
+                signature: 'to.xml(rootName)',
+                example: '$xml: $object | to.xml("root");'
+            },
+            'epochmillis': { 
+                desc: 'Converts date to epoch milliseconds.',
+                signature: 'to.epochmillis',
+                example: '$timestamp: $date | to.epochmillis;'
+            },
+            
+            // Date modifiers
+            'date': { 
+                desc: 'Date operations namespace.',
+                signature: 'date.parse | date.add | date.part | date.fromEpochSeconds | date.fromEpochMillis',
+                example: '$parsed: $str | date.parse("yyyy-MM-dd");\n$tomorrow: $date | date.add(1, "DAYS");'
+            },
+            'parse': { 
+                desc: 'Parses a date string with the given format.',
+                signature: 'date.parse(format, {locale})',
+                example: '$date: "2024-01-15" | date.parse("yyyy-MM-dd");\n$parsed: $str | date.parse("MM/dd/yyyy", {locale: "en_US"});'
+            },
+            'add': { 
+                desc: 'Adds time to a date. Units: YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS.',
+                signature: 'date.add(amount, unit)',
+                example: '$tomorrow: $date | date.add(1, "DAYS");\n$nextWeek: $date | date.add(7, "DAYS");'
+            },
+            'part': { 
+                desc: 'Extracts a part of a date. Parts: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DAYOFYEAR, DAYOFWEEK.',
+                signature: 'date.part(part)',
+                example: '$year: $date | date.part("YEAR");\n$month: $date | date.part("MONTH");'
+            },
+            
+            // Math modifiers
+            'Math': { 
+                desc: 'Math operations on arrays and numbers.',
+                signature: 'Math.sum | Math.average | Math.min | Math.max | Math.clamp | Math.round',
+                example: '$total: $prices | Math.sum(0);\n$avg: $values | Math.average;'
+            },
+            'sum': { 
+                desc: 'Sums all numbers in an array.',
+                signature: 'Math.sum(initialValue)',
+                example: '$total: $prices | Math.sum(0);'
+            },
+            'average': { 
+                desc: 'Calculates the average of numbers in an array.',
+                signature: 'Math.average',
+                example: '$avg: $scores | Math.average;'
+            },
+            'min': { 
+                desc: 'Finds the minimum value in an array.',
+                signature: 'Math.min',
+                example: '$lowest: $prices | Math.min;'
+            },
+            'max': { 
+                desc: 'Finds the maximum value in an array.',
+                signature: 'Math.max',
+                example: '$highest: $scores | Math.max;'
+            },
+            'clamp': { 
+                desc: 'Clamps a number to a range [min, max].',
+                signature: 'Math.clamp(min, max)',
+                example: '$safe: $value | Math.clamp(0, 100);'
+            },
+            'precision': { 
+                desc: 'Sets decimal precision for a number.',
+                signature: 'precision(digits)',
+                example: '$price: $value | precision(2); // 12.99'
+            },
+            'round': { 
+                desc: 'Rounds a number.',
+                signature: 'Math.round',
+                example: '$rounded: $value | Math.round;'
+            },
+            'floor': { 
+                desc: 'Rounds down to nearest integer.',
+                signature: 'Math.floor',
+                example: '$down: $value | Math.floor;'
+            },
+            'ceil': { 
+                desc: 'Rounds up to nearest integer.',
+                signature: 'Math.ceil',
+                example: '$up: $value | Math.ceil;'
+            },
+            'abs': { 
+                desc: 'Returns absolute value.',
+                signature: 'Math.abs',
+                example: '$positive: $negative | Math.abs;'
+            },
+            
+            // XML/CSV modifiers
+            'xml': { 
+                desc: 'XML operations.',
+                signature: 'xml.parse',
+                example: '$obj: $xmlString | xml.parse;'
+            },
+            'csv': { 
+                desc: 'CSV parsing operations.',
+                signature: 'csv.parsemultiline(options)',
+                example: '$data: $csvText | csv.parsemultiline;'
+            },
+            'parsemultiline': { 
+                desc: 'Parses multi-line CSV into array of objects.',
+                signature: 'csv.parsemultiline({headers, separator, skipLines})',
+                example: '$data: $csv | csv.parsemultiline;\n$custom: $csv | csv.parsemultiline({separator: ";", skipLines: 1});'
+            },
+            
+            // Regex modifiers
+            'regex': { 
+                desc: 'Regular expression operations.',
+                signature: 'regex.find | regex.matches | regex.replace',
+                example: '$found: $text | regex.find("/\\d+/");\n$clean: $text | regex.replace("/[^a-z]/", "");'
+            },
+            
+            // Object modifiers
+            'keys': { 
+                desc: 'Returns an array of object keys.',
+                signature: 'keys',
+                example: '$propNames: $object | keys;'
+            },
+            'kv': { 
+                desc: 'Converts object to array of key-value pairs.',
+                signature: 'kv',
+                example: '$pairs: $object | kv; // [{key: "name", value: "John"}]'
+            },
+            'delete': { 
+                desc: 'Removes a property from an object.',
+                signature: 'delete(propertyName)',
+                example: '$clean: $object | delete("tempField");'
+            },
+            'select': { 
+                desc: 'Selects a nested property by path.',
+                signature: 'select(path)',
+                example: '$value: $object | select("user.address.city");'
+            },
+            'getProperty': { 
+                desc: 'Gets a property by name (case-insensitive).',
+                signature: 'getProperty(name)',
+                example: '$value: $object | getProperty("Name"); // finds "name", "Name", or "NAME"'
+            },
+            
+            // Encoding
+            'encode': { 
+                desc: 'Encoding operations.',
+                signature: 'encode.base64',
+                example: '$encoded: $text | encode.base64;'
+            },
+            'decode': { 
+                desc: 'Decoding operations.',
+                signature: 'decode.base64',
+                example: '$decoded: $encoded | decode.base64;'
+            },
+            'base64': { 
+                desc: 'Base64 encode/decode.',
+                signature: 'encode.base64 or decode.base64',
+                example: '$enc: $text | encode.base64;\n$dec: $enc | decode.base64;'
+            },
+            
+            // Other
+            'default': { 
+                desc: 'Returns a default value if the input is null or empty.',
+                signature: 'default(defaultValue)',
+                example: '$name: $input.name | default("Unknown");'
+            },
+            'coalesce': { 
+                desc: 'Returns first non-null value. Use ?? operator instead.',
+                signature: 'coalesce(alternativeValue)',
+                example: '$value: $input.value | coalesce($fallback);\n// Better: $value: $input.value ?? $fallback;'
+            },
+        };
+
+        const info = modifiers[word];
+        if (info) {
+            let markdown = `**\`${word}\`** modifier\n\n${info.desc}`;
+            if (info.signature) {
+                markdown += `\n\n**Signature:** \`${info.signature}\``;
+            }
+            if (info.example) {
+                markdown += `\n\n**Example:**\n\`\`\`isl\n${info.example}\n\`\`\``;
+            }
+            const md = new vscode.MarkdownString(markdown);
+            md.isTrusted = true;
+            return new vscode.Hover(md);
+        }
+
+        const markdown = new vscode.MarkdownString(`**\`${word}\`** modifier`);
+        markdown.isTrusted = true;
+        return new vscode.Hover(markdown);
+    }
+
+    private getVariableHover(word: string, document: vscode.TextDocument): vscode.Hover {
+        const markdown = new vscode.MarkdownString(`**$${word}**\n\nVariable`);
+        markdown.isTrusted = true;
+        return new vscode.Hover(markdown);
+    }
+}
diff --git a/plugin/src/inlayhints.ts b/plugin/src/inlayhints.ts
new file mode 100644
index 0000000..a18ea81
--- /dev/null
+++ b/plugin/src/inlayhints.ts
@@ -0,0 +1,207 @@
+import * as vscode from 'vscode';
+
+export class IslInlayHintsProvider implements vscode.InlayHintsProvider {
+    
+    provideInlayHints(
+        document: vscode.TextDocument,
+        range: vscode.Range,
+        token: vscode.CancellationToken
+    ): vscode.InlayHint[] {
+        const hints: vscode.InlayHint[] = [];
+        const text = document.getText(range);
+        const lines = text.split('\n');
+        const startLine = range.start.line;
+        
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            const lineNumber = startLine + i;
+            
+            // Add type hints for variable declarations
+            this.addVariableTypeHints(line, lineNumber, hints, document);
+            
+            // Add parameter name hints for function calls
+            this.addParameterNameHints(line, lineNumber, hints, document);
+            
+            // Add array operation hints
+            this.addArrayOperationHints(line, lineNumber, hints, document);
+        }
+        
+        return hints;
+    }
+    
+    private addVariableTypeHints(line: string, lineNumber: number, hints: vscode.InlayHint[], document: vscode.TextDocument) {
+        // Detect variable declarations with modifiers that indicate type
+        const patterns = [
+            // to.string suggests string
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*to\.string/g, type: 'string' },
+            // to.number suggests number
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*to\.number/g, type: 'number' },
+            // to.decimal suggests decimal
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*to\.decimal/g, type: 'decimal' },
+            // to.boolean suggests boolean
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*to\.boolean/g, type: 'boolean' },
+            // to.array or map suggests array
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*(to\.array|map|filter)/g, type: 'array' },
+            // date.parse suggests date
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*date\.parse/g, type: 'date' },
+            // @.Date suggests date
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*@\.Date\./g, type: 'date' },
+            // Math operations suggest number
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*\{\{[^}]+\}\}/g, type: 'number' },
+            // keys suggests string array
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*[^;|]*\|\s*keys/g, type: 'string[]' },
+            // Object literal suggests object (but not {{ for math expressions)
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*\{(?!\{)/g, type: 'object' },
+            // Array literal suggests array
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*\[/g, type: 'array' },
+            // String literal
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*["'`]/g, type: 'string' },
+            // Number literal
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*-?\d+(\.\d+)?(?!\w)/g, type: 'number' },
+            // Boolean literal
+            { pattern: /(\$[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(true|false)\b/g, type: 'boolean' },
+        ];
+        
+        for (const { pattern, type } of patterns) {
+            let match;
+            pattern.lastIndex = 0; // Reset regex
+            
+            while ((match = pattern.exec(line)) !== null) {
+                const varName = match[1];
+                const position = new vscode.Position(lineNumber, match.index + varName.length);
+                
+                const hint = new vscode.InlayHint(
+                    position,
+                    `: ${type}`,
+                    vscode.InlayHintKind.Type
+                );
+                hint.paddingLeft = false;
+                hint.paddingRight = false;
+                
+                hints.push(hint);
+            }
+        }
+    }
+    
+    private addParameterNameHints(line: string, lineNumber: number, hints: vscode.InlayHint[], document: vscode.TextDocument) {
+        // Add parameter name hints for common functions with multiple parameters
+        const functionCalls = [
+            // truncate(length, suffix)
+            { 
+                pattern: /\|\s*truncate\s*\(\s*(\d+)\s*,\s*("[^"]*")/g, 
+                params: ['maxLength:', 'suffix:']
+            },
+            // padStart(length, padString)
+            { 
+                pattern: /\|\s*padStart\s*\(\s*(\d+)\s*,\s*("[^"]*")/g, 
+                params: ['length:', 'padString:']
+            },
+            // padEnd(length, padString)
+            { 
+                pattern: /\|\s*padEnd\s*\(\s*(\d+)\s*,\s*("[^"]*")/g, 
+                params: ['length:', 'padString:']
+            },
+            // Math.clamp(min, max)
+            { 
+                pattern: /\|\s*Math\.clamp\s*\(\s*(-?\d+(?:\.\d+)?)\s*,\s*(-?\d+(?:\.\d+)?)/g, 
+                params: ['min:', 'max:']
+            },
+            // date.add(amount, unit)
+            { 
+                pattern: /\|\s*date\.add\s*\(\s*(-?\d+)\s*,\s*"([^"]*)"/g, 
+                params: ['amount:', 'unit:']
+            },
+            // substring(start, end)
+            { 
+                pattern: /\|\s*substring\s*\(\s*(\d+)\s*,\s*(\d+)/g, 
+                params: ['start:', 'end:']
+            },
+            // replace(find, replaceWith)
+            { 
+                pattern: /\|\s*replace\s*\(\s*("[^"]*")\s*,\s*("[^"]*")/g, 
+                params: ['find:', 'replaceWith:']
+            },
+        ];
+        
+        for (const { pattern, params } of functionCalls) {
+            let match;
+            pattern.lastIndex = 0;
+            
+            while ((match = pattern.exec(line)) !== null) {
+                // Add hint for each parameter
+                for (let i = 1; i < match.length && i - 1 < params.length; i++) {
+                    const paramValue = match[i];
+                    const paramStart = match.index + match[0].indexOf(paramValue);
+                    const position = new vscode.Position(lineNumber, paramStart);
+                    
+                    const hint = new vscode.InlayHint(
+                        position,
+                        params[i - 1],
+                        vscode.InlayHintKind.Parameter
+                    );
+                    hint.paddingLeft = false;
+                    hint.paddingRight = true;
+                    
+                    hints.push(hint);
+                }
+            }
+        }
+    }
+    
+    private addArrayOperationHints(line: string, lineNumber: number, hints: vscode.InlayHint[], document: vscode.TextDocument) {
+        // Add hints for array operations that produce specific types
+        const arrayOps = [
+            // map produces array
+            { pattern: /(\|)\s*(map\s*\([^)]+\))/g, hint: ' → array' },
+            // filter produces array
+            { pattern: /(\|)\s*(filter\s*\([^)]+\))/g, hint: ' → array' },
+            // unique produces array
+            { pattern: /(\|)\s*(unique)/g, hint: ' → array' },
+            // sort produces array
+            { pattern: /(\|)\s*(sort)/g, hint: ' → array' },
+            // reverse produces array
+            { pattern: /(\|)\s*(reverse)/g, hint: ' → array' },
+            // flatten produces array
+            { pattern: /(\|)\s*(flatten)/g, hint: ' → array' },
+            // Math.sum produces number
+            { pattern: /(\|)\s*(Math\.sum\([^)]*\))/g, hint: ' → number' },
+            // Math.average produces number
+            { pattern: /(\|)\s*(Math\.average)/g, hint: ' → number' },
+            // length produces number
+            { pattern: /(\|)\s*(length)/g, hint: ' → number' },
+            // first produces single item
+            { pattern: /(\|)\s*(first)/g, hint: ' → item' },
+            // last produces single item
+            { pattern: /(\|)\s*(last)/g, hint: ' → item' },
+            // keys produces string array
+            { pattern: /(\|)\s*(keys)/g, hint: ' → string[]' },
+            // to.boolean produces boolean
+            { pattern: /(\|)\s*(to\.boolean)/g, hint: ' → boolean' },
+            // isEmpty produces boolean
+            { pattern: /(\|)\s*(isEmpty)/g, hint: ' → boolean' },
+            // isNotEmpty produces boolean
+            { pattern: /(\|)\s*(isNotEmpty)/g, hint: ' → boolean' },
+        ];
+        
+        for (const { pattern, hint: hintText } of arrayOps) {
+            let match;
+            pattern.lastIndex = 0;
+            
+            while ((match = pattern.exec(line)) !== null) {
+                const opEnd = match.index + match[0].length;
+                const position = new vscode.Position(lineNumber, opEnd);
+                
+                const hint = new vscode.InlayHint(
+                    position,
+                    hintText,
+                    vscode.InlayHintKind.Type
+                );
+                hint.paddingLeft = true;
+                hint.paddingRight = false;
+                
+                hints.push(hint);
+            }
+        }
+    }
+}
+
diff --git a/plugin/src/signature.ts b/plugin/src/signature.ts
new file mode 100644
index 0000000..f82a09e
--- /dev/null
+++ b/plugin/src/signature.ts
@@ -0,0 +1,521 @@
+import * as vscode from 'vscode';
+
+export class IslSignatureHelpProvider implements vscode.SignatureHelpProvider {
+    
+    provideSignatureHelp(
+        document: vscode.TextDocument,
+        position: vscode.Position,
+        token: vscode.CancellationToken,
+        context: vscode.SignatureHelpContext
+    ): vscode.SignatureHelp | undefined {
+        const line = document.lineAt(position).text;
+        const beforeCursor = line.substring(0, position.character);
+        
+        // Check if we're inside a modifier call
+        const modifierMatch = beforeCursor.match(/\|\s*([a-zA-Z_][a-zA-Z0-9_.]*)(?:\(([^)]*))?$/);
+        if (modifierMatch) {
+            return this.getModifierSignature(modifierMatch[1], beforeCursor);
+        }
+        
+        // Check if we're inside a service call
+        const serviceMatch = beforeCursor.match(/@\.([A-Z][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)(?:\(([^)]*))?$/);
+        if (serviceMatch) {
+            return this.getServiceSignature(serviceMatch[1], serviceMatch[2], beforeCursor);
+        }
+        
+        // Check if we're inside a custom function call (@.This.)
+        const thisMatch = beforeCursor.match(/@\.This\.([a-zA-Z_][a-zA-Z0-9_]*)(?:\(([^)]*))?$/);
+        if (thisMatch) {
+            return this.getCustomFunctionSignature(document, thisMatch[1], beforeCursor);
+        }
+        
+        return undefined;
+    }
+    
+    private getModifierSignature(modifier: string, beforeCursor: string): vscode.SignatureHelp | undefined {
+        const signatures: { [key: string]: { label: string, params: Array<{ label: string, doc: string }>, doc: string } } = {
+            // String modifiers
+            'split': {
+                label: 'split(delimiter: string)',
+                params: [
+                    { label: 'delimiter', doc: 'The string to split on (e.g., ",", " ")' }
+                ],
+                doc: 'Splits a string into an array using the delimiter'
+            },
+            'replace': {
+                label: 'replace(find: string, replaceWith: string)',
+                params: [
+                    { label: 'find', doc: 'The string to find' },
+                    { label: 'replaceWith', doc: 'The replacement string' }
+                ],
+                doc: 'Replaces all occurrences of find with replaceWith'
+            },
+            'substring': {
+                label: 'substring(start: number, end: number)',
+                params: [
+                    { label: 'start', doc: 'Starting index (0-based)' },
+                    { label: 'end', doc: 'Ending index (exclusive)' }
+                ],
+                doc: 'Extracts a portion of the string'
+            },
+            'truncate': {
+                label: 'truncate(maxLength: number, suffix: string)',
+                params: [
+                    { label: 'maxLength', doc: 'Maximum length of the string' },
+                    { label: 'suffix', doc: 'Suffix to add if truncated (e.g., "...")' }
+                ],
+                doc: 'Truncates string to maxLength and adds suffix if needed'
+            },
+            'padStart': {
+                label: 'padStart(length: number, padString: string)',
+                params: [
+                    { label: 'length', doc: 'Target length of the string' },
+                    { label: 'padString', doc: 'String to pad with (e.g., "0", " ")' }
+                ],
+                doc: 'Pads the start of the string to reach target length'
+            },
+            'padEnd': {
+                label: 'padEnd(length: number, padString: string)',
+                params: [
+                    { label: 'length', doc: 'Target length of the string' },
+                    { label: 'padString', doc: 'String to pad with' }
+                ],
+                doc: 'Pads the end of the string to reach target length'
+            },
+            
+            // Array modifiers
+            'filter': {
+                label: 'filter(condition: expression)',
+                params: [
+                    { label: 'condition', doc: 'Boolean expression using $ or $item for current element' }
+                ],
+                doc: 'Filters array elements based on condition. Use $ for current item.'
+            },
+            'map': {
+                label: 'map(expression: any)',
+                params: [
+                    { label: 'expression', doc: 'Transform expression using $ or $item for current element' }
+                ],
+                doc: 'Transforms each array element. Use $ for current item.'
+            },
+            'reduce': {
+                label: 'reduce(expression: any, initialValue: any)',
+                params: [
+                    { label: 'expression', doc: 'Accumulator expression using $acc and $it' },
+                    { label: 'initialValue', doc: 'Initial value for the accumulator' }
+                ],
+                doc: 'Reduces array to single value. Use $acc (accumulator) and $it (current item).'
+            },
+            'at': {
+                label: 'at(index: number)',
+                params: [
+                    { label: 'index', doc: 'Array index (supports negative for counting from end)' }
+                ],
+                doc: 'Returns element at index. Use -1 for last element.'
+            },
+            'push': {
+                label: 'push(item: any)',
+                params: [
+                    { label: 'item', doc: 'Item to add to array' }
+                ],
+                doc: 'Adds item to end of array'
+            },
+            
+            // Date modifiers
+            'date.parse': {
+                label: 'date.parse(format: string, options?: object)',
+                params: [
+                    { label: 'format', doc: 'Date format pattern (e.g., "yyyy-MM-dd")' },
+                    { label: 'options', doc: 'Optional: {locale: "en_US"}' }
+                ],
+                doc: 'Parses date string using Java DateTimeFormatter patterns'
+            },
+            'date.add': {
+                label: 'date.add(amount: number, unit: string)',
+                params: [
+                    { label: 'amount', doc: 'Amount to add (can be negative)' },
+                    { label: 'unit', doc: 'Time unit: YEARS, MONTHS, DAYS, HOURS, MINUTES, SECONDS' }
+                ],
+                doc: 'Adds time to a date'
+            },
+            'date.part': {
+                label: 'date.part(part: string)',
+                params: [
+                    { label: 'part', doc: 'Date part: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DAYOFYEAR, DAYOFWEEK' }
+                ],
+                doc: 'Extracts a specific part from a date'
+            },
+            
+            // Math modifiers
+            'Math.sum': {
+                label: 'Math.sum(initialValue: number)',
+                params: [
+                    { label: 'initialValue', doc: 'Starting value for sum (usually 0)' }
+                ],
+                doc: 'Sums all numbers in array'
+            },
+            'Math.clamp': {
+                label: 'Math.clamp(min: number, max: number)',
+                params: [
+                    { label: 'min', doc: 'Minimum allowed value' },
+                    { label: 'max', doc: 'Maximum allowed value' }
+                ],
+                doc: 'Clamps number to range [min, max]'
+            },
+            'precision': {
+                label: 'precision(digits: number)',
+                params: [
+                    { label: 'digits', doc: 'Number of decimal places' }
+                ],
+                doc: 'Sets decimal precision (e.g., precision(2) → 12.99)'
+            },
+            
+            // Type conversions
+            'to.string': {
+                label: 'to.string(format?: string)',
+                params: [
+                    { label: 'format', doc: 'For dates: format pattern (e.g., "yyyy-MM-dd HH:mm:ss")' }
+                ],
+                doc: 'Converts value to string. For dates, optional format parameter.'
+            },
+            'to.xml': {
+                label: 'to.xml(rootName: string)',
+                params: [
+                    { label: 'rootName', doc: 'Root element name for XML' }
+                ],
+                doc: 'Converts object to XML string'
+            },
+            
+            // Regex
+            'regex.find': {
+                label: 'regex.find(pattern: string, options?: object)',
+                params: [
+                    { label: 'pattern', doc: 'Regular expression pattern' },
+                    { label: 'options', doc: 'Optional: {ignoreCase: true, multiLine: true}' }
+                ],
+                doc: 'Finds all matches of pattern in string'
+            },
+            'regex.matches': {
+                label: 'regex.matches(pattern: string, options?: object)',
+                params: [
+                    { label: 'pattern', doc: 'Regular expression pattern' },
+                    { label: 'options', doc: 'Optional: {ignoreCase: true}' }
+                ],
+                doc: 'Tests if pattern matches string (returns boolean)'
+            },
+            'regex.replace': {
+                label: 'regex.replace(pattern: string, replacement: string, options?: object)',
+                params: [
+                    { label: 'pattern', doc: 'Regular expression pattern' },
+                    { label: 'replacement', doc: 'Replacement string' },
+                    { label: 'options', doc: 'Optional: {ignoreCase: true}' }
+                ],
+                doc: 'Replaces pattern matches with replacement'
+            },
+            
+            // CSV
+            'csv.parsemultiline': {
+                label: 'csv.parsemultiline(options?: object)',
+                params: [
+                    { label: 'options', doc: 'Optional: {headers: true, separator: ",", skipLines: 0}' }
+                ],
+                doc: 'Parses multi-line CSV to array of objects'
+            },
+            
+            // Object
+            'delete': {
+                label: 'delete(propertyName: string)',
+                params: [
+                    { label: 'propertyName', doc: 'Name of property to delete' }
+                ],
+                doc: 'Removes property from object'
+            },
+            'select': {
+                label: 'select(path: string)',
+                params: [
+                    { label: 'path', doc: 'Property path (e.g., "user.address.city")' }
+                ],
+                doc: 'Selects nested property by path'
+            },
+            'getProperty': {
+                label: 'getProperty(name: string)',
+                params: [
+                    { label: 'name', doc: 'Property name (case-insensitive)' }
+                ],
+                doc: 'Gets property by name (case-insensitive lookup)'
+            },
+            
+            // Other
+            'default': {
+                label: 'default(defaultValue: any)',
+                params: [
+                    { label: 'defaultValue', doc: 'Value to use if input is null/empty' }
+                ],
+                doc: 'Returns default value if input is null or empty'
+            },
+            'coalesce': {
+                label: 'coalesce(alternativeValue: any)',
+                params: [
+                    { label: 'alternativeValue', doc: 'Alternative value if input is null' }
+                ],
+                doc: 'Returns first non-null value (prefer ?? operator)'
+            },
+        };
+        
+        const sig = signatures[modifier];
+        if (!sig) {
+            return undefined;
+        }
+        
+        const signatureHelp = new vscode.SignatureHelp();
+        const signature = new vscode.SignatureInformation(sig.label, new vscode.MarkdownString(sig.doc));
+        
+        sig.params.forEach(param => {
+            signature.parameters.push(new vscode.ParameterInformation(param.label, new vscode.MarkdownString(param.doc)));
+        });
+        
+        signatureHelp.signatures = [signature];
+        signatureHelp.activeSignature = 0;
+        
+        // Determine active parameter based on comma count
+        const paramSection = beforeCursor.match(/\(([^)]*)?$/)?.[1] || '';
+        const commaCount = (paramSection.match(/,/g) || []).length;
+        signatureHelp.activeParameter = Math.min(commaCount, sig.params.length - 1);
+        
+        return signatureHelp;
+    }
+    
+    private getServiceSignature(service: string, method: string, beforeCursor: string): vscode.SignatureHelp | undefined {
+        const signatures: { [key: string]: { [key: string]: { label: string, params: Array<{ label: string, doc: string }>, doc: string } } } = {
+            'Date': {
+                'parse': {
+                    label: '@.Date.parse(dateString: string, format: string, options?: object)',
+                    params: [
+                        { label: 'dateString', doc: 'String containing the date to parse' },
+                        { label: 'format', doc: 'Date format pattern (e.g., "yyyy-MM-dd")' },
+                        { label: 'options', doc: 'Optional: {locale: "en_US"}' }
+                    ],
+                    doc: 'Parses a date string into a date object'
+                },
+                'fromEpochSeconds': {
+                    label: '@.Date.fromEpochSeconds(seconds: number)',
+                    params: [
+                        { label: 'seconds', doc: 'Unix timestamp in seconds' }
+                    ],
+                    doc: 'Creates date from Unix timestamp (seconds)'
+                },
+                'fromEpochMillis': {
+                    label: '@.Date.fromEpochMillis(milliseconds: number)',
+                    params: [
+                        { label: 'milliseconds', doc: 'Unix timestamp in milliseconds' }
+                    ],
+                    doc: 'Creates date from Unix timestamp (milliseconds)'
+                }
+            },
+            'Math': {
+                'sum': {
+                    label: '@.Math.sum(array: number[], initialValue: number)',
+                    params: [
+                        { label: 'array', doc: 'Array of numbers to sum' },
+                        { label: 'initialValue', doc: 'Starting value (usually 0)' }
+                    ],
+                    doc: 'Sums all numbers in array'
+                },
+                'clamp': {
+                    label: '@.Math.clamp(value: number, min: number, max: number)',
+                    params: [
+                        { label: 'value', doc: 'Number to clamp' },
+                        { label: 'min', doc: 'Minimum allowed value' },
+                        { label: 'max', doc: 'Maximum allowed value' }
+                    ],
+                    doc: 'Clamps value to range [min, max]'
+                }
+            },
+            'String': {
+                'concat': {
+                    label: '@.String.concat(...strings: string[])',
+                    params: [
+                        { label: 'strings', doc: 'Strings to concatenate' }
+                    ],
+                    doc: 'Concatenates multiple strings'
+                },
+                'join': {
+                    label: '@.String.join(array: string[], separator: string)',
+                    params: [
+                        { label: 'array', doc: 'Array of strings to join' },
+                        { label: 'separator', doc: 'Separator string (e.g., ", ")' }
+                    ],
+                    doc: 'Joins array elements into string'
+                },
+                'split': {
+                    label: '@.String.split(string: string, separator: string)',
+                    params: [
+                        { label: 'string', doc: 'String to split' },
+                        { label: 'separator', doc: 'Separator pattern' }
+                    ],
+                    doc: 'Splits string into array'
+                }
+            },
+            'Json': {
+                'parse': {
+                    label: '@.Json.parse(jsonString: string)',
+                    params: [
+                        { label: 'jsonString', doc: 'JSON string to parse' }
+                    ],
+                    doc: 'Parses JSON string into object'
+                },
+                'stringify': {
+                    label: '@.Json.stringify(object: any)',
+                    params: [
+                        { label: 'object', doc: 'Object to convert to JSON' }
+                    ],
+                    doc: 'Converts object to JSON string'
+                }
+            },
+            'Xml': {
+                'parse': {
+                    label: '@.Xml.parse(xmlString: string)',
+                    params: [
+                        { label: 'xmlString', doc: 'XML string to parse' }
+                    ],
+                    doc: 'Parses XML string into JSON object'
+                },
+                'toXml': {
+                    label: '@.Xml.toXml(object: any, rootName: string)',
+                    params: [
+                        { label: 'object', doc: 'Object to convert' },
+                        { label: 'rootName', doc: 'Root element name' }
+                    ],
+                    doc: 'Converts object to XML string'
+                }
+            },
+            'Csv': {
+                'parse': {
+                    label: '@.Csv.parse(csvLine: string)',
+                    params: [
+                        { label: 'csvLine', doc: 'Single line of CSV to parse' }
+                    ],
+                    doc: 'Parses single CSV line to array'
+                },
+                'parsemultiline': {
+                    label: '@.Csv.parsemultiline(csvString: string, options?: object)',
+                    params: [
+                        { label: 'csvString', doc: 'Multi-line CSV string' },
+                        { label: 'options', doc: 'Optional: {headers: true, separator: ","}' }
+                    ],
+                    doc: 'Parses multi-line CSV to array of objects'
+                }
+            },
+            'Crypto': {
+                'md5': {
+                    label: '@.Crypto.md5(string: string)',
+                    params: [
+                        { label: 'string', doc: 'String to hash' }
+                    ],
+                    doc: 'Computes MD5 hash (returns hex string)'
+                },
+                'sha1': {
+                    label: '@.Crypto.sha1(string: string)',
+                    params: [
+                        { label: 'string', doc: 'String to hash' }
+                    ],
+                    doc: 'Computes SHA-1 hash (returns hex string)'
+                },
+                'sha256': {
+                    label: '@.Crypto.sha256(string: string)',
+                    params: [
+                        { label: 'string', doc: 'String to hash' }
+                    ],
+                    doc: 'Computes SHA-256 hash (returns hex string)'
+                },
+                'base64encode': {
+                    label: '@.Crypto.base64encode(string: string)',
+                    params: [
+                        { label: 'string', doc: 'String to encode' }
+                    ],
+                    doc: 'Encodes string to Base64'
+                },
+                'base64decode': {
+                    label: '@.Crypto.base64decode(string: string)',
+                    params: [
+                        { label: 'string', doc: 'Base64 string to decode' }
+                    ],
+                    doc: 'Decodes Base64 string'
+                }
+            }
+        };
+        
+        const serviceSigs = signatures[service];
+        if (!serviceSigs) {
+            return undefined;
+        }
+        
+        const sig = serviceSigs[method];
+        if (!sig) {
+            return undefined;
+        }
+        
+        const signatureHelp = new vscode.SignatureHelp();
+        const signature = new vscode.SignatureInformation(sig.label, new vscode.MarkdownString(sig.doc));
+        
+        sig.params.forEach(param => {
+            signature.parameters.push(new vscode.ParameterInformation(param.label, new vscode.MarkdownString(param.doc)));
+        });
+        
+        signatureHelp.signatures = [signature];
+        signatureHelp.activeSignature = 0;
+        
+        // Determine active parameter
+        const paramSection = beforeCursor.match(/\(([^)]*)?$/)?.[1] || '';
+        const commaCount = (paramSection.match(/,/g) || []).length;
+        signatureHelp.activeParameter = Math.min(commaCount, sig.params.length - 1);
+        
+        return signatureHelp;
+    }
+    
+    private getCustomFunctionSignature(document: vscode.TextDocument, functionName: string, beforeCursor: string): vscode.SignatureHelp | undefined {
+        const text = document.getText();
+        const lines = text.split('\n');
+        
+        // Find function declaration
+        const functionPattern = new RegExp(`^\\s*(fun|modifier)\\s+${functionName}\\s*\\(([^)]*)\\)`);
+        
+        for (let i = 0; i < lines.length; i++) {
+            const match = lines[i].match(functionPattern);
+            if (match) {
+                const funcType = match[1];
+                const params = match[2].trim();
+                
+                if (!params) {
+                    return undefined; // No parameters
+                }
+                
+                const signatureHelp = new vscode.SignatureHelp();
+                const signature = new vscode.SignatureInformation(
+                    `${funcType} ${functionName}(${params})`,
+                    new vscode.MarkdownString(`Custom ${funcType} defined in this file`)
+                );
+                
+                // Parse parameters
+                const paramList = params.split(',').map(p => p.trim()).filter(p => p.length > 0);
+                paramList.forEach(param => {
+                    const paramName = param.split(':')[0].trim();
+                    signature.parameters.push(new vscode.ParameterInformation(paramName));
+                });
+                
+                signatureHelp.signatures = [signature];
+                signatureHelp.activeSignature = 0;
+                
+                // Determine active parameter
+                const paramSection = beforeCursor.match(/\(([^)]*)?$/)?.[1] || '';
+                const commaCount = (paramSection.match(/,/g) || []).length;
+                signatureHelp.activeParameter = Math.min(commaCount, paramList.length - 1);
+                
+                return signatureHelp;
+            }
+        }
+        
+        return undefined;
+    }
+}
+
diff --git a/plugin/src/validator.ts b/plugin/src/validator.ts
new file mode 100644
index 0000000..87ced88
--- /dev/null
+++ b/plugin/src/validator.ts
@@ -0,0 +1,1108 @@
+import * as vscode from 'vscode';
+import { IslExtensionsManager } from './extensions';
+
+export class IslValidator {
+    private diagnosticCollection: vscode.DiagnosticCollection;
+    private validationTimeout: NodeJS.Timeout | undefined;
+
+    // Built-in modifiers
+    private readonly builtInModifiers = new Set([
+        // String modifiers
+        'trim', 'trimStart', 'trimEnd',
+        'cap', 'left', 'right',
+        'substring', 'substringUpto', 'substringAfter',
+        'lowerCase', 'upperCase',
+        'replace', 'remove',
+        'concat', 'append',
+        'split',
+        'csv.*',
+        'padStart', 'padEnd',
+        'reverse',
+        'capitalize', 'titleCase', 'camelCase', 'snakeCase',
+        'truncate',
+        'html.*',
+        'sanitizeTid',
+        
+        // Array modifiers
+        'isEmpty', 'isNotEmpty',
+        'push', 'pop', 'pushItems',
+        'at', 'first', 'last',
+        'take', 'drop',
+        'unique', 'slice',
+        'indexOf', 'lastIndexOf',
+        'chunk',
+        
+        // Object modifiers
+        'length',
+        'keys', 'kv',
+        'sort',
+        'delete',
+        'select',
+        'getProperty', 'setProperty',
+        'merge',
+        'pick', 'omit',
+        'rename',
+        'has',
+        'default',
+        
+        // Math modifiers (pipe usage)
+        'negate', 'absolute', 'precision',
+        'round.*',
+        
+        // Conversion modifiers
+        'to.*',
+        'hex.*',
+        'join.*',
+        'email.*',
+        
+        // Encoding modifiers
+        'encode.*',
+        'decode.*',
+        
+        // Compression modifiers
+        'gzip', 'gunzip', 'gunzipToByte',
+        
+        // JSON/XML/YAML modifiers
+        'json.*',
+        'yaml.*',
+        'xml.*',
+        
+        // Regex modifiers
+        'regex.*',
+        
+        // Date modifiers
+        'date.*',
+        
+        // Type modifiers
+        'typeof',
+        
+        // High-order modifiers
+        'map', 'filter', 'reduce',
+        
+        // Legacy/Alias modifiers
+        'contains', 'startsWith', 'endsWith'
+    ]);
+
+    // Built-in functions (static methods) - these can also be used with pipes
+    private readonly builtInFunctions = new Set([
+        // Date functions
+        'Date.now', 'Date.parse', 'Date.format',
+        'Date.fromEpochSeconds', 'Date.fromEpochMillis',
+        
+        // Math functions (can be used as @.Math.* or | Math.*)
+        'Math.min', 'Math.max', 'Math.mean', 'Math.mod', 'Math.sqrt',
+        'Math.sum', 'Math.average',
+        'Math.round', 'Math.floor', 'Math.ceil', 'Math.abs',
+        'Math.RandInt', 'Math.RandFloat', 'Math.RandDouble',
+        
+        // String functions
+        'String.concat', 'String.join',
+        
+        // Array functions
+        'Array.from', 'Array.of', 'Array.range',
+        'Array.slice', 'Array.unique',
+        
+        // JSON/XML/YAML functions
+        'Json.parse', 'Json.stringify',
+        'Xml.parse', 'Xml.toXml',
+        'Yaml.parse',
+        
+        // Crypto functions
+        'Crypto.md5', 'Crypto.sha1', 'Crypto.sha256',
+        'Crypto.base64encode', 'Crypto.base64decode',
+        
+        // Pagination functions
+        'Pagination.Cursor', 'Pagination.Page', 'Pagination.Date', 'Pagination.Offset', 'Pagination.Keyset'
+    ]);
+
+    constructor(private extensionsManager: IslExtensionsManager) {
+        this.diagnosticCollection = vscode.languages.createDiagnosticCollection('isl');
+    }
+
+    public dispose() {
+        this.diagnosticCollection.dispose();
+        if (this.validationTimeout) {
+            clearTimeout(this.validationTimeout);
+        }
+    }
+
+    public validateDebounced(document: vscode.TextDocument) {
+        if (this.validationTimeout) {
+            clearTimeout(this.validationTimeout);
+        }
+        this.validationTimeout = setTimeout(() => this.validate(document), 500);
+    }
+
+    public async validate(document: vscode.TextDocument): Promise {
+        const config = vscode.workspace.getConfiguration('isl.validation');
+        if (!config.get('enabled', true)) {
+            return;
+        }
+
+        const diagnostics: vscode.Diagnostic[] = [];
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        // Load custom extensions
+        const extensions = await this.extensionsManager.getExtensionsForDocument(document);
+
+        // Basic syntax validation
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            const lineNumber = i;
+
+            // Check for common syntax errors
+            this.checkBraceMatching(line, lineNumber, diagnostics, document);
+            this.checkVariableDeclaration(line, lineNumber, diagnostics, document);
+            this.checkStringInterpolation(line, lineNumber, diagnostics, document);
+            this.checkFunctionDeclaration(line, lineNumber, diagnostics, document);
+            this.checkControlFlow(line, lineNumber, diagnostics, document);
+        }
+
+        // Check for overall structure issues
+        this.checkBalancedBraces(text, diagnostics, document);
+        this.checkControlFlowBalance(text, diagnostics, document);
+        this.checkBalancedBackticks(text, diagnostics, document);
+
+        // Semantic validation
+        const userDefinedFunctions = this.extractUserDefinedFunctions(document);
+        const userDefinedModifiers = this.extractUserDefinedModifiers(document);
+        const declaredVariables = this.extractDeclaredVariables(document);
+
+        // Extract pagination variables for property validation
+        const paginationVariables = this.extractPaginationVariables(document);
+        
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            this.checkFunctionCalls(line, i, diagnostics, document, userDefinedFunctions, extensions);
+            this.checkModifierUsage(line, i, diagnostics, document, userDefinedModifiers, extensions);
+            this.checkVariableUsage(line, i, diagnostics, document, declaredVariables);
+            this.checkPaginationPropertyAccess(line, i, diagnostics, document, paginationVariables);
+            this.checkLongObjectDeclaration(line, i, diagnostics, document);
+            this.checkUnnecessaryStringInterpolation(line, i, diagnostics, document);
+            this.checkDefaultModifier(line, i, diagnostics, document);
+            this.checkColonAssignment(line, i, diagnostics, document);
+        }
+
+        this.diagnosticCollection.set(document.uri, diagnostics);
+    }
+
+    private checkBraceMatching(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Skip this check - it causes false positives on multi-line constructs
+        // The overall balance check in checkBalancedBraces handles this better
+        return;
+    }
+
+    private checkVariableDeclaration(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Check for invalid variable names
+        const varPattern = /\$([a-zA-Z_][a-zA-Z0-9_]*)/g;
+        let match;
+        
+        while ((match = varPattern.exec(line)) !== null) {
+            const varName = match[1];
+            
+            // Check if variable name is a reserved keyword
+            const reservedKeywords = ['if', 'else', 'endif', 'switch', 'endswitch', 'foreach', 'endfor', 'while', 'endwhile', 'fun', 'modifier', 'return', 'import', 'type', 'as', 'from'];
+            if (reservedKeywords.includes(varName)) {
+                const startPos = match.index;
+                const range = new vscode.Range(lineNumber, startPos, lineNumber, startPos + match[0].length);
+                diagnostics.push(new vscode.Diagnostic(
+                    range,
+                    `'${varName}' is a reserved keyword and cannot be used as a variable name`,
+                    vscode.DiagnosticSeverity.Error
+                ));
+            }
+        }
+    }
+
+    private checkStringInterpolation(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Note: Multi-line backtick strings are valid in ISL
+        // We check for balanced backticks at the document level, not line level
+        // This method now only checks for empty interpolation expressions
+        
+        // Check for invalid interpolation syntax (empty ${})
+        // But be careful - the backtick might not close on this line
+        const interpolationPattern = /\$\{([^}]*)\}/g;
+        let match;
+        while ((match = interpolationPattern.exec(line)) !== null) {
+            const expr = match[1];
+            if (expr.trim() === '') {
+                const startPos = match.index;
+                const range = new vscode.Range(lineNumber, startPos, lineNumber, startPos + match[0].length);
+                diagnostics.push(new vscode.Diagnostic(
+                    range,
+                    'Empty interpolation expression',
+                    vscode.DiagnosticSeverity.Warning
+                ));
+            }
+        }
+    }
+
+    private checkFunctionDeclaration(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Check function declarations
+        const funPattern = /^\s*(fun|modifier)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/;
+        const match = line.match(funPattern);
+        
+        if (match) {
+            const funcName = match[2];
+            // Could add more validation here (e.g., duplicate function names)
+        }
+
+        // Check for return statements outside functions
+        if (line.trim().startsWith('return ') && !this.isInsideFunction(document, lineNumber)) {
+            const range = new vscode.Range(lineNumber, line.indexOf('return'), lineNumber, line.indexOf('return') + 6);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                'Return statement outside of function',
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+    }
+
+    private checkControlFlow(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Check for proper control flow syntax
+        const trimmed = line.trim();
+        
+        // Check if/else/endif
+        if (trimmed.startsWith('if ') && !trimmed.includes('(')) {
+            const range = new vscode.Range(lineNumber, 0, lineNumber, line.length);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                'If statement requires parentheses around condition',
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+
+        // Check foreach
+        if (trimmed.startsWith('foreach ') && !trimmed.includes(' in ')) {
+            const range = new vscode.Range(lineNumber, 0, lineNumber, line.length);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                'Foreach loop requires "in" keyword',
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+    }
+
+    private checkBalancedBraces(text: string, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        let braceCount = 0;
+        let bracketCount = 0;
+        let parenCount = 0;
+
+        const lines = text.split('\n');
+        
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            
+            // Skip comments
+            const commentIndex = Math.min(
+                line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+                line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+            );
+            const checkLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+            braceCount += (checkLine.match(/\{/g) || []).length - (checkLine.match(/\}/g) || []).length;
+            bracketCount += (checkLine.match(/\[/g) || []).length - (checkLine.match(/\]/g) || []).length;
+            parenCount += (checkLine.match(/\(/g) || []).length - (checkLine.match(/\)/g) || []).length;
+        }
+
+        if (braceCount !== 0) {
+            const range = new vscode.Range(0, 0, 0, 0);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                `Unbalanced braces: ${braceCount > 0 ? 'missing closing' : 'extra closing'} brace(s)`,
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+
+        if (bracketCount !== 0) {
+            const range = new vscode.Range(0, 0, 0, 0);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                `Unbalanced brackets: ${bracketCount > 0 ? 'missing closing' : 'extra closing'} bracket(s)`,
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+
+        if (parenCount !== 0) {
+            const range = new vscode.Range(0, 0, 0, 0);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                `Unbalanced parentheses: ${parenCount > 0 ? 'missing closing' : 'extra closing'} parenthesis/parentheses`,
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+    }
+
+    private checkBalancedBackticks(text: string, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Check for balanced backticks across the entire document
+        // Backtick strings can span multiple lines in ISL
+        
+        const lines = text.split('\n');
+        let backtickCount = 0;
+        let lastBacktickLine = -1;
+        let lastBacktickCol = -1;
+        
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            
+            // Process each character to properly handle escaped backticks
+            let inString = false;
+            let stringChar = '';
+            
+            for (let j = 0; j < line.length; j++) {
+                const char = line[j];
+                const prevChar = j > 0 ? line[j - 1] : '';
+                
+                // Skip escaped characters
+                if (prevChar === '\\') {
+                    continue;
+                }
+                
+                // Track single and double quoted strings (backticks don't nest inside them)
+                if ((char === '"' || char === "'") && !inString) {
+                    inString = true;
+                    stringChar = char;
+                    continue;
+                } else if (char === stringChar && inString) {
+                    inString = false;
+                    stringChar = '';
+                    continue;
+                }
+                
+                // Count backticks only outside of regular strings
+                if (char === '`' && !inString) {
+                    backtickCount++;
+                    lastBacktickLine = i;
+                    lastBacktickCol = j;
+                }
+            }
+        }
+        
+        // If backtick count is odd, we have an unclosed template literal
+        if (backtickCount % 2 !== 0 && lastBacktickLine >= 0) {
+            const range = new vscode.Range(lastBacktickLine, lastBacktickCol, lastBacktickLine, lastBacktickCol + 1);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                'Unclosed template literal (backtick string)',
+                vscode.DiagnosticSeverity.Error
+            ));
+        }
+    }
+
+    private checkControlFlowBalance(text: string, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        const lines = text.split('\n');
+        
+        const controlFlowStack: Array<{ type: string, line: number, isBlock: boolean }> = [];
+
+        for (let i = 0; i < lines.length; i++) {
+            const fullLine = lines[i];
+            
+            // Skip comments
+            const commentIndex = Math.min(
+                fullLine.indexOf('//') !== -1 ? fullLine.indexOf('//') : Infinity,
+                fullLine.indexOf('#') !== -1 ? fullLine.indexOf('#') : Infinity
+            );
+            const line = (commentIndex !== Infinity ? fullLine.substring(0, commentIndex) : fullLine).trim();
+            
+            // Skip empty lines
+            if (!line) {
+                continue;
+            }
+
+            // Check for control flow keywords (can appear anywhere in the line for expression forms)
+            // Use word boundaries (\b) to avoid matching partial words
+            
+            // Distinguish between block statements and inline expressions for all control flow constructs
+            // Block statements: start at beginning of line (after whitespace) - require end keyword
+            // Inline expressions: preceded by = or : (assignment/property) - can span multiple lines
+            //                     BUT if terminated with ; or , on same line, they're complete
+            
+            // IF statements
+            const blockIfMatches = line.match(/^\s*if[\s(]/g) || [];
+            const inlineIfMatches = line.match(/[=:>]\s*if[\s(]/g) || [];
+            const endifMatches = line.match(/\bendif\b/g) || [];
+            
+            // SWITCH statements  
+            const blockSwitchMatches = line.match(/^\s*switch[\s(]/g) || [];
+            const inlineSwitchMatches = line.match(/[=:>]\s*switch[\s(]/g) || [];
+            const endswitchMatches = line.match(/\bendswitch\b/g) || [];
+            
+            // FOREACH loops
+            const blockForeachMatches = line.match(/^\s*foreach\s/g) || [];
+            const inlineForeachMatches = line.match(/[=:>]\s*foreach\s/g) || [];
+            const endforMatches = line.match(/\bendfor\b/g) || [];
+            
+            // WHILE loops
+            const blockWhileMatches = line.match(/^\s*while[\s(]/g) || [];
+            const inlineWhileMatches = line.match(/[=:>]\s*while[\s(]/g) || [];
+            const endwhileMatches = line.match(/\bendwhile\b/g) || [];
+            
+            // Check if inline expressions on this line are complete (have terminator ; or , and no end keyword)
+            const hasTerminator = line.includes(';') || line.includes(',');
+            const hasEndKeyword = endifMatches.length > 0 || endswitchMatches.length > 0 || 
+                                 endforMatches.length > 0 || endwhileMatches.length > 0;
+            const inlineIsComplete = hasTerminator && !hasEndKeyword;
+            
+            // Push opening keywords
+            // - Always push block statements (marked as isBlock: true)
+            // - Only push inline statements if they're NOT complete on this line (marked as isBlock: false)
+            // - Inline statements can end with } instead of endif, so we won't report unclosed errors for them
+            for (let j = 0; j < blockIfMatches.length; j++) {
+                controlFlowStack.push({ type: 'if', line: i, isBlock: true });
+            }
+            if (!inlineIsComplete) {
+                for (let j = 0; j < inlineIfMatches.length; j++) {
+                    controlFlowStack.push({ type: 'if', line: i, isBlock: false });
+                }
+            }
+            
+            for (let j = 0; j < blockSwitchMatches.length; j++) {
+                controlFlowStack.push({ type: 'switch', line: i, isBlock: true });
+            }
+            if (!inlineIsComplete) {
+                for (let j = 0; j < inlineSwitchMatches.length; j++) {
+                    controlFlowStack.push({ type: 'switch', line: i, isBlock: false });
+                }
+            }
+            
+            for (let j = 0; j < blockForeachMatches.length; j++) {
+                controlFlowStack.push({ type: 'foreach', line: i, isBlock: true });
+            }
+            if (!inlineIsComplete) {
+                for (let j = 0; j < inlineForeachMatches.length; j++) {
+                    controlFlowStack.push({ type: 'foreach', line: i, isBlock: false });
+                }
+            }
+            
+            for (let j = 0; j < blockWhileMatches.length; j++) {
+                controlFlowStack.push({ type: 'while', line: i, isBlock: true });
+            }
+            if (!inlineIsComplete) {
+                for (let j = 0; j < inlineWhileMatches.length; j++) {
+                    controlFlowStack.push({ type: 'while', line: i, isBlock: false });
+                }
+            }
+            
+            // Pop closing keywords - now that we track both block and inline, just pop when we find a match
+            
+            // Note: Explicit end keywords (endif, endfor, etc.) always close their control flow
+            // The }; or ], pattern is only for inline control flows that don't use explicit end keywords
+            
+            // For endif
+            for (let j = 0; j < endifMatches.length; j++) {
+                if (controlFlowStack.length === 0 || controlFlowStack[controlFlowStack.length - 1].type !== 'if') {
+                    const range = new vscode.Range(i, 0, i, fullLine.length);
+                    diagnostics.push(new vscode.Diagnostic(
+                        range,
+                        'Unexpected endif without matching if',
+                        vscode.DiagnosticSeverity.Error
+                    ));
+                } else {
+                    controlFlowStack.pop();
+                }
+            }
+            
+            // For endfor
+            for (let j = 0; j < endforMatches.length; j++) {
+                if (controlFlowStack.length === 0 || controlFlowStack[controlFlowStack.length - 1].type !== 'foreach') {
+                    const range = new vscode.Range(i, 0, i, fullLine.length);
+                    diagnostics.push(new vscode.Diagnostic(
+                        range,
+                        'Unexpected endfor without matching foreach',
+                        vscode.DiagnosticSeverity.Error
+                    ));
+                } else {
+                    controlFlowStack.pop();
+                }
+            }
+            
+            // For endwhile
+            for (let j = 0; j < endwhileMatches.length; j++) {
+                if (controlFlowStack.length === 0 || controlFlowStack[controlFlowStack.length - 1].type !== 'while') {
+                    const range = new vscode.Range(i, 0, i, fullLine.length);
+                    diagnostics.push(new vscode.Diagnostic(
+                        range,
+                        'Unexpected endwhile without matching while',
+                        vscode.DiagnosticSeverity.Error
+                    ));
+                } else {
+                    controlFlowStack.pop();
+                }
+            }
+            
+            // For endswitch
+            for (let j = 0; j < endswitchMatches.length; j++) {
+                if (controlFlowStack.length === 0 || controlFlowStack[controlFlowStack.length - 1].type !== 'switch') {
+                    const range = new vscode.Range(i, 0, i, fullLine.length);
+                    diagnostics.push(new vscode.Diagnostic(
+                        range,
+                        'Unexpected endswitch without matching switch',
+                        vscode.DiagnosticSeverity.Error
+                    ));
+                } else {
+                    controlFlowStack.pop();
+                }
+            }
+        }
+
+        // Check for unclosed control flow statements
+        // Only report errors for block statements, not inline expressions
+        // Inline expressions can use { } blocks instead of endif/endswitch/etc.
+        for (const item of controlFlowStack) {
+            if (item.isBlock) {
+                const range = new vscode.Range(item.line, 0, item.line, lines[item.line].length);
+                diagnostics.push(new vscode.Diagnostic(
+                    range,
+                    `Unclosed ${item.type} statement`,
+                    vscode.DiagnosticSeverity.Error
+                ));
+            }
+        }
+    }
+
+    private isInsideFunction(document: vscode.TextDocument, lineNumber: number): boolean {
+        // Track function scopes using brace counting
+        const functionStarts: number[] = [];
+        
+        for (let i = 0; i <= lineNumber; i++) {
+            const fullLine = document.lineAt(i).text;
+            
+            // Skip comments
+            const commentIndex = Math.min(
+                fullLine.indexOf('//') !== -1 ? fullLine.indexOf('//') : Infinity,
+                fullLine.indexOf('#') !== -1 ? fullLine.indexOf('#') : Infinity
+            );
+            const line = commentIndex !== Infinity ? fullLine.substring(0, commentIndex) : fullLine;
+            
+            // Check if this line has a function/modifier definition
+            if (line.match(/\b(fun|modifier)\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(/)) {
+                functionStarts.push(i);
+            }
+        }
+        
+        // For each function start, check if the current line is within its braces
+        for (const funcStart of functionStarts) {
+            let braceDepth = 0;
+            let foundOpeningBrace = false;
+            
+            for (let i = funcStart; i <= lineNumber; i++) {
+                const fullLine = document.lineAt(i).text;
+                const commentIndex = Math.min(
+                    fullLine.indexOf('//') !== -1 ? fullLine.indexOf('//') : Infinity,
+                    fullLine.indexOf('#') !== -1 ? fullLine.indexOf('#') : Infinity
+                );
+                const line = commentIndex !== Infinity ? fullLine.substring(0, commentIndex) : fullLine;
+                
+                // Count braces
+                const openBraces = (line.match(/\{/g) || []).length;
+                const closeBraces = (line.match(/\}/g) || []).length;
+                
+                braceDepth += openBraces;
+                if (openBraces > 0) {
+                    foundOpeningBrace = true;
+                }
+                braceDepth -= closeBraces;
+                
+                // If we're at the target line and inside this function's braces
+                if (i === lineNumber && foundOpeningBrace && braceDepth > 0) {
+                    return true;
+                }
+                
+                // If we've closed this function completely before reaching the target line
+                if (foundOpeningBrace && braceDepth === 0 && i < lineNumber) {
+                    break; // This function is closed, try the next one
+                }
+            }
+        }
+        
+        return false;
+    }
+
+    // Semantic validation methods
+
+    private extractUserDefinedFunctions(document: vscode.TextDocument): Set {
+        const functions = new Set();
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        for (const line of lines) {
+            // Match function definitions: fun functionName(
+            const funMatch = line.match(/^\s*fun\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/);
+            if (funMatch) {
+                functions.add(funMatch[1]);
+            }
+        }
+
+        return functions;
+    }
+
+    private extractUserDefinedModifiers(document: vscode.TextDocument): Set {
+        const modifiers = new Set();
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        for (const line of lines) {
+            // Match modifier definitions: modifier modifierName(
+            const modMatch = line.match(/^\s*modifier\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/);
+            if (modMatch) {
+                modifiers.add(modMatch[1]);
+            }
+        }
+
+        return modifiers;
+    }
+
+    private extractPaginationVariables(document: vscode.TextDocument): Map {
+        const paginationVars = new Map(); // variable name -> pagination type
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        for (const line of lines) {
+            // Match @.Pagination.[Type]( $varName, ... )
+            const cursorMatch = line.match(/@\.Pagination\.Cursor\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (cursorMatch) {
+                paginationVars.set(cursorMatch[1], 'Cursor');
+            }
+            
+            const offsetMatch = line.match(/@\.Pagination\.Offset\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (offsetMatch) {
+                paginationVars.set(offsetMatch[1], 'Offset');
+            }
+            
+            const pageMatch = line.match(/@\.Pagination\.Page\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (pageMatch) {
+                paginationVars.set(pageMatch[1], 'Page');
+            }
+            
+            const keysetMatch = line.match(/@\.Pagination\.Keyset\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (keysetMatch) {
+                paginationVars.set(keysetMatch[1], 'Keyset');
+            }
+            
+            const dateMatch = line.match(/@\.Pagination\.Date\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (dateMatch) {
+                paginationVars.set(dateMatch[1], 'Date');
+            }
+        }
+
+        return paginationVars;
+    }
+    
+    private extractDeclaredVariables(document: vscode.TextDocument): Map {
+        const variables = new Map(); // variable name -> first declaration line
+        const text = document.getText();
+        const lines = text.split('\n');
+
+        for (let i = 0; i < lines.length; i++) {
+            const line = lines[i];
+            
+            // Match variable declarations: $varName = ... or $varName: ...
+            const varDeclPattern = /\$([a-zA-Z_][a-zA-Z0-9_]*)\s*[=:]/g;
+            let match;
+            
+            while ((match = varDeclPattern.exec(line)) !== null) {
+                const varName = match[1];
+                if (!variables.has(varName)) {
+                    variables.set(varName, i);
+                }
+            }
+
+            // Also track function parameters as declared variables
+            const funParamMatch = line.match(/^\s*(fun|modifier)\s+[a-zA-Z_][a-zA-Z0-9_]*\s*\(([^)]*)\)/);
+            if (funParamMatch) {
+                const params = funParamMatch[2];
+                const paramNames = params.split(',').map(p => p.trim().replace(/^\$/, ''));
+                for (const param of paramNames) {
+                    if (param && !variables.has(param)) {
+                        variables.set(param, i);
+                    }
+                }
+            }
+
+            // Track foreach loop variables: foreach $item in $items
+            // Creates both $item and $itemIndex (zero-based index)
+            const foreachMatch = line.match(/foreach\s+\$([a-zA-Z_][a-zA-Z0-9_]*)\s+in/);
+            if (foreachMatch) {
+                const varName = foreachMatch[1];
+                if (!variables.has(varName)) {
+                    variables.set(varName, i);
+                }
+                
+                // Also add the index variable: $iteratorIndex
+                const indexVarName = varName + 'Index';
+                if (!variables.has(indexVarName)) {
+                    variables.set(indexVarName, i);
+                }
+            }
+            
+            // Track pagination function parameters: @.Pagination.[Type]( $varName, ... )
+            // The first parameter to pagination functions is a variable declaration
+            const paginationMatch = line.match(/@\.Pagination\.[A-Za-z_][A-Za-z0-9_]*\s*\(\s*\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            if (paginationMatch) {
+                const varName = paginationMatch[1];
+                if (!variables.has(varName)) {
+                    variables.set(varName, i);
+                }
+            }
+        }
+
+        return variables;
+    }
+
+    private checkFunctionCalls(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument, userDefinedFunctions: Set, extensions: import('./extensions').IslExtensions) {
+        // Skip comments - only check code part
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+        
+        // Check for @.This.functionName() or @.functionName() calls
+        const functionCallPattern = /@\.(?:This\.)?([a-zA-Z_][a-zA-Z0-9_]*)\s*\(/g;
+        let match;
+
+        while ((match = functionCallPattern.exec(codeOnlyLine)) !== null) {
+            const funcName = match[1];
+            
+            // Skip if it's a built-in function, user-defined function, or custom extension function
+            if (this.builtInFunctions.has(funcName) || userDefinedFunctions.has(funcName) || extensions.functions.has(funcName)) {
+                continue;
+            }
+
+            // Check if it's a namespaced built-in (like Date.now, Math.sum)
+            const fullMatch = match[0];
+            let isBuiltIn = false;
+            for (const builtIn of this.builtInFunctions) {
+                if (fullMatch.includes(builtIn.split('.')[1])) {
+                    isBuiltIn = true;
+                    break;
+                }
+            }
+
+            if (!isBuiltIn) {
+                const startPos = match.index + match[0].indexOf(funcName);
+                const range = new vscode.Range(lineNumber, startPos, lineNumber, startPos + funcName.length);
+                diagnostics.push(new vscode.Diagnostic(
+                    range,
+                    `Function '${funcName}' is not defined`,
+                    vscode.DiagnosticSeverity.Warning
+                ));
+            }
+        }
+    }
+
+    private checkModifierUsage(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument, userDefinedModifiers: Set, extensions: import('./extensions').IslExtensions) {
+        // Skip comments - only check code part
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+        
+        // Check for | modifierName usage (including multi-level like regex.find or Math.sum)
+        const modifierPattern = /\|\s*([a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\s*(?:\(|$|\|)/g;
+        let match;
+
+        while ((match = modifierPattern.exec(codeOnlyLine)) !== null) {
+            const modifierName = match[1];
+            
+            // Check if it's a user-defined modifier or custom extension modifier
+            if (userDefinedModifiers.has(modifierName) || extensions.modifiers.has(modifierName)) {
+                continue;
+            }
+            
+            // Check if it's a built-in modifier (exact match)
+            if (this.builtInModifiers.has(modifierName)) {
+                continue;
+            }
+            
+            // Check if it matches a wildcard pattern (e.g., regex.* matches regex.find)
+            let isBuiltIn = false;
+            for (const builtIn of this.builtInModifiers) {
+                if (builtIn.endsWith('.*')) {
+                    const prefix = builtIn.slice(0, -1); // Remove the *
+                    if (modifierName.startsWith(prefix)) {
+                        isBuiltIn = true;
+                        break;
+                    }
+                }
+            }
+            
+            // Check if it's also in the builtInFunctions set (Math.sum, etc. can be used as modifiers)
+            if (this.builtInFunctions.has(modifierName)) {
+                isBuiltIn = true;
+            }
+            
+            if (isBuiltIn) {
+                continue;
+            }
+
+            const startPos = match.index + match[0].indexOf(modifierName);
+            const range = new vscode.Range(lineNumber, startPos, lineNumber, startPos + modifierName.length);
+            diagnostics.push(new vscode.Diagnostic(
+                range,
+                `Modifier '${modifierName}' is not defined`,
+                vscode.DiagnosticSeverity.Warning
+            ));
+        }
+    }
+
+    private checkVariableUsage(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument, declaredVariables: Map) {
+        // Skip comments - remove everything after // or #
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+        
+        // Skip if the entire line is a comment
+        if (codeOnlyLine.trim() === '') {
+            return;
+        }
+
+        // Check if this line has an assignment (variable on left side of = or :)
+        // Match: $var = ... or $var.prop = ... or $var.prop.nested = ... or prop: $var or prop: value
+        const assignmentMatch = codeOnlyLine.match(/^(\s*)(\$[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)\s*[=:]\s*(.+)/);
+        if (assignmentMatch) {
+            const leftSide = assignmentMatch[2]; // The variable being assigned to
+            const rightSide = assignmentMatch[3]; // The value being assigned
+            
+            // Extract the base variable from the left side (e.g., $var from $var.prop.nested)
+            const baseVarMatch = leftSide.match(/\$([a-zA-Z_][a-zA-Z0-9_]*)/);
+            const baseVarBeingDeclared = baseVarMatch ? baseVarMatch[1] : null;
+            
+            // Only check variables on the RIGHT side of assignment
+            // But exclude the base variable being declared from the check
+            this.checkVariablesInExpression(rightSide, lineNumber, diagnostics, declaredVariables, codeOnlyLine.indexOf(rightSide), baseVarBeingDeclared);
+            return;
+        }
+        
+        // Also check for object property syntax: propertyName: value (without $ on left)
+        const propertyMatch = codeOnlyLine.match(/^(\s*)([a-zA-Z_][a-zA-Z0-9_]*)\s*:\s*(.+)/);
+        if (propertyMatch) {
+            const rightSide = propertyMatch[3];
+            // Check variables on the right side of the colon
+            this.checkVariablesInExpression(rightSide, lineNumber, diagnostics, declaredVariables, codeOnlyLine.indexOf(rightSide), null);
+            return;
+        }
+
+        // Check all variable usages in the code part of the line (not comments)
+        this.checkVariablesInExpression(codeOnlyLine, lineNumber, diagnostics, declaredVariables, 0, null);
+    }
+
+    private checkVariablesInExpression(expression: string, lineNumber: number, diagnostics: vscode.Diagnostic[], declaredVariables: Map, offset: number, excludeVar: string | null) {
+        // Find all variable references: $varName or $varName.property
+        const varPattern = /\$([a-zA-Z_][a-zA-Z0-9_]*)(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*/g;
+        let match;
+
+        while ((match = varPattern.exec(expression)) !== null) {
+            const baseVarName = match[1]; // Just the base variable name without $
+            
+            // Skip special variables created automatically by modifiers and contexts:
+            // - it: current item in reduce, general iteration contexts
+            // - fit: current item being filtered in filter()
+            // - acc: accumulator in reduce()
+            // - index: index in iteration contexts
+            // - key, value: key-value iteration
+            // - this, This: self-reference to current context/function
+            const specialVars = ['it', 'fit', 'acc', 'index', 'key', 'value', 'this', 'This'];
+            if (specialVars.includes(baseVarName)) {
+                continue;
+            }
+
+            // Skip the variable being declared on this line (if any)
+            if (excludeVar && baseVarName === excludeVar) {
+                continue;
+            }
+
+            // Check if variable has been declared
+            if (!declaredVariables.has(baseVarName)) {
+                const startPos = offset + match.index;
+                const range = new vscode.Range(lineNumber, startPos, lineNumber, startPos + match[0].length);
+                diagnostics.push(new vscode.Diagnostic(
+                    range,
+                    `Variable '$${baseVarName}' is used before being declared`,
+                    vscode.DiagnosticSeverity.Warning
+                ));
+            }
+        }
+    }
+
+    private checkLongObjectDeclaration(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Check for long single-line object declarations that should be formatted
+        if (line.length < 100) {
+            return;
+        }
+
+        // Skip comments
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+        // Check if line contains object with multiple properties (at least 2 colons indicating properties)
+        const objectMatch = codeOnlyLine.match(/\{[^}]*:[^}]*:[^}]*\}/);
+        if (!objectMatch) {
+            return;
+        }
+
+        // Find the position of the opening brace
+        const bracePos = codeOnlyLine.indexOf('{');
+        if (bracePos === -1) {
+            return;
+        }
+
+        const range = new vscode.Range(lineNumber, bracePos, lineNumber, bracePos + 1);
+        const diagnostic = new vscode.Diagnostic(
+            range,
+            'Long object declaration can be formatted on multiple lines',
+            vscode.DiagnosticSeverity.Hint
+        );
+        diagnostic.code = 'format-object';
+        diagnostics.push(diagnostic);
+    }
+
+    private checkUnnecessaryStringInterpolation(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Skip comments
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+        // Check for ${$variable} pattern (without dots - simple variables only)
+        const unnecessaryInterpolation = /\$\{(\$[a-zA-Z_][a-zA-Z0-9_]*)\}/g;
+        let match;
+
+        while ((match = unnecessaryInterpolation.exec(codeOnlyLine)) !== null) {
+            const fullMatch = match[0]; // ${$variable}
+            const variable = match[1];  // $variable
+
+            // Only flag simple variables (no property access)
+            if (!variable.includes('.')) {
+                const startPos = match.index;
+                const endPos = startPos + fullMatch.length;
+                const range = new vscode.Range(lineNumber, startPos, lineNumber, endPos);
+                
+                const diagnostic = new vscode.Diagnostic(
+                    range,
+                    `Unnecessary braces around ${variable} in string interpolation`,
+                    vscode.DiagnosticSeverity.Hint
+                );
+                diagnostic.code = 'simplify-interpolation';
+                diagnostics.push(diagnostic);
+            }
+        }
+    }
+
+    private checkDefaultModifier(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Skip comments
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+        // Check for | default() pattern
+        const defaultPattern = /\|\s*(default)\s*\(/g;
+        let match;
+
+        while ((match = defaultPattern.exec(codeOnlyLine)) !== null) {
+            const startPos = match.index;
+            const endPos = startPos + match[0].length - 1; // Exclude the opening paren
+            const range = new vscode.Range(lineNumber, startPos, lineNumber, endPos);
+            
+            const diagnostic = new vscode.Diagnostic(
+                range,
+                'Consider using ?? operator instead of | default()',
+                vscode.DiagnosticSeverity.Hint
+            );
+            diagnostic.code = 'use-coalesce-operator';
+            diagnostics.push(diagnostic);
+        }
+    }
+
+    private checkPaginationPropertyAccess(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument, paginationVariables: Map) {
+        // Skip comments
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+        
+        // Find pagination variable property access: $varName.propertyName
+        const propertyAccessPattern = /\$([a-zA-Z_][a-zA-Z0-9_]*)\.([a-zA-Z_][a-zA-Z0-9_]*)/g;
+        let match;
+        
+        while ((match = propertyAccessPattern.exec(codeOnlyLine)) !== null) {
+            const varName = match[1];
+            const propertyName = match[2];
+            
+            if (paginationVariables.has(varName)) {
+                const paginationType = paginationVariables.get(varName)!;
+                const validProperties = this.getValidPaginationProperties(paginationType);
+                
+                if (!validProperties.includes(propertyName)) {
+                    const startPos = match.index + match[0].indexOf(propertyName);
+                    const range = new vscode.Range(lineNumber, startPos, lineNumber, startPos + propertyName.length);
+                    
+                    const validPropsStr = validProperties.join(', ');
+                    diagnostics.push(new vscode.Diagnostic(
+                        range,
+                        `Invalid property '${propertyName}' for pagination ${paginationType}. Valid properties are: ${validPropsStr}`,
+                        vscode.DiagnosticSeverity.Error
+                    ));
+                }
+            }
+        }
+    }
+    
+    private getValidPaginationProperties(paginationType: string): string[] {
+        switch (paginationType) {
+            case 'Cursor':
+                return ['current', 'next'];
+            case 'Page':
+                return ['startIndex', 'pageSize', 'page', 'fromOffset', 'toOffset', 'hasMorePages'];
+            case 'Date':
+                return ['startDate', 'endDate', 'page'];
+            case 'Offset':
+                // Placeholder - will be filled in next request
+                return [];
+            case 'Keyset':
+                // Placeholder - will be filled in next request
+                return [];
+            default:
+                return [];
+        }
+    }
+    
+    private checkColonAssignment(line: string, lineNumber: number, diagnostics: vscode.Diagnostic[], document: vscode.TextDocument) {
+        // Skip comments
+        const commentIndex = Math.min(
+            line.indexOf('//') !== -1 ? line.indexOf('//') : Infinity,
+            line.indexOf('#') !== -1 ? line.indexOf('#') : Infinity
+        );
+        const codeOnlyLine = commentIndex !== Infinity ? line.substring(0, commentIndex) : line;
+
+        // Check for variable assignment using : instead of =
+        // Match: $varName: (at the start of line, optionally with whitespace)
+        const colonAssignmentPattern = /^(\s*)(\$[a-zA-Z_][a-zA-Z0-9_]*(?:\.[a-zA-Z_][a-zA-Z0-9_]*)*)(\s*)(:)/;
+        const match = codeOnlyLine.match(colonAssignmentPattern);
+
+        if (match) {
+            const colonPos = match.index! + match[1].length + match[2].length + match[3].length;
+            const range = new vscode.Range(lineNumber, colonPos, lineNumber, colonPos + 1);
+            
+            const diagnostic = new vscode.Diagnostic(
+                range,
+                'Use = instead of : for variable assignment',
+                vscode.DiagnosticSeverity.Hint
+            );
+            diagnostic.code = 'use-equals-assignment';
+            diagnostics.push(diagnostic);
+        }
+    }
+}
+
diff --git a/plugin/syntaxes/isl.tmLanguage.json b/plugin/syntaxes/isl.tmLanguage.json
new file mode 100644
index 0000000..7cd796a
--- /dev/null
+++ b/plugin/syntaxes/isl.tmLanguage.json
@@ -0,0 +1,464 @@
+{
+  "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
+  "name": "ISL",
+  "scopeName": "source.isl",
+  "patterns": [
+    { "include": "#comments" },
+    { "include": "#imports" },
+    { "include": "#types" },
+    { "include": "#functions" },
+    { "include": "#keywords" },
+    { "include": "#strings" },
+    { "include": "#numbers" },
+    { "include": "#constants" },
+    { "include": "#variables" },
+    { "include": "#operators" },
+    { "include": "#function-calls" },
+    { "include": "#modifiers" },
+    { "include": "#punctuation" }
+  ],
+  "repository": {
+    "comments": {
+      "patterns": [
+        {
+          "name": "comment.line.double-slash.isl",
+          "match": "//.*$"
+        },
+        {
+          "name": "comment.line.number-sign.isl",
+          "match": "#.*$"
+        },
+        {
+          "name": "comment.block.isl",
+          "begin": "/\\*",
+          "end": "\\*/"
+        }
+      ]
+    },
+    "imports": {
+      "patterns": [
+        {
+          "match": "\\b(import)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s+(from)\\s+(['\"])([^'\"]+)\\4",
+          "captures": {
+            "1": { "name": "keyword.control.import.isl" },
+            "2": { "name": "variable.other.readwrite.isl" },
+            "3": { "name": "keyword.control.from.isl" },
+            "4": { "name": "punctuation.definition.string.begin.isl" },
+            "5": { "name": "string.quoted.isl" }
+          }
+        }
+      ]
+    },
+    "types": {
+      "patterns": [
+        {
+          "match": "\\b(type)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s+(as|from)",
+          "captures": {
+            "1": { "name": "keyword.other.type.isl" },
+            "2": { "name": "entity.name.type.isl" },
+            "3": { "name": "keyword.other.isl" }
+          }
+        },
+        {
+          "name": "support.type.isl",
+          "match": "\\b(string|number|integer|boolean|object|array|any|null|text|date|datetime|binary)\\b"
+        }
+      ]
+    },
+    "functions": {
+      "patterns": [
+        {
+          "match": "\\b(fun|modifier)\\s+([A-Za-z_][A-Za-z0-9_]*)\\s*\\(",
+          "captures": {
+            "1": { "name": "keyword.control.function.isl" },
+            "2": { "name": "entity.name.function.isl" }
+          }
+        },
+        {
+          "name": "keyword.control.cache.isl",
+          "match": "\\b(cache)\\b"
+        }
+      ]
+    },
+    "keywords": {
+      "patterns": [
+        { "include": "#inline-if-expression" },
+        { "include": "#block-if-statement" },
+        {
+          "name": "keyword.control.loop.isl",
+          "match": "\\b(foreach|endfor|while|endwhile|parallel)\\b"
+        },
+        {
+          "name": "keyword.control.flow.isl",
+          "match": "\\b(return|in)\\b"
+        },
+        {
+          "name": "keyword.other.isl",
+          "match": "\\b(as|from|type|import)\\b"
+        },
+        {
+          "name": "keyword.operator.logical.isl",
+          "match": "\\b(and|or|not)\\b"
+        },
+        {
+          "name": "keyword.operator.comparison.isl",
+          "match": "\\b(contains|startsWith|endsWith|matches|is)\\b"
+        },
+        {
+          "name": "keyword.other.modifier.isl",
+          "match": "\\b(filter|map)\\b"
+        }
+      ]
+    },
+    "strings": {
+      "patterns": [
+        {
+          "name": "string.quoted.backtick.isl",
+          "begin": "`",
+          "end": "`",
+          "patterns": [
+            {
+              "name": "constant.character.escape.isl",
+              "match": "\\\\."
+            },
+            {
+              "name": "meta.embedded.expression.isl",
+              "begin": "(\\$)(\\{)",
+              "end": "\\}",
+              "beginCaptures": {
+                "1": { "name": "punctuation.definition.template-expression.begin.isl keyword.operator.interpolation.isl" },
+                "2": { "name": "punctuation.definition.template-expression.begin.isl keyword.control.interpolation.bracket.isl" }
+              },
+              "endCaptures": {
+                "0": { "name": "punctuation.definition.template-expression.end.isl keyword.control.interpolation.bracket.isl" }
+              },
+              "patterns": [
+                { "include": "#variables" },
+                { "include": "#operators" },
+                { "include": "#function-calls" },
+                { "include": "#modifiers" },
+                { "include": "#numbers" },
+                { "include": "#constants" }
+              ]
+            },
+            {
+              "name": "meta.embedded.math.isl",
+              "contentName": "meta.math-expression.content.isl",
+              "begin": "(\\{)(\\{)",
+              "end": "(\\})(\\})",
+              "beginCaptures": {
+                "0": { "name": "keyword.operator.math.isl punctuation.definition.math-expression.begin.isl" },
+                "1": { "name": "keyword.operator.math.bracket.isl" },
+                "2": { "name": "keyword.operator.math.bracket.isl" }
+              },
+              "endCaptures": {
+                "0": { "name": "keyword.operator.math.isl punctuation.definition.math-expression.end.isl" },
+                "1": { "name": "keyword.operator.math.bracket.isl" },
+                "2": { "name": "keyword.operator.math.bracket.isl" }
+              },
+              "patterns": [
+                { "include": "#numbers" },
+                { "include": "#variables" },
+                { "include": "#math-operators" },
+                { "include": "#function-calls" }
+              ]
+            },
+            {
+              "name": "variable.other.interpolated.isl",
+              "match": "(\\$)([A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*)",
+              "captures": {
+                "1": { "name": "punctuation.definition.variable.isl keyword.operator.interpolation.isl" },
+                "2": { "name": "variable.other.readwrite.isl" }
+              }
+            },
+            {
+              "name": "meta.function-call.interpolated.isl",
+              "match": "(@\\.)([A-Za-z_][A-Za-z0-9_.]*)(?:\\(([^)]*)\\))?",
+              "captures": {
+                "1": { "name": "punctuation.accessor.isl" },
+                "2": { "name": "entity.name.function.isl" }
+              }
+            }
+          ]
+        },
+        {
+          "name": "string.quoted.double.isl",
+          "begin": "\"",
+          "end": "\"",
+          "patterns": [
+            {
+              "name": "constant.character.escape.isl",
+              "match": "\\\\."
+            }
+          ]
+        },
+        {
+          "name": "string.quoted.single.isl",
+          "begin": "'",
+          "end": "'",
+          "patterns": [
+            {
+              "name": "constant.character.escape.isl",
+              "match": "\\\\."
+            }
+          ]
+        }
+      ]
+    },
+    "numbers": {
+      "patterns": [
+        {
+          "name": "constant.numeric.decimal.isl",
+          "match": "\\b([0-9]+\\.[0-9]+)\\b"
+        },
+        {
+          "name": "constant.numeric.integer.isl",
+          "match": "\\b([0-9]+)\\b"
+        }
+      ]
+    },
+    "constants": {
+      "patterns": [
+        {
+          "name": "constant.language.boolean.isl",
+          "match": "\\b(true|false)\\b"
+        },
+        {
+          "name": "constant.language.null.isl",
+          "match": "\\bnull\\b"
+        }
+      ]
+    },
+    "variables": {
+      "patterns": [
+        {
+          "name": "variable.other.readwrite.isl",
+          "match": "(\\$)([A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*|\\[[0-9]+\\]|\\[\\([^)]+\\)\\])*)",
+          "captures": {
+            "1": { "name": "punctuation.definition.variable.isl keyword.operator.variable.isl" },
+            "2": { "name": "variable.other.readwrite.isl" }
+          }
+        }
+      ]
+    },
+    "operators": {
+      "patterns": [
+        {
+          "name": "keyword.operator.comparison.isl",
+          "match": "==|!=|<=|>=|<|>|!contains|!startsWith|!endsWith|!in|!is|!matches"
+        },
+        {
+          "name": "keyword.operator.arithmetic.isl",
+          "match": "\\+|\\-|\\*|\\/"
+        },
+        {
+          "name": "keyword.operator.assignment.isl",
+          "match": "="
+        },
+        {
+          "name": "keyword.operator.logical.isl",
+          "match": "!|\\?"
+        },
+        {
+          "name": "keyword.operator.coalesce.isl",
+          "match": "\\?\\?"
+        },
+        {
+          "name": "keyword.operator.spread.isl",
+          "match": "\\.\\.\\."
+        },
+        {
+          "name": "keyword.operator.arrow.isl",
+          "match": "->"
+        }
+      ]
+    },
+    "math-operators": {
+      "patterns": [
+        {
+          "name": "keyword.operator.arithmetic.math.isl",
+          "match": "\\+|\\-|\\*|\\/|\\(|\\)"
+        }
+      ]
+    },
+    "function-calls": {
+      "patterns": [
+        {
+          "name": "meta.function-call.isl",
+          "match": "(@\\.)([A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*)",
+          "captures": {
+            "1": { "name": "punctuation.accessor.isl keyword.operator.accessor.isl" },
+            "2": { "name": "entity.name.function.isl" }
+          }
+        },
+        {
+          "name": "entity.name.function.isl",
+          "match": "\\b([A-Za-z_][A-Za-z0-9_]*)\\s*(?=\\()"
+        }
+      ]
+    },
+    "modifiers": {
+      "patterns": [
+        {
+          "name": "meta.modifier.namespace.isl",
+          "match": "(\\|)\\s*((to|date|Math|xml|csv|regex|encode|decode|crypto|join)(\\.)(\\w+))",
+          "captures": {
+            "1": { "name": "keyword.control.flow.pipe.isl" },
+            "2": { "name": "entity.name.function.isl" }
+          }
+        },
+        {
+          "name": "meta.modifier.isl",
+          "match": "(\\|)\\s*([A-Za-z_][A-Za-z0-9_]*)",
+          "captures": {
+            "1": { "name": "keyword.control.flow.pipe.isl" },
+            "2": { "name": "entity.name.function.isl" }
+          }
+        }
+      ]
+    },
+    "punctuation": {
+      "patterns": [
+        {
+          "name": "punctuation.separator.isl",
+          "match": "[,;:]"
+        },
+        {
+          "name": "punctuation.section.brackets.isl",
+          "match": "[\\[\\]\\(\\)\\{\\}]"
+        }
+      ]
+    },
+    "inline-if-expression": {
+      "patterns": [
+        {
+          "name": "meta.inline-if-expression.isl",
+          "begin": "\\b(if)\\s*(\\()",
+          "end": "(;)|(?=\\n)|(?=,)",
+          "beginCaptures": {
+            "1": { "name": "keyword.control.conditional.if.isl" },
+            "2": { "name": "punctuation.definition.condition.begin.isl" }
+          },
+          "endCaptures": {
+            "1": { "name": "punctuation.terminator.statement.isl" }
+          },
+          "patterns": [
+            {
+              "name": "meta.condition.isl",
+              "begin": "\\G",
+              "end": "\\)",
+              "endCaptures": {
+                "0": { "name": "punctuation.definition.condition.end.isl" }
+              },
+              "patterns": [
+                { "include": "#variables" },
+                { "include": "#operators" },
+                { "include": "#function-calls" },
+                { "include": "#constants" },
+                { "include": "#numbers" },
+                { "include": "#strings" },
+                {
+                  "name": "keyword.operator.logical.isl",
+                  "match": "\\b(and|or|not)\\b"
+                },
+                {
+                  "name": "keyword.operator.comparison.isl",
+                  "match": "\\b(contains|startsWith|endsWith|matches|is)\\b"
+                }
+              ]
+            },
+            {
+              "name": "keyword.control.conditional.else.isl",
+              "match": "\\b(else)\\b"
+            },
+            {
+              "name": "keyword.control.conditional.endif.isl",
+              "match": "\\b(endif)\\b"
+            },
+            { "include": "#strings" },
+            { "include": "#numbers" },
+            { "include": "#constants" },
+            { "include": "#variables" },
+            { "include": "#function-calls" },
+            { "include": "#modifiers" },
+            { "include": "#operators" }
+          ]
+        }
+      ]
+    },
+    "block-if-statement": {
+      "patterns": [
+        {
+          "name": "meta.block-if-statement.isl",
+          "begin": "^\\s*(if)\\s*(\\()",
+          "end": "\\b(endif)\\b",
+          "beginCaptures": {
+            "1": { "name": "keyword.control.conditional.if.isl" },
+            "2": { "name": "punctuation.definition.condition.begin.isl" }
+          },
+          "endCaptures": {
+            "1": { "name": "keyword.control.conditional.endif.isl" }
+          },
+          "patterns": [
+            {
+              "name": "meta.condition.isl",
+              "begin": "\\G",
+              "end": "\\)",
+              "endCaptures": {
+                "0": { "name": "punctuation.definition.condition.end.isl" }
+              },
+              "patterns": [
+                { "include": "#variables" },
+                { "include": "#operators" },
+                { "include": "#function-calls" },
+                { "include": "#constants" },
+                { "include": "#numbers" },
+                { "include": "#strings" },
+                {
+                  "name": "keyword.operator.logical.isl",
+                  "match": "\\b(and|or|not)\\b"
+                },
+                {
+                  "name": "keyword.operator.comparison.isl",
+                  "match": "\\b(contains|startsWith|endsWith|matches|is)\\b"
+                }
+              ]
+            },
+            {
+              "name": "keyword.control.conditional.else.isl",
+              "match": "\\b(else)\\b"
+            },
+            {
+              "include": "#comments"
+            },
+            {
+              "include": "#strings"
+            },
+            {
+              "include": "#numbers"
+            },
+            {
+              "include": "#constants"
+            },
+            {
+              "include": "#variables"
+            },
+            {
+              "include": "#operators"
+            },
+            {
+              "include": "#function-calls"
+            },
+            {
+              "include": "#modifiers"
+            }
+          ]
+        },
+        {
+          "name": "keyword.control.conditional.switch.isl",
+          "match": "\\b(switch|endswitch)\\b"
+        }
+      ]
+    }
+  }
+}
diff --git a/plugin/tsconfig.json b/plugin/tsconfig.json
new file mode 100644
index 0000000..80f178e
--- /dev/null
+++ b/plugin/tsconfig.json
@@ -0,0 +1,18 @@
+{
+  "compilerOptions": {
+    "module": "commonjs",
+    "target": "ES2020",
+    "lib": ["ES2020"],
+    "outDir": "out",
+    "rootDir": "src",
+    "sourceMap": true,
+    "strict": true,
+    "esModuleInterop": true,
+    "skipLibCheck": true,
+    "forceConsistentCasingInFileNames": true,
+    "resolveJsonModule": true
+  },
+  "include": ["src/**/*"],
+  "exclude": ["node_modules", ".vscode-test"]
+}
+