From 72fbd452f73d5b3cc981255b14c6ccced7958764 Mon Sep 17 00:00:00 2001 From: omarabid Date: Thu, 12 Feb 2026 09:58:05 +0000 Subject: [PATCH 01/21] chore(docs): update TOC --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 15e0d37..26f6dc6 100644 --- a/README.md +++ b/README.md @@ -14,19 +14,19 @@ - **Table of Contents** - [Features](#features) - - [CodeOwners](#codeowners-features) + - [CodeOwners Features](#codeowners-features) - [Installation](#installation) - [Pre-built Binaries](#pre-built-binaries) - [Installation Instructions](#installation-instructions) - [From Cargo](#from-cargo) - [From Source](#from-source) + - [From NPM](#from-npm) - [Quick Start](#quick-start) - [Commands](#commands) - - [CodeOwners](#codeowners-1) + - [CodeOwners](#codeowners) - [Parse CODEOWNERS](#parse-codeowners) - [List Files](#list-files) - [List Owners](#list-owners) From cd02164ad3c876e7eb7fc869982c476ac02ba081 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Mon, 2 Mar 2026 16:06:02 +0800 Subject: [PATCH 02/21] chore: bump version to 0.0.5 and update repository URL - Update codeinput and ci crates to version 0.0.5 - Change repository URL from CodeInputCorp/cli to code-input/cli - Add CHANGELOG entry for 0.0.5 with LSP server features --- CHANGELOG.md | 34 ++++++++++++++++++++++++++++++++++ ci/Cargo.toml | 6 +++--- codeinput/Cargo.toml | 4 ++-- 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b13789..120e748 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,35 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## [0.0.5] - 2025-03-02 + +### Added +- **LSP Server**: Language Server Protocol implementation for IDE integration + - `textDocument/hover`: Shows owners and tags when hovering over files + - `textDocument/codeLens`: Displays ownership annotations above files + - `textDocument/publishDiagnostics`: Warns about unowned files + - Multi-root workspace support +- **TCP Transport**: LSP server now supports TCP connections (`ci lsp --port `) +- **VS Code Extension**: Companion extension for Visual Studio Code (in `vscode-extension/`) + +### Changed +- Upgraded `utoipa` to 5.4.0 with schema fixes +- LSP feature is now opt-in via `--features lsp` cargo flag + +### Fixed +- Safe serialization of CodeLens arguments +- Output redirected to stderr for LSP compatibility + +## [0.0.4] - 2024-12-XX + +### Added +- `infer-owners` command for intelligent owner inference +- ARM64 runners for release builds (Linux, Windows, macOS) + +### Changed +- Dependency updates and formatting improvements + +## [0.0.3] - Previous Release + +Initial public release with core CODEOWNERS parsing and analysis features. diff --git a/ci/Cargo.toml b/ci/Cargo.toml index 26f0359..0e37b2e 100644 --- a/ci/Cargo.toml +++ b/ci/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "ci" -version = "0.0.4" +version = "0.0.5" authors = ["Abid Omar "] edition = "2021" -repository = "https://github.com/CodeInputCorp/cli" +repository = "https://github.com/code-input/cli" readme = "../README.md" license = "MIT" keywords = ["cli", "codeowners", "git", "tooling", "binary"] @@ -24,7 +24,7 @@ syslog = ["codeinput/syslog"] lsp = ["codeinput/tower-lsp", "codeinput/tokio", "tokio"] [dependencies] -codeinput = { version = "0.0.4", path = "../codeinput" } +codeinput = { version = "0.0.5", path = "../codeinput" } human-panic = { workspace = true } better-panic = { workspace = true } log = { workspace = true } diff --git a/codeinput/Cargo.toml b/codeinput/Cargo.toml index cdcad1f..ed7f8a8 100644 --- a/codeinput/Cargo.toml +++ b/codeinput/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "codeinput" -version = "0.0.4" +version = "0.0.5" authors = ["Abid Omar "] edition = "2021" -repository = "https://github.com/CodeInputCorp/cli" +repository = "https://github.com/code-input/cli" readme = "../README.md" license = "MIT" keywords = ["codeowners", "git", "parsing", "analysis", "tooling"] From 409f25210ee4b2263f8a6734adab8678586d573a Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Mon, 2 Mar 2026 16:28:25 +0800 Subject: [PATCH 03/21] fix: release action --- .github/workflows/release.yml | 96 +++++++---------------------------- 1 file changed, 18 insertions(+), 78 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1a4602e..d319644 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -116,85 +116,25 @@ jobs: with: path: artifacts - - name: Remove Same Release - uses: omarabid-forks/action-rollback@stable - continue-on-error: true - with: - tag: ${{ steps.vars.outputs.package_version }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create Release - id: create-release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.vars.outputs.package_version }} - release_name: Version ${{ steps.vars.outputs.package_version }} - body: ${{ steps.vars.outputs.package_name }} - ${{ steps.vars.outputs.package_version }} - draft: false - prerelease: false - - - name: Upload Linux x86_64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: artifacts/ci-linux-x86_64/ci - asset_name: ci-linux-x86_64 - asset_content_type: application/octet-stream - - - name: Upload Linux aarch64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: artifacts/ci-linux-aarch64/ci - asset_name: ci-linux-aarch64 - asset_content_type: application/octet-stream - - - name: Upload Windows x86_64 binary - uses: actions/upload-release-asset@v1 + - name: Create Release and Upload Assets env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: artifacts/ci-windows-x86_64.exe/ci.exe - asset_name: ci-windows-x86_64.exe - asset_content_type: application/octet-stream - - - name: Upload Windows aarch64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: artifacts/ci-windows-aarch64.exe/ci.exe - asset_name: ci-windows-aarch64.exe - asset_content_type: application/octet-stream - - - name: Upload macOS x86_64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: artifacts/ci-macos-x86_64/ci - asset_name: ci-macos-x86_64 - asset_content_type: application/octet-stream - - - name: Upload macOS aarch64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.create-release.outputs.upload_url }} - asset_path: artifacts/ci-macos-aarch64/ci - asset_name: ci-macos-aarch64 - asset_content_type: application/octet-stream + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.vars.outputs.package_version }} + PACKAGE_NAME: ${{ steps.vars.outputs.package_name }} + run: | + # Delete existing release if exists + gh release delete "$TAG" --yes || true + + # Create release + gh release create "$TAG" \ + --title "Version $TAG" \ + --notes "$PACKAGE_NAME - $TAG" \ + artifacts/ci-linux-x86_64/ci \ + artifacts/ci-linux-aarch64/ci \ + artifacts/ci-windows-x86_64.exe/ci.exe \ + artifacts/ci-windows-aarch64.exe/ci.exe \ + artifacts/ci-macos-x86_64/ci \ + artifacts/ci-macos-aarch64/ci - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1 From 15f6a959c844913bd90db92a7ac649efbdfdfb12 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Mon, 2 Mar 2026 19:51:07 +0800 Subject: [PATCH 04/21] feat(vscode): add initial VS Code extension for CODEOWNERS LSP integration Adds a new VS Code extension that integrates with the CodeInput LSP server to provide CODEOWNERS support including owner display, tags, and status bar. --- extensions/vscode/.gitignore | 33 + extensions/vscode/.vscodeignore | 17 + extensions/vscode/package.json | 133 + extensions/vscode/src/client.ts | 165 + extensions/vscode/src/downloader.ts | 145 + extensions/vscode/src/extension.ts | 198 ++ extensions/vscode/src/statusbar.ts | 121 + extensions/vscode/tsconfig.json | 16 + extensions/vscode/yarn.lock | 4354 +++++++++++++++++++++++++++ 9 files changed, 5182 insertions(+) create mode 100644 extensions/vscode/.gitignore create mode 100644 extensions/vscode/.vscodeignore create mode 100644 extensions/vscode/package.json create mode 100644 extensions/vscode/src/client.ts create mode 100644 extensions/vscode/src/downloader.ts create mode 100644 extensions/vscode/src/extension.ts create mode 100644 extensions/vscode/src/statusbar.ts create mode 100644 extensions/vscode/tsconfig.json create mode 100644 extensions/vscode/yarn.lock diff --git a/extensions/vscode/.gitignore b/extensions/vscode/.gitignore new file mode 100644 index 0000000..d61721c --- /dev/null +++ b/extensions/vscode/.gitignore @@ -0,0 +1,33 @@ +# Dependencies +node_modules/ + +# Build output +out/ +dist/ + +# VS Code extension package +*.vsix + +# Logs +*.log +yarn-debug.log* +yarn-error.log* + +# npm (migrated to yarn) +package-lock.json + +# OS files +.DS_Store +Thumbs.db + +# IDE +.idea/ +*.swp +*.swo + +# Test coverage +coverage/ + +# Temporary files +*.tmp +*.temp diff --git a/extensions/vscode/.vscodeignore b/extensions/vscode/.vscodeignore new file mode 100644 index 0000000..1681d2e --- /dev/null +++ b/extensions/vscode/.vscodeignore @@ -0,0 +1,17 @@ +.vscode/** +.vscode-test/** +src/** +node_modules/** +.gitignore +.yarnrc +.yarnrc.yml +.yarn/ +.pnp.cjs +.pnp.loader.mjs +yarn.lock +vsc-extension-quickstart.md +**/tsconfig.json +**/.eslintrc.json +**/*.map +**/*.ts +*.vsix diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json new file mode 100644 index 0000000..e728742 --- /dev/null +++ b/extensions/vscode/package.json @@ -0,0 +1,133 @@ +{ + "name": "codeinput", + "displayName": "CodeInput - CODEOWNERS Integration", + "description": "LSP-based CODEOWNERS integration for VS Code", + "version": "0.0.1", + "publisher": "codeinput", + "license": "MIT", + "engines": { + "vscode": "^1.74.0" + }, + "categories": [ + "Other", + "SCM Providers" + ], + "keywords": [ + "codeowners", + "git", + "ownership", + "lsp" + ], + "activationEvents": [ + "onLanguage:plaintext", + "workspaceContains:**/CODEOWNERS", + "workspaceContains:**/.github/CODEOWNERS", + "workspaceContains:**/.gitlab/CODEOWNERS" + ], + "main": "./out/extension.js", + "contributes": { + "commands": [ + { + "command": "codeinput.showOwners", + "title": "Show CODEOWNERS Owners", + "category": "CodeInput" + }, + { + "command": "codeinput.showTags", + "title": "Show CODEOWNERS Tags", + "category": "CodeInput" + }, + { + "command": "codeinput.addOwner", + "title": "Add CODEOWNERS Entry", + "category": "CodeInput" + }, + { + "command": "codeinput.refreshCache", + "title": "Refresh CODEOWNERS Cache", + "category": "CodeInput" + }, + { + "command": "codeinput.showInfo", + "title": "Show CODEOWNERS Info for Current File", + "category": "CodeInput" + } + ], + "configuration": { + "title": "CodeInput", + "properties": { + "codeinput.binaryPath": { + "type": "string", + "default": "ci-lsp", + "description": "Path to the codeinput LSP server binary" + }, + "codeinput.cacheFile": { + "type": "string", + "default": ".codeowners.cache", + "description": "Name of the cache file" + }, + "codeinput.showInStatusBar": { + "type": "boolean", + "default": true, + "description": "Show CODEOWNERS info in the status bar" + }, + "codeinput.showDiagnostics": { + "type": "boolean", + "default": true, + "description": "Show diagnostics for unowned files" + }, + "codeinput.lspTransport": { + "type": "string", + "enum": [ + "stdio", + "tcp" + ], + "default": "stdio", + "description": "Transport method for LSP communication" + }, + "codeinput.lspPort": { + "type": "number", + "default": 8123, + "description": "TCP port for LSP communication (when using tcp transport)" + } + } + }, + "menus": { + "commandPalette": [ + { + "command": "codeinput.showOwners", + "when": "false" + }, + { + "command": "codeinput.showTags", + "when": "false" + }, + { + "command": "codeinput.addOwner", + "when": "false" + } + ] + } + }, + "scripts": { + "vscode:prepublish": "yarn esbuild-base --minify", + "esbuild-base": "esbuild ./src/extension.ts --bundle --outfile=out/extension.js --external:vscode --format=cjs --platform=node", + "compile": "tsc -p ./", + "watch": "tsc -watch -p ./", + "lint": "eslint src --ext ts", + "package": "vsce package --no-yarn" + }, + "devDependencies": { + "@types/node": "^20.x", + "@types/vscode": "^1.74.0", + "@typescript-eslint/eslint-plugin": "^6.x", + "@typescript-eslint/parser": "^6.x", + "@vscode/vsce": "^3.7.1", + "esbuild": "^0.27.3", + "eslint": "^8.x", + "typescript": "^5.x" + }, + "dependencies": { + "vscode-languageclient": "^9.0.1" + } +} diff --git a/extensions/vscode/src/client.ts b/extensions/vscode/src/client.ts new file mode 100644 index 0000000..8aa5287 --- /dev/null +++ b/extensions/vscode/src/client.ts @@ -0,0 +1,165 @@ +import * as vscode from 'vscode'; +import { + LanguageClient, + LanguageClientOptions, + ServerOptions, + TransportKind +} from 'vscode-languageclient/node'; + +export interface FileOwnershipInfo { + path: string; + owners: Array<{ identifier: string; owner_type: string }>; + tags: Array<{ 0: string }>; + is_unowned: boolean; +} + +export class CodeInputClient { + private client: LanguageClient | undefined; + + constructor(private binaryPath: string) { + this.initializeClient(); + } + + private initializeClient(): void { + const config = vscode.workspace.getConfiguration('codeinput'); + const transport = config.get('lspTransport', 'stdio'); + const port = config.get('lspPort', 8123); + + let serverOptions: ServerOptions; + + if (transport === 'tcp') { + // TCP transport + serverOptions = (() => { + const socket = require('net').connect({ port }); + const result = { + reader: socket, + writer: socket + }; + return Promise.resolve(result); + }) as unknown as ServerOptions; + } else { + // STDIO transport (default) + serverOptions = { + command: this.binaryPath, + args: ['lsp'], + transport: TransportKind.stdio, + options: { + cwd: vscode.workspace.workspaceFolders?.[0]?.uri.fsPath + } + }; + } + + const clientOptions: LanguageClientOptions = { + documentSelector: [ + { scheme: 'file', pattern: '**/*' } + ], + synchronize: { + fileEvents: [ + vscode.workspace.createFileSystemWatcher('**/CODEOWNERS'), + vscode.workspace.createFileSystemWatcher('**/.github/CODEOWNERS'), + vscode.workspace.createFileSystemWatcher('**/.gitlab/CODEOWNERS') + ] + }, + outputChannelName: 'CodeInput LSP' + }; + + this.client = new LanguageClient( + 'codeinput', + 'CodeInput LSP', + serverOptions, + clientOptions + ); + } + + public async start(): Promise { + if (this.client) { + try { + await this.client.start(); + console.log('CodeInput LSP client started'); + } catch (error) { + console.error('Failed to start CodeInput LSP client:', error); + vscode.window.showErrorMessage( + `Failed to start CodeInput LSP: ${error}. Make sure the 'ci-lsp' binary is installed and in your PATH.` + ); + } + } + } + + public async stop(): Promise { + if (this.client) { + await this.client.stop(); + console.log('CodeInput LSP client stopped'); + } + } + + public async getFileOwnership(uri: vscode.Uri): Promise { + if (!this.client) { + return undefined; + } + + // Use the hover request to get ownership info + try { + const hover = await this.client.sendRequest('textDocument/hover', { + textDocument: { uri: uri.toString() }, + position: { line: 0, character: 0 } + }) as any; + + if (hover && hover.contents) { + // Parse hover contents to extract ownership info + return this.parseHoverContents(hover.contents, uri); + } + } catch (error) { + console.error('Error getting file ownership:', error); + } + + return undefined; + } + + private parseHoverContents(contents: any, uri: vscode.Uri): FileOwnershipInfo | undefined { + // The LSP server returns hover contents with owners and tags + // This is a simplified parser - in production you'd want more robust parsing + const info: FileOwnershipInfo = { + path: uri.fsPath, + owners: [], + tags: [], + is_unowned: false + }; + + if (Array.isArray(contents)) { + for (const item of contents) { + if (typeof item === 'string') { + if (item.includes('Owners:')) { + const ownersMatch = item.match(/\*\*Owners:\*\* (.+)/); + if (ownersMatch) { + const ownersStr = ownersMatch[1]; + if (ownersStr !== '(none)') { + info.owners = ownersStr.split(', ').map(o => ({ + identifier: o.replace(/`/g, ''), + owner_type: 'Unknown' + })); + } + } + } + if (item.includes('Tags:')) { + const tagsMatch = item.match(/\*\*Tags:\*\* (.+)/); + if (tagsMatch) { + const tagsStr = tagsMatch[1]; + info.tags = tagsStr.split(', ').map(t => ({ + 0: t.replace(/`#/g, '').replace(/`/g, '') + })); + } + } + if (item.includes('Warning')) { + info.is_unowned = true; + } + } + } + } + + return info; + } + + public isRunning(): boolean { + return this.client?.isRunning() === true; + } +} \ No newline at end of file diff --git a/extensions/vscode/src/downloader.ts b/extensions/vscode/src/downloader.ts new file mode 100644 index 0000000..6c437c8 --- /dev/null +++ b/extensions/vscode/src/downloader.ts @@ -0,0 +1,145 @@ +import * as vscode from 'vscode'; +import * as https from 'https'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as os from 'os'; +import { spawn } from 'child_process'; + +export class BinaryDownloader { + private readonly baseUrl = 'https://github.com/code-input/cli/releases/latest/download'; + + constructor(private context: vscode.ExtensionContext) {} + + async ensureBinary(): Promise { + const binaryName = this.getBinaryName(); + const binaryPath = this.getBinaryPath(binaryName); + + // Check if binary already exists and is executable + if (fs.existsSync(binaryPath)) { + if (await this.isBinaryWorking(binaryPath)) { + console.log(`[CodeInput] Found working binary at ${binaryPath}`); + return binaryPath; + } else { + console.log(`[CodeInput] Binary exists at ${binaryPath} but not working, removing...`); + fs.unlinkSync(binaryPath); + } + } + + // Download the binary + return await this.downloadBinary(binaryName, binaryPath); + } + + private async isBinaryWorking(binaryPath: string): Promise { + return new Promise((resolve) => { + const proc = spawn(binaryPath, ['lsp', '--help']); + proc.on('error', () => resolve(false)); + proc.on('exit', (code) => resolve(code === 0)); + // Timeout after 2 seconds + setTimeout(() => { + proc.kill(); + resolve(false); + }, 2000); + }); + } + + private getBinaryName(): string { + const platform = os.platform(); + const arch = os.arch(); + + let platformSuffix: string; + switch (platform) { + case 'linux': platformSuffix = 'linux'; break; + case 'darwin': platformSuffix = 'darwin'; break; + case 'win32': platformSuffix = 'windows'; break; + default: platformSuffix = 'linux'; // fallback + } + + let archSuffix: string; + switch (arch) { + case 'x64': archSuffix = 'x64'; break; + case 'arm64': archSuffix = 'arm64'; break; + default: archSuffix = 'x64'; // fallback + } + + const ext = platform === 'win32' ? '.exe' : ''; + return `ci-lsp-${platformSuffix}-${archSuffix}${ext}`; + } + + private getBinaryPath(binaryName: string): string { + const extensionDir = this.context.globalStorageUri.fsPath; + // Ensure directory exists + if (!fs.existsSync(extensionDir)) { + fs.mkdirSync(extensionDir, { recursive: true }); + } + return path.join(extensionDir, binaryName); + } + + private async downloadBinary(binaryName: string, destPath: string): Promise { + const url = `${this.baseUrl}/${binaryName}`; + + return await vscode.window.withProgress({ + location: vscode.ProgressLocation.Notification, + title: `Downloading codeinput-lsp (${binaryName})...`, + cancellable: false + }, async (progress) => { + try { + await this.downloadFile(url, destPath, progress); + + // Make executable on Unix + if (os.platform() !== 'win32') { + fs.chmodSync(destPath, 0o755); + } + + vscode.window.showInformationMessage('codeinput-lsp downloaded successfully!'); + return destPath; + } catch (error) { + vscode.window.showErrorMessage(`Failed to download codeinput-lsp: ${error}`); + return undefined; + } + }); + } + + private downloadFile(url: string, destPath: string, progress: vscode.Progress<{ message?: string; increment?: number }>): Promise { + return new Promise((resolve, reject) => { + const file = fs.createWriteStream(destPath); + + https.get(url, { headers: { 'User-Agent': 'codeinput-vscode' } }, (response) => { + // Handle redirects + if (response.statusCode === 302 || response.statusCode === 301) { + const redirectUrl = response.headers.location; + if (redirectUrl) { + file.close(); + fs.unlinkSync(destPath); + this.downloadFile(redirectUrl, destPath, progress).then(resolve).catch(reject); + return; + } + } + + if (response.statusCode !== 200) { + reject(new Error(`Download failed with status ${response.statusCode}`)); + return; + } + + const totalBytes = parseInt(response.headers['content-length'] || '0', 10); + let downloadedBytes = 0; + + response.on('data', (chunk: Buffer) => { + downloadedBytes += chunk.length; + if (totalBytes > 0) { + const percent = Math.round((downloadedBytes / totalBytes) * 100); + progress.report({ message: `${percent}%` }); + } + }); + + response.pipe(file); + file.on('finish', () => { + file.close(); + resolve(); + }); + }).on('error', (err) => { + fs.unlinkSync(destPath); + reject(err); + }); + }); + } +} diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts new file mode 100644 index 0000000..902dd94 --- /dev/null +++ b/extensions/vscode/src/extension.ts @@ -0,0 +1,198 @@ +import * as vscode from 'vscode'; +import { CodeInputClient } from './client'; +import { StatusBarManager } from './statusbar'; +import { BinaryDownloader } from './downloader'; +import { spawn } from 'child_process'; + +let client: CodeInputClient | undefined; +let statusBar: StatusBarManager | undefined; + +async function checkBinary(binaryPath: string): Promise { + return new Promise((resolve) => { + const proc = spawn(binaryPath, ['lsp', '--help']); + proc.on('error', () => resolve(false)); + proc.on('exit', (code) => resolve(code === 0)); + // Timeout after 2 seconds + setTimeout(() => { + proc.kill(); + resolve(false); + }, 2000); + }); +} + +export async function activate(context: vscode.ExtensionContext) { + console.log('CodeInput extension is now active'); + + // Check if custom binary path is set + const config = vscode.workspace.getConfiguration('codeinput'); + const userBinaryPath = config.get('binaryPath', 'ci-lsp'); + + let finalBinaryPath: string | undefined; + let binarySource = 'unknown'; + + // If user set a custom path, use it + if (userBinaryPath !== 'ci-lsp') { + console.log(`[CodeInput] Checking user-specified binary: ${userBinaryPath}`); + const exists = await checkBinary(userBinaryPath); + if (exists) { + finalBinaryPath = userBinaryPath; + binarySource = 'user-config'; + console.log(`[CodeInput] Using user-specified binary: ${finalBinaryPath}`); + } else { + console.error(`[CodeInput] User-specified binary not found: ${userBinaryPath}`); + vscode.window.showErrorMessage( + `Custom binary not found: ${userBinaryPath}. Please check the path or install codeinput-lsp.` + ); + return; + } + } else { + // Try to download ci-lsp first + console.log('[CodeInput] Attempting to download ci-lsp binary...'); + const downloader = new BinaryDownloader(context); + const downloadedPath = await downloader.ensureBinary(); + + if (downloadedPath) { + finalBinaryPath = downloadedPath; + binarySource = 'downloaded'; + console.log(`[CodeInput] Using downloaded binary: ${finalBinaryPath}`); + } else { + console.log('[CodeInput] Download failed, checking for existing ci binary with LSP support...'); + // Download failed, check if `ci` with LSP exists + const ciExists = await checkBinary('ci'); + if (ciExists) { + binarySource = 'fallback-ci'; + finalBinaryPath = 'ci'; + console.log('[CodeInput] Using fallback ci binary with LSP support'); + vscode.window.showInformationMessage( + 'Using existing `ci` binary with LSP support. Consider downloading `ci-lsp` for better performance.' + ); + } else { + // Neither works + console.error('[CodeInput] No usable binary found (tried downloading ci-lsp and using ci)'); + vscode.window.showErrorMessage( + 'codeinput-lsp not found. Please install it: curl -L https://github.com/code-input/cli/releases/latest/download/ci-lsp-linux-x64 -o ~/bin/ci-lsp && chmod +x ~/bin/ci-lsp' + ); + return; + } + } + } + + // Initialize the LSP client with the binary path + console.log(`[CodeInput] Starting LSP client with binary: ${finalBinaryPath} (source: ${binarySource})`); + client = new CodeInputClient(finalBinaryPath); + await client.start(); + + // Initialize status bar + if (config.get('showInStatusBar', true)) { + statusBar = new StatusBarManager(client); + statusBar.show(); + context.subscriptions.push(statusBar); + } + + // Register commands + context.subscriptions.push( + vscode.commands.registerCommand('codeinput.showInfo', async () => { + const editor = vscode.window.activeTextEditor; + if (!editor) { + vscode.window.showInformationMessage('No active editor'); + return; + } + + const fileUri = editor.document.uri; + const info = await client?.getFileOwnership(fileUri); + + if (info) { + const owners = info.owners.length > 0 + ? info.owners.map(o => o.identifier).join(', ') + : '(none)'; + const tags = info.tags.length > 0 + ? info.tags.map(t => `#${t}`).join(', ') + : '(none)'; + + const message = [ + `**File:** ${fileUri.fsPath}`, + `**Owners:** ${owners}`, + `**Tags:** ${tags}`, + ].join('\n\n'); + + vscode.window.showInformationMessage(message, { modal: true }); + } else { + vscode.window.showInformationMessage('No CODEOWNERS info available for this file'); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('codeinput.refreshCache', async () => { + await vscode.window.withProgress({ + location: vscode.ProgressLocation.Window, + title: 'Refreshing CODEOWNERS cache...' + }, async () => { + // The LSP server will automatically refresh when CODEOWNERS files change + vscode.window.showInformationMessage('CODEOWNERS cache refreshed'); + }); + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('codeinput.showOwners', (uri: string, owners: any[]) => { + if (owners && owners.length > 0) { + const ownerList = owners.map(o => o.identifier).join(', '); + vscode.window.showInformationMessage(`Owners: ${ownerList}`); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('codeinput.showTags', (uri: string, tags: any[]) => { + if (tags && tags.length > 0) { + const tagList = tags.map(t => `#${t}`).join(', '); + vscode.window.showInformationMessage(`Tags: ${tagList}`); + } + }) + ); + + context.subscriptions.push( + vscode.commands.registerCommand('codeinput.addOwner', async (uri: string) => { + const owner = await vscode.window.showInputBox({ + prompt: 'Enter owner (e.g., @username or @org/team)', + placeHolder: '@username' + }); + + if (owner) { + vscode.window.showInformationMessage(`Would add owner ${owner} to ${uri}`); + // TODO: Implement adding owner to CODEOWNERS file + } + }) + ); + + // Handle configuration changes + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('codeinput.showInStatusBar')) { + const showInStatusBar = config.get('showInStatusBar', true); + + if (showInStatusBar && !statusBar) { + statusBar = new StatusBarManager(client!); + statusBar.show(); + context.subscriptions.push(statusBar); + } else if (!showInStatusBar && statusBar) { + statusBar.dispose(); + statusBar = undefined; + } + } + }) + ); + + // Clean up on deactivate + context.subscriptions.push({ + dispose: () => { + client?.stop(); + } + }); +} + +export function deactivate(): Thenable | undefined { + statusBar?.dispose(); + return client?.stop(); +} diff --git a/extensions/vscode/src/statusbar.ts b/extensions/vscode/src/statusbar.ts new file mode 100644 index 0000000..40808d7 --- /dev/null +++ b/extensions/vscode/src/statusbar.ts @@ -0,0 +1,121 @@ +import * as vscode from 'vscode'; +import { CodeInputClient } from './client'; + +export class StatusBarManager implements vscode.Disposable { + private statusBarItem: vscode.StatusBarItem; + private client: CodeInputClient; + private disposables: vscode.Disposable[] = []; + + constructor(client: CodeInputClient) { + this.client = client; + this.statusBarItem = vscode.window.createStatusBarItem( + vscode.StatusBarAlignment.Right, + 100 + ); + this.statusBarItem.command = 'codeinput.showInfo'; + + // Update when active editor changes + this.disposables.push( + vscode.window.onDidChangeActiveTextEditor(() => { + this.update(); + }) + ); + + // Update when document is saved (cache might have changed) + this.disposables.push( + vscode.workspace.onDidSaveTextDocument(() => { + this.update(); + }) + ); + + // Initial update + this.update(); + } + + public show(): void { + this.statusBarItem.show(); + } + + public hide(): void { + this.statusBarItem.hide(); + } + + private async update(): Promise { + const editor = vscode.window.activeTextEditor; + if (!editor) { + this.statusBarItem.hide(); + return; + } + + const config = vscode.workspace.getConfiguration('codeinput'); + if (!config.get('showInStatusBar', true)) { + this.statusBarItem.hide(); + return; + } + + const fileUri = editor.document.uri; + + // Only show for file:// URIs + if (fileUri.scheme !== 'file') { + this.statusBarItem.hide(); + return; + } + + try { + const info = await this.client.getFileOwnership(fileUri); + + if (info) { + if (info.is_unowned || info.owners.length === 0) { + this.statusBarItem.text = '$(warning) Unowned'; + this.statusBarItem.tooltip = 'This file has no CODEOWNERS assignment\nClick to see details'; + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + } else { + const ownerNames = info.owners.map(o => o.identifier).join(', '); + const ownerInitials = info.owners + .map(o => this.getInitials(o.identifier)) + .join(''); + + this.statusBarItem.text = `$(lock) ${ownerInitials}`; + this.statusBarItem.tooltip = `Owners: ${ownerNames}\nClick to see details`; + this.statusBarItem.backgroundColor = undefined; + } + + this.statusBarItem.show(); + } else { + // No CODEOWNERS info available (file not in cache) + this.statusBarItem.hide(); + } + } catch (error) { + console.error('Error updating status bar:', error); + this.statusBarItem.hide(); + } + } + + private getInitials(identifier: string): string { + // Extract initials from owner identifier + // @org/team -> T, @username -> U, email@domain.com -> E + + if (identifier.startsWith('@')) { + // Handle @org/team format + const parts = identifier.split('/'); + if (parts.length > 1) { + return parts[parts.length - 1].charAt(0).toUpperCase(); + } + // Handle @username format + return identifier.charAt(1).toUpperCase(); + } + + if (identifier.includes('@')) { + // Email format + return identifier.charAt(0).toUpperCase(); + } + + // Fallback + return identifier.charAt(0).toUpperCase(); + } + + public dispose(): void { + this.statusBarItem.dispose(); + this.disposables.forEach(d => d.dispose()); + } +} \ No newline at end of file diff --git a/extensions/vscode/tsconfig.json b/extensions/vscode/tsconfig.json new file mode 100644 index 0000000..49ef38f --- /dev/null +++ b/extensions/vscode/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "lib": ["ES2020"], + "outDir": "out", + "rootDir": "src", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true + }, + "exclude": ["node_modules", ".vscode-test"] +} \ No newline at end of file diff --git a/extensions/vscode/yarn.lock b/extensions/vscode/yarn.lock new file mode 100644 index 0000000..4fd800b --- /dev/null +++ b/extensions/vscode/yarn.lock @@ -0,0 +1,4354 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 6 + cacheKey: 8 + +"@azu/format-text@npm:^1.0.1, @azu/format-text@npm:^1.0.2": + version: 1.0.2 + resolution: "@azu/format-text@npm:1.0.2" + checksum: b28045c48b133b44de0945316f10f3b82015a846c1a988f0de08735f9b7b4c79895f0f57b519d34e6ea8fd46eb829b4945c315ea085e6b3c5694d153f57299e6 + languageName: node + linkType: hard + +"@azu/style-format@npm:^1.0.1": + version: 1.0.1 + resolution: "@azu/style-format@npm:1.0.1" + dependencies: + "@azu/format-text": ^1.0.1 + checksum: 8a4c2339a82117f66ddfdd425f1dae147e3ea94a023270cb220a09377b391862ce8e1a9de98cd57491b1975fb21b8e4d05b7005a42408d1662ad034c49c595ba + languageName: node + linkType: hard + +"@azure/abort-controller@npm:^2.0.0, @azure/abort-controller@npm:^2.1.2": + version: 2.1.2 + resolution: "@azure/abort-controller@npm:2.1.2" + dependencies: + tslib: ^2.6.2 + checksum: 22176c04ea01498311c6bbd336669f6e3faffad1cbb0c9ebc6ee9c1ff2cf958fd17ce73c7354b99d8bda9fcd311325ece7bee248875279174e3fc460e8b1a63d + languageName: node + linkType: hard + +"@azure/core-auth@npm:^1.10.0, @azure/core-auth@npm:^1.9.0": + version: 1.10.1 + resolution: "@azure/core-auth@npm:1.10.1" + dependencies: + "@azure/abort-controller": ^2.1.2 + "@azure/core-util": ^1.13.0 + tslib: ^2.6.2 + checksum: 230c1766d4cb3ac7beac45db65bd5e493e1530f6f1d51dc0fd3537f8144e5c9acfed94700fd28c7aee67bab7502e23a1588adc6aa76f918f08fe40b3b007e2a3 + languageName: node + linkType: hard + +"@azure/core-client@npm:^1.9.2": + version: 1.10.1 + resolution: "@azure/core-client@npm:1.10.1" + 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 + checksum: b1312966ec52dd4c48798bbdffbbd2faf18bc3eea65967a011cc2e4c0988e1135ecb937f91f13927585101941ee3f065f47db609155f2d337edbbad54a8d33b0 + languageName: node + linkType: hard + +"@azure/core-rest-pipeline@npm:^1.17.0, @azure/core-rest-pipeline@npm:^1.22.0": + version: 1.22.2 + resolution: "@azure/core-rest-pipeline@npm:1.22.2" + 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 + checksum: 965738fe8d3ea20d49fefa1a432bb8e5504537e000fc95d741094e94bcd0e3bd0cbabfb08b0befadc751ceb1826a3804aaa2e8e7cd2e59927e5b272c0eb0930b + languageName: node + linkType: hard + +"@azure/core-tracing@npm:^1.0.0, @azure/core-tracing@npm:^1.3.0": + version: 1.3.1 + resolution: "@azure/core-tracing@npm:1.3.1" + dependencies: + tslib: ^2.6.2 + checksum: 549d19af4b9459847947384a38d12566b85f5ffb44ef4e2391d3372865b8e3cc73d7d1738b4652ebca32e498a2e32f4993f0cd2db1a1f938b581f18e686348bb + languageName: node + linkType: hard + +"@azure/core-util@npm:^1.11.0, @azure/core-util@npm:^1.13.0": + version: 1.13.1 + resolution: "@azure/core-util@npm:1.13.1" + dependencies: + "@azure/abort-controller": ^2.1.2 + "@typespec/ts-http-runtime": ^0.3.0 + tslib: ^2.6.2 + checksum: c005e59109757bf0fe4ec099f8454c128fde5947e94dc19a7e709de32908f8c75571ac1e565227ef22a80ad0a0d44b69d0b21ed7b86c922b6dc21d6a21599b12 + languageName: node + linkType: hard + +"@azure/identity@npm:^4.1.0": + version: 4.13.0 + resolution: "@azure/identity@npm:4.13.0" + 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 + checksum: c07e609919bcbb84f6212076420ea4c1907cb09e9b8cbba5e69b99d2aae3cc8d883ceafd3edd3088c60fa887e810de5b23acd658df44501579b635a792ce673b + languageName: node + linkType: hard + +"@azure/logger@npm:^1.0.0, @azure/logger@npm:^1.3.0": + version: 1.3.0 + resolution: "@azure/logger@npm:1.3.0" + dependencies: + "@typespec/ts-http-runtime": ^0.3.0 + tslib: ^2.6.2 + checksum: 2089429ef3eadc6d4d10c5e12f1cf6580587ac0eed5c7107fc621c56927fc162e150e57668e98092d4ba0dc10c6425ee61971dea67e80022fb3906e9c4efc3a6 + languageName: node + linkType: hard + +"@azure/msal-browser@npm:^4.2.0": + version: 4.29.0 + resolution: "@azure/msal-browser@npm:4.29.0" + dependencies: + "@azure/msal-common": 15.15.0 + checksum: 7d49a30cb5dac187bd98b1a6d44d6ffbc7a4c1f0d56b1e64c4cdd663fba770637146a38a287e21c6fcc377974b7437ef4d07e69751ddc9a71be2cd22de87a2e0 + languageName: node + linkType: hard + +"@azure/msal-common@npm:15.15.0": + version: 15.15.0 + resolution: "@azure/msal-common@npm:15.15.0" + checksum: 75c644b3321ae5590825e81728a737643ce3f2576cce073a56febdc815011d03bf7e2f945b1eb66a133cc7ce078c081ffa78cb15faa21786a631737347434c03 + languageName: node + linkType: hard + +"@azure/msal-node@npm:^3.5.0": + version: 3.8.8 + resolution: "@azure/msal-node@npm:3.8.8" + dependencies: + "@azure/msal-common": 15.15.0 + jsonwebtoken: ^9.0.0 + uuid: ^8.3.0 + checksum: 915d7ec16a38a82f9559183485b965a4cc277071a9534ea81e275f83cc964ccb51c17930cb471fb3cac1b9558d2a752d6893b3b712a5a462f665542b0e316dd5 + languageName: node + linkType: hard + +"@babel/code-frame@npm:^7.26.2": + version: 7.29.0 + resolution: "@babel/code-frame@npm:7.29.0" + dependencies: + "@babel/helper-validator-identifier": ^7.28.5 + js-tokens: ^4.0.0 + picocolors: ^1.1.1 + checksum: 39f5b303757e4d63bbff8133e251094cd4f952b46e3fa9febc7368d907583911d6a1eded6090876dc1feeff5cf6e134fb19b706f8d58d26c5402cd50e5e1aeb2 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.28.5": + version: 7.28.5 + resolution: "@babel/helper-validator-identifier@npm:7.28.5" + checksum: 5a251a6848e9712aea0338f659a1a3bd334d26219d5511164544ca8ec20774f098c3a6661e9da65a0d085c745c00bb62c8fada38a62f08fa1f8053bc0aeb57e4 + languageName: node + linkType: hard + +"@esbuild/aix-ppc64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/aix-ppc64@npm:0.27.3" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/android-arm64@npm:0.27.3" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/android-arm@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/android-arm@npm:0.27.3" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@esbuild/android-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/android-x64@npm:0.27.3" + conditions: os=android & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/darwin-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/darwin-arm64@npm:0.27.3" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/darwin-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/darwin-x64@npm:0.27.3" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/freebsd-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/freebsd-arm64@npm:0.27.3" + conditions: os=freebsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/freebsd-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/freebsd-x64@npm:0.27.3" + conditions: os=freebsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/linux-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-arm64@npm:0.27.3" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/linux-arm@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-arm@npm:0.27.3" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@esbuild/linux-ia32@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-ia32@npm:0.27.3" + conditions: os=linux & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/linux-loong64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-loong64@npm:0.27.3" + conditions: os=linux & cpu=loong64 + languageName: node + linkType: hard + +"@esbuild/linux-mips64el@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-mips64el@npm:0.27.3" + conditions: os=linux & cpu=mips64el + languageName: node + linkType: hard + +"@esbuild/linux-ppc64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-ppc64@npm:0.27.3" + conditions: os=linux & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/linux-riscv64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-riscv64@npm:0.27.3" + conditions: os=linux & cpu=riscv64 + languageName: node + linkType: hard + +"@esbuild/linux-s390x@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-s390x@npm:0.27.3" + conditions: os=linux & cpu=s390x + languageName: node + linkType: hard + +"@esbuild/linux-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/linux-x64@npm:0.27.3" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/netbsd-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/netbsd-arm64@npm:0.27.3" + conditions: os=netbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/netbsd-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/netbsd-x64@npm:0.27.3" + conditions: os=netbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openbsd-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/openbsd-arm64@npm:0.27.3" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/openbsd-x64@npm:0.27.3" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/openharmony-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/openharmony-arm64@npm:0.27.3" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/sunos-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/sunos-x64@npm:0.27.3" + conditions: os=sunos & cpu=x64 + languageName: node + linkType: hard + +"@esbuild/win32-arm64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/win32-arm64@npm:0.27.3" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/win32-ia32@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/win32-ia32@npm:0.27.3" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@esbuild/win32-x64@npm:0.27.3": + version: 0.27.3 + resolution: "@esbuild/win32-x64@npm:0.27.3" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": + version: 4.9.1 + resolution: "@eslint-community/eslint-utils@npm:4.9.1" + dependencies: + eslint-visitor-keys: ^3.4.3 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 0a27c2d676c4be6b329ebb5dd8f6c5ef5fae9a019ff575655306d72874bb26f3ab20e0b241a5f086464bb1f2511ca26a29ff6f80c1e2b0b02eca4686b4dfe1b5 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": + version: 4.12.2 + resolution: "@eslint-community/regexpp@npm:4.12.2" + checksum: 1770bc81f676a72f65c7200b5675ff7a349786521f30e66125faaf767fde1ba1c19c3790e16ba8508a62a3933afcfc806a893858b3b5906faf693d862b9e4120 + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/eslintrc@npm:2.1.4" + 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 + checksum: 10957c7592b20ca0089262d8c2a8accbad14b4f6507e35416c32ee6b4dbf9cad67dfb77096bbd405405e9ada2b107f3797fe94362e1c55e0b09d6e90dd149127 + languageName: node + linkType: hard + +"@eslint/js@npm:8.57.1": + version: 8.57.1 + resolution: "@eslint/js@npm:8.57.1" + checksum: 2afb77454c06e8316793d2e8e79a0154854d35e6782a1217da274ca60b5044d2c69d6091155234ed0551a1e408f86f09dd4ece02752c59568fa403e60611e880 + languageName: node + linkType: hard + +"@gar/promise-retry@npm:^1.0.0": + version: 1.0.2 + resolution: "@gar/promise-retry@npm:1.0.2" + dependencies: + retry: ^0.13.1 + checksum: b91326999ce94677cbe91973079eabc689761a93a045f6a2d34d4070e9305b27f6c54e4021688c7080cb14caf89eafa0c0f300af741b94c20d18608bdb66ca46 + languageName: node + linkType: hard + +"@humanwhocodes/config-array@npm:^0.13.0": + version: 0.13.0 + resolution: "@humanwhocodes/config-array@npm:0.13.0" + dependencies: + "@humanwhocodes/object-schema": ^2.0.3 + debug: ^4.3.1 + minimatch: ^3.0.5 + checksum: eae69ff9134025dd2924f0b430eb324981494be26f0fddd267a33c28711c4db643242cf9fddf7dadb9d16c96b54b2d2c073e60a56477df86e0173149313bd5d6 + languageName: node + linkType: hard + +"@humanwhocodes/module-importer@npm:^1.0.1": + version: 1.0.1 + resolution: "@humanwhocodes/module-importer@npm:1.0.1" + checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 + languageName: node + linkType: hard + +"@humanwhocodes/object-schema@npm:^2.0.3": + version: 2.0.3 + resolution: "@humanwhocodes/object-schema@npm:2.0.3" + checksum: d3b78f6c5831888c6ecc899df0d03bcc25d46f3ad26a11d7ea52944dc36a35ef543fad965322174238d677a43d5c694434f6607532cff7077062513ad7022631 + languageName: node + linkType: hard + +"@isaacs/cliui@npm:^9.0.0": + version: 9.0.0 + resolution: "@isaacs/cliui@npm:9.0.0" + checksum: 9b80836cd9fa64099faffc3cb9c0620fd8c1106670f507378c5030daecfe9a29012a67488299e69f3273c6421da2a27ea6a1f1d7600bac01b0cbb5da8eea6277 + languageName: node + linkType: hard + +"@isaacs/fs-minipass@npm:^4.0.0": + version: 4.0.1 + resolution: "@isaacs/fs-minipass@npm:4.0.1" + dependencies: + minipass: ^7.0.4 + checksum: 5d36d289960e886484362d9eb6a51d1ea28baed5f5d0140bbe62b99bac52eaf06cc01c2bc0d3575977962f84f6b2c4387b043ee632216643d4787b0999465bf2 + languageName: node + linkType: hard + +"@nodelib/fs.scandir@npm:2.1.5": + version: 2.1.5 + resolution: "@nodelib/fs.scandir@npm:2.1.5" + dependencies: + "@nodelib/fs.stat": 2.0.5 + run-parallel: ^1.1.9 + checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 + languageName: node + linkType: hard + +"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": + version: 2.0.5 + resolution: "@nodelib/fs.stat@npm:2.0.5" + checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 + languageName: node + linkType: hard + +"@nodelib/fs.walk@npm:^1.2.3, @nodelib/fs.walk@npm:^1.2.8": + version: 1.2.8 + resolution: "@nodelib/fs.walk@npm:1.2.8" + dependencies: + "@nodelib/fs.scandir": 2.1.5 + fastq: ^1.6.0 + checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 + languageName: node + linkType: hard + +"@npmcli/agent@npm:^4.0.0": + version: 4.0.0 + resolution: "@npmcli/agent@npm:4.0.0" + dependencies: + agent-base: ^7.1.0 + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.1 + lru-cache: ^11.2.1 + socks-proxy-agent: ^8.0.3 + checksum: 89ae20b44859ff8d4de56ade319d8ceaa267a0742d6f7345fe98aa5cd8614ced7db85ea4dc5bfbd6614dbb200a10b134e087143582534c939e8a02219e8665c8 + languageName: node + linkType: hard + +"@npmcli/fs@npm:^5.0.0": + version: 5.0.0 + resolution: "@npmcli/fs@npm:5.0.0" + dependencies: + semver: ^7.3.5 + checksum: 897dac32eb37e011800112d406b9ea2ebd96f1dab01bb8fbeb59191b86f6825dffed6a89f3b6c824753d10f8735b76d630927bd7610e9e123b129ef2e5f02cb5 + languageName: node + linkType: hard + +"@secretlint/config-creator@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/config-creator@npm:10.2.2" + dependencies: + "@secretlint/types": ^10.2.2 + checksum: 678350d016bbfdf09c9911158eb739a0b80ef4244c8f791187c9dd120a7162fc50b4aa8d7a042c0c23b6259436ba59e1d9a7c68ece49d10eec0f54e42815858e + languageName: node + linkType: hard + +"@secretlint/config-loader@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/config-loader@npm:10.2.2" + 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 + checksum: b9b5ef985a7e3bd30343a96f317081da4386e7644f1112a7e50f37cff40398f6eeb5fd5b25ae4638b66f570556866c6ef512696b4e8d8e3537e9c7d356983ab6 + languageName: node + linkType: hard + +"@secretlint/core@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/core@npm:10.2.2" + dependencies: + "@secretlint/profiler": ^10.2.2 + "@secretlint/types": ^10.2.2 + debug: ^4.4.1 + structured-source: ^4.0.0 + checksum: 5753e1fb306bdbd4867d660b93f9bbbe2d8d78f6aa4185425fae3827831e75c92dec88cf053f6e129a7b78a25a2943b0b4ce1310afeb53424ba68c0d090fd63a + languageName: node + linkType: hard + +"@secretlint/formatter@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/formatter@npm:10.2.2" + 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 + checksum: 6d2ec48f05ccea0c3ce65bc788b3d066f6bb4e7f385b4798e1157b74416e5de9ece5b7978e444a83249df73d36567943fa90c71eee2947a18df4339a73e570f9 + languageName: node + linkType: hard + +"@secretlint/node@npm:^10.1.2, @secretlint/node@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/node@npm:10.2.2" + dependencies: + "@secretlint/config-loader": ^10.2.2 + "@secretlint/core": ^10.2.2 + "@secretlint/formatter": ^10.2.2 + "@secretlint/profiler": ^10.2.2 + "@secretlint/source-creator": ^10.2.2 + "@secretlint/types": ^10.2.2 + debug: ^4.4.1 + p-map: ^7.0.3 + checksum: 9751d2f6d246dfb215147459965f843d263d811478de94b86ee54fdad38e59addf50a7c815ba2d14e39860a638154eb44957456634b9ebdb13a9481a624b1590 + languageName: node + linkType: hard + +"@secretlint/profiler@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/profiler@npm:10.2.2" + checksum: 7010912291a0df8bac3a2cbf8b290eafe5df5d22d18ab74412f4f074a135b97157bdbf2fa89c2da52a8f154014d69077825c25e43eb1c84bff96947efbcf0f3f + languageName: node + linkType: hard + +"@secretlint/resolver@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/resolver@npm:10.2.2" + checksum: 2853edac30e82833429aed92b7a2754b1f67c142a2612362231d75cc338b5be8412d863a78e6ffe3f3872077251ef2952fdb1cbb44f8140d1ed07ad650a9b006 + languageName: node + linkType: hard + +"@secretlint/secretlint-formatter-sarif@npm:^10.1.2": + version: 10.2.2 + resolution: "@secretlint/secretlint-formatter-sarif@npm:10.2.2" + dependencies: + node-sarif-builder: ^3.2.0 + checksum: 69abbde342eb2ad4a570cc42bde2cee0b6a869e1b55178589fb870d90d2877e5acb5404008edbce239c450c5efcfb02d19c0990daacb92dc3f8533179bf37f30 + languageName: node + linkType: hard + +"@secretlint/secretlint-rule-no-dotenv@npm:^10.1.2": + version: 10.2.2 + resolution: "@secretlint/secretlint-rule-no-dotenv@npm:10.2.2" + dependencies: + "@secretlint/types": ^10.2.2 + checksum: aa5030b770c8c2d6406f636286eb4e325cef50697a3bf43aa04037809e038df7c4dd94bfb05aec3a65ccc290ead0df34583b80b240a56ff0590b894a253ea801 + languageName: node + linkType: hard + +"@secretlint/secretlint-rule-preset-recommend@npm:^10.1.2": + version: 10.2.2 + resolution: "@secretlint/secretlint-rule-preset-recommend@npm:10.2.2" + checksum: b0647f0270b927d68345005b1de1b4febbfc6d3c41863a7c14a674e3ca2ea13d1437a0f7cadb261069c0637c462df369d4a4c809e8959e55942e7a35ad76eac5 + languageName: node + linkType: hard + +"@secretlint/source-creator@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/source-creator@npm:10.2.2" + dependencies: + "@secretlint/types": ^10.2.2 + istextorbinary: ^9.5.0 + checksum: 6699a08ed6cc5964157bd868b67788b03dc6d4406bba230011549aad337c7cb1dc7d3029a0fa0ed86554a4e0cdbf4e9da11c730a9dde1516bf0d42dbe3ec55a6 + languageName: node + linkType: hard + +"@secretlint/types@npm:^10.2.2": + version: 10.2.2 + resolution: "@secretlint/types@npm:10.2.2" + checksum: f7426f45a690f65fdd7d039e5e71fee952139adb8957ce7547c85d7e835d88eb06b0dfe823b6afa40b63732f0a3ef842c341fa3ce2aa3dcf2ef22754327ba395 + languageName: node + linkType: hard + +"@sindresorhus/merge-streams@npm:^2.1.0": + version: 2.3.0 + resolution: "@sindresorhus/merge-streams@npm:2.3.0" + checksum: e989d53dee68d7e49b4ac02ae49178d561c461144cea83f66fa91ff012d981ad0ad2340cbd13f2fdb57989197f5c987ca22a74eb56478626f04e79df84291159 + languageName: node + linkType: hard + +"@textlint/ast-node-types@npm:15.5.2": + version: 15.5.2 + resolution: "@textlint/ast-node-types@npm:15.5.2" + checksum: 18f46c3bbfed5bb48e65280532848516f30f9c243dff5fde1d381f7c30ab1028d4f92fb15d74a6dbe63cba3fa15d34e6f2c2167000e9bb9d08c344dae46e2b6c + languageName: node + linkType: hard + +"@textlint/linter-formatter@npm:^15.2.0": + version: 15.5.2 + resolution: "@textlint/linter-formatter@npm:15.5.2" + dependencies: + "@azu/format-text": ^1.0.2 + "@azu/style-format": ^1.0.1 + "@textlint/module-interop": 15.5.2 + "@textlint/resolver": 15.5.2 + "@textlint/types": 15.5.2 + chalk: ^4.1.2 + debug: ^4.4.3 + js-yaml: ^4.1.1 + lodash: ^4.17.23 + pluralize: ^2.0.0 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + table: ^6.9.0 + text-table: ^0.2.0 + checksum: c5f28afb9097d073dd26d8874f3fcf957bb1ca63aef609131fbfb4e42a020325f45a4adf4bb58b7d3df8dd356a36144777d44dd16a2dafbfcaeeda544db2a550 + languageName: node + linkType: hard + +"@textlint/module-interop@npm:15.5.2, @textlint/module-interop@npm:^15.2.0": + version: 15.5.2 + resolution: "@textlint/module-interop@npm:15.5.2" + checksum: 7457c99e4e36eaf822509ab835447f3d0efe374a838d0febb0da1462675e40d5d45e00ac46b620f1b91b421fb5cfe623b41e58a4f432c06eef560c5393d16978 + languageName: node + linkType: hard + +"@textlint/resolver@npm:15.5.2": + version: 15.5.2 + resolution: "@textlint/resolver@npm:15.5.2" + checksum: 685b5ed24ade634b9ef19f1f97940dadd3dd2d5c42e02b7bc87c666c816c159fca19d6264f4948962dbab85706f25b37da1389fdd4a1c5a516810adbbc752d6f + languageName: node + linkType: hard + +"@textlint/types@npm:15.5.2, @textlint/types@npm:^15.2.0": + version: 15.5.2 + resolution: "@textlint/types@npm:15.5.2" + dependencies: + "@textlint/ast-node-types": 15.5.2 + checksum: 0105f85499bbdaa7ba69621df5957e012dc47777cfcad5615699d0a87585010911860598abdbfa6f28bc29da0c5aaa9c8560112d9b1fbce03927e3134c26a31b + languageName: node + linkType: hard + +"@types/json-schema@npm:^7.0.12": + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 97ed0cb44d4070aecea772b7b2e2ed971e10c81ec87dd4ecc160322ffa55ff330dace1793489540e3e318d90942064bb697cc0f8989391797792d919737b3b98 + languageName: node + linkType: hard + +"@types/node@npm:^20.x": + version: 20.19.35 + resolution: "@types/node@npm:20.19.35" + dependencies: + undici-types: ~6.21.0 + checksum: 465aac31b208bd4248f64b05abd0218509c696c55f62ae000571427e357168650d4c484f4531c37ad3be2a75198ba13f9dda7a0c14c539b09cf52b529d7f0d66 + languageName: node + linkType: hard + +"@types/normalize-package-data@npm:^2.4.3": + version: 2.4.4 + resolution: "@types/normalize-package-data@npm:2.4.4" + checksum: 65dff72b543997b7be8b0265eca7ace0e34b75c3e5fee31de11179d08fa7124a7a5587265d53d0409532ecb7f7fba662c2012807963e1f9b059653ec2c83ee05 + languageName: node + linkType: hard + +"@types/sarif@npm:^2.1.7": + version: 2.1.7 + resolution: "@types/sarif@npm:2.1.7" + checksum: ee5d30f5a2678091502343fba7905e85d25dbb545f920de9fc8a7c6693509b491a043168970a16325730cc0c88de54d2b6b3de0c2caa31645c8ebf558c5553af + languageName: node + linkType: hard + +"@types/semver@npm:^7.5.0": + version: 7.7.1 + resolution: "@types/semver@npm:7.7.1" + checksum: 76d218e414482a398148d5c28f2bfa017108869f3fc18cda379c9d8d062348f8b9653ae2fa8642d3b5b52e211928fe8be34f22da4e1f08245c84e0e51e040673 + languageName: node + linkType: hard + +"@types/vscode@npm:^1.74.0": + version: 1.109.0 + resolution: "@types/vscode@npm:1.109.0" + checksum: 63c1b3c57114e53d662a48005e30ece27964dd8a01d63ae39b48a93813c74c45dee04a3f36a8aab53920d0ba90c5514b5b33b01ea4753a082384949788997579 + languageName: node + linkType: hard + +"@typescript-eslint/eslint-plugin@npm:^6.x": + version: 6.21.0 + resolution: "@typescript-eslint/eslint-plugin@npm:6.21.0" + 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 + peerDependencies: + "@typescript-eslint/parser": ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 5ef2c502255e643e98051e87eb682c2a257e87afd8ec3b9f6274277615e1c2caf3131b352244cfb1987b8b2c415645eeacb9113fa841fc4c9b2ac46e8aed6efd + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:^6.x": + version: 6.21.0 + resolution: "@typescript-eslint/parser@npm:6.21.0" + 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 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 162fe3a867eeeffda7328bce32dae45b52283c68c8cb23258fb9f44971f761991af61f71b8c9fe1aa389e93dfe6386f8509c1273d870736c507d76dd40647b68 + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/scope-manager@npm:6.21.0" + dependencies: + "@typescript-eslint/types": 6.21.0 + "@typescript-eslint/visitor-keys": 6.21.0 + checksum: 71028b757da9694528c4c3294a96cc80bc7d396e383a405eab3bc224cda7341b88e0fc292120b35d3f31f47beac69f7083196c70616434072fbcd3d3e62d3376 + languageName: node + linkType: hard + +"@typescript-eslint/type-utils@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/type-utils@npm:6.21.0" + dependencies: + "@typescript-eslint/typescript-estree": 6.21.0 + "@typescript-eslint/utils": 6.21.0 + debug: ^4.3.4 + ts-api-utils: ^1.0.1 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 77025473f4d80acf1fafcce99c5c283e557686a61861febeba9c9913331f8a41e930bf5cd8b7a54db502a57b6eb8ea6d155cbd4f41349ed00e3d7aeb1f477ddc + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/types@npm:6.21.0" + checksum: 9501b47d7403417af95fc1fb72b2038c5ac46feac0e1598a46bcb43e56a606c387e9dcd8a2a0abe174c91b509f2d2a8078b093786219eb9a01ab2fbf9ee7b684 + languageName: node + linkType: hard + +"@typescript-eslint/typescript-estree@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/typescript-estree@npm:6.21.0" + 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 + peerDependenciesMeta: + typescript: + optional: true + checksum: dec02dc107c4a541e14fb0c96148f3764b92117c3b635db3a577b5a56fc48df7a556fa853fb82b07c0663b4bf2c484c9f245c28ba3e17e5cb0918ea4cab2ea21 + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/utils@npm:6.21.0" + 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 + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + checksum: b129b3a4aebec8468259f4589985cb59ea808afbfdb9c54f02fad11e17d185e2bf72bb332f7c36ec3c09b31f18fc41368678b076323e6e019d06f74ee93f7bf2 + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:6.21.0": + version: 6.21.0 + resolution: "@typescript-eslint/visitor-keys@npm:6.21.0" + dependencies: + "@typescript-eslint/types": 6.21.0 + eslint-visitor-keys: ^3.4.1 + checksum: 67c7e6003d5af042d8703d11538fca9d76899f0119130b373402819ae43f0bc90d18656aa7add25a24427ccf1a0efd0804157ba83b0d4e145f06107d7d1b7433 + languageName: node + linkType: hard + +"@typespec/ts-http-runtime@npm:^0.3.0": + version: 0.3.3 + resolution: "@typespec/ts-http-runtime@npm:0.3.3" + dependencies: + http-proxy-agent: ^7.0.0 + https-proxy-agent: ^7.0.0 + tslib: ^2.6.2 + checksum: 47d54a9f2eed1a70c3de6d715daedab181db54a95319dce728ff0014022db6520d5a6700e92db6b78d966a6fd131f3f1841a258774ae9a09433a961fc9976922 + languageName: node + linkType: hard + +"@ungap/structured-clone@npm:^1.2.0": + version: 1.3.0 + resolution: "@ungap/structured-clone@npm:1.3.0" + checksum: 64ed518f49c2b31f5b50f8570a1e37bde3b62f2460042c50f132430b2d869c4a6586f13aa33a58a4722715b8158c68cae2827389d6752ac54da2893c83e480fc + languageName: node + linkType: hard + +"@vscode/vsce-sign-alpine-arm64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-alpine-arm64@npm:2.0.6" + conditions: os=alpine & cpu=arm64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-alpine-x64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-alpine-x64@npm:2.0.6" + conditions: os=alpine & cpu=x64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-darwin-arm64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-darwin-arm64@npm:2.0.6" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-darwin-x64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-darwin-x64@npm:2.0.6" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-linux-arm64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-linux-arm64@npm:2.0.6" + conditions: os=linux & cpu=arm64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-linux-arm@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-linux-arm@npm:2.0.6" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@vscode/vsce-sign-linux-x64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-linux-x64@npm:2.0.6" + conditions: os=linux & cpu=x64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-win32-arm64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-win32-arm64@npm:2.0.6" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@vscode/vsce-sign-win32-x64@npm:2.0.6": + version: 2.0.6 + resolution: "@vscode/vsce-sign-win32-x64@npm:2.0.6" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@vscode/vsce-sign@npm:^2.0.0": + version: 2.0.9 + resolution: "@vscode/vsce-sign@npm:2.0.9" + dependencies: + "@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 + dependenciesMeta: + "@vscode/vsce-sign-alpine-arm64": + optional: true + "@vscode/vsce-sign-alpine-x64": + optional: true + "@vscode/vsce-sign-darwin-arm64": + optional: true + "@vscode/vsce-sign-darwin-x64": + optional: true + "@vscode/vsce-sign-linux-arm": + optional: true + "@vscode/vsce-sign-linux-arm64": + optional: true + "@vscode/vsce-sign-linux-x64": + optional: true + "@vscode/vsce-sign-win32-arm64": + optional: true + "@vscode/vsce-sign-win32-x64": + optional: true + checksum: bef03713f3bb68fd4a55e1c589c92341c3a4572c6e1e15868269fbeb66cf1a3066d82c58a6280d0161a4adcca38387bdbf71bcda2b9b3e0f54d7ee0b4f92e30b + languageName: node + linkType: hard + +"@vscode/vsce@npm:^3.7.1": + version: 3.7.1 + resolution: "@vscode/vsce@npm:3.7.1" + 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 + keytar: ^7.7.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 + dependenciesMeta: + keytar: + optional: true + bin: + vsce: vsce + checksum: 7dd30db0370461b60de5fd42d06faf7e83f080af4a0893efb31bd0016c5183db590c35993455d5e30ab09b52c842f1ca7af73e5a2fa2a222fea157a713d2d973 + languageName: node + linkType: hard + +"abbrev@npm:^4.0.0": + version: 4.0.0 + resolution: "abbrev@npm:4.0.0" + checksum: d0344b63d28e763f259b4898c41bdc92c08e9d06d0da5617d0bbe4d78244e46daea88c510a2f9472af59b031d9060ec1a999653144e793fd029a59dae2f56dc8 + languageName: node + linkType: hard + +"acorn-jsx@npm:^5.3.2": + version: 5.3.2 + resolution: "acorn-jsx@npm:5.3.2" + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 + languageName: node + linkType: hard + +"acorn@npm:^8.9.0": + version: 8.16.0 + resolution: "acorn@npm:8.16.0" + bin: + acorn: bin/acorn + checksum: bbfa466cd0dbd18b4460a85e9d0fc2f35db999380892403c573261beda91f23836db2aa71fd3ae65e94424ad14ff8e2b7bd37c7a2624278fd89137cd6e448c41 + languageName: node + linkType: hard + +"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": + version: 7.1.4 + resolution: "agent-base@npm:7.1.4" + checksum: 86a7f542af277cfbd77dd61e7df8422f90bac512953709003a1c530171a9d019d072e2400eab2b59f84b49ab9dd237be44315ca663ac73e82b3922d10ea5eafa + languageName: node + linkType: hard + +"ajv@npm:^6.12.4": + version: 6.14.0 + resolution: "ajv@npm:6.14.0" + 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 + checksum: 7bb3ea97bb8af52521589079f427e799b6561acaa94f50e13410cb87588c51df8db1afe1157b3e48f1a829269adaa11116e0c2cafe2b998add1523789809a3c5 + languageName: node + linkType: hard + +"ajv@npm:^8.0.1, ajv@npm:^8.17.1": + version: 8.18.0 + resolution: "ajv@npm:8.18.0" + dependencies: + fast-deep-equal: ^3.1.3 + fast-uri: ^3.0.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + checksum: bcdf6c7b040ca488108e2b4e219b31cf9ed478331007d4dd1ed8acc3946dd6b84295817c0f4724207b8dd8589c9966168b2fd4c7f32109d4b8526cdd3743e936 + languageName: node + linkType: hard + +"ansi-escapes@npm:^7.0.0": + version: 7.3.0 + resolution: "ansi-escapes@npm:7.3.0" + dependencies: + environment: ^1.0.0 + checksum: b5e99117d07abdff097eff474dd0bf64638c70c35cbc3758baf8b77cb8921bf406a082786138e21f7e2e3498137a2d859219103db85435de6551844e6db6cb4e + languageName: node + linkType: hard + +"ansi-regex@npm:^5.0.1": + version: 5.0.1 + resolution: "ansi-regex@npm:5.0.1" + checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + languageName: node + linkType: hard + +"ansi-regex@npm:^6.2.2": + version: 6.2.2 + resolution: "ansi-regex@npm:6.2.2" + checksum: 9b17ce2c6daecc75bcd5966b9ad672c23b184dc3ed9bf3c98a0702f0d2f736c15c10d461913568f2cf527a5e64291c7473358885dd493305c84a1cfed66ba94f + languageName: node + linkType: hard + +"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": + version: 4.3.0 + resolution: "ansi-styles@npm:4.3.0" + dependencies: + color-convert: ^2.0.1 + checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + languageName: node + linkType: hard + +"argparse@npm:^2.0.1": + version: 2.0.1 + resolution: "argparse@npm:2.0.1" + checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced + languageName: node + linkType: hard + +"array-union@npm:^2.1.0": + version: 2.1.0 + resolution: "array-union@npm:2.1.0" + checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d + languageName: node + linkType: hard + +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766 + languageName: node + linkType: hard + +"async-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-function@npm:1.0.0" + checksum: 9102e246d1ed9b37ac36f57f0a6ca55226876553251a31fc80677e71471f463a54c872dc78d5d7f80740c8ba624395cccbe8b60f7b690c4418f487d8e9fd1106 + languageName: node + linkType: hard + +"async-generator-function@npm:^1.0.0": + version: 1.0.0 + resolution: "async-generator-function@npm:1.0.0" + checksum: 74a71a4a2dd7afd06ebb612f6d612c7f4766a351bedffde466023bf6dae629e46b0d2cd38786239e0fbf245de0c7df76035465e16d1213774a0efb22fec0d713 + languageName: node + linkType: hard + +"asynckit@npm:^0.4.0": + version: 0.4.0 + resolution: "asynckit@npm:0.4.0" + checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + languageName: node + linkType: hard + +"azure-devops-node-api@npm:^12.5.0": + version: 12.5.0 + resolution: "azure-devops-node-api@npm:12.5.0" + dependencies: + tunnel: 0.0.6 + typed-rest-client: ^1.8.4 + checksum: 7c2c3ae21eaf1bc3627ba4ea87bdac1085a3594eacf40eb6d7b11292f057988db38f718f4597733c6861d854c28bfe146bcf3964a13adddebe1085270bb63097 + languageName: node + linkType: hard + +"balanced-match@npm:^1.0.0": + version: 1.0.2 + resolution: "balanced-match@npm:1.0.2" + checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + languageName: node + linkType: hard + +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: fb07bb66a0959c2843fc055838047e2a95ccebb837c519614afb067ebfdf2fa967ca8d712c35ced07f2cd26fc6f07964230b094891315ad74f11eba3d53178a0 + languageName: node + linkType: hard + +"base64-js@npm:^1.3.1": + version: 1.5.1 + resolution: "base64-js@npm:1.5.1" + checksum: 669632eb3745404c2f822a18fc3a0122d2f9a7a13f7fb8b5823ee19d1d2ff9ee5b52c53367176ea4ad093c332fd5ab4bd0ebae5a8e27917a4105a4cfc86b1005 + languageName: node + linkType: hard + +"binaryextensions@npm:^6.11.0": + version: 6.11.0 + resolution: "binaryextensions@npm:6.11.0" + dependencies: + editions: ^6.21.0 + checksum: c168d4436da7a31df2ca0af71751f714b6e731758cdf681fa18ca8ace6c3b2a334234acad5964a2e12b0c3c36772a6cc6e83b74456a8f7939081f626c8352dee + languageName: node + linkType: hard + +"bl@npm:^4.0.3": + version: 4.1.0 + resolution: "bl@npm:4.1.0" + dependencies: + buffer: ^5.5.0 + inherits: ^2.0.4 + readable-stream: ^3.4.0 + checksum: 9e8521fa7e83aa9427c6f8ccdcba6e8167ef30cc9a22df26effcc5ab682ef91d2cbc23a239f945d099289e4bbcfae7a192e9c28c84c6202e710a0dfec3722662 + languageName: node + linkType: hard + +"boolbase@npm:^1.0.0": + version: 1.0.0 + resolution: "boolbase@npm:1.0.0" + checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 + languageName: node + linkType: hard + +"boundary@npm:^2.0.0": + version: 2.0.0 + resolution: "boundary@npm:2.0.0" + checksum: 0dda2b4adda5f5ed0b35f22296fe586d96b70719e9d25bff1b565b55e4e3e9bb822a384746f2f0145bf194128486e6a3709e87b90b47195616005d2cf776d132 + languageName: node + linkType: hard + +"brace-expansion@npm:^1.1.7": + version: 1.1.12 + resolution: "brace-expansion@npm:1.1.12" + dependencies: + balanced-match: ^1.0.0 + concat-map: 0.0.1 + checksum: 12cb6d6310629e3048cadb003e1aca4d8c9bb5c67c3c321bafdd7e7a50155de081f78ea3e0ed92ecc75a9015e784f301efc8132383132f4f7904ad1ac529c562 + languageName: node + linkType: hard + +"brace-expansion@npm:^2.0.1": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" + dependencies: + balanced-match: ^1.0.0 + checksum: 01dff195e3646bc4b0d27b63d9bab84d2ebc06121ff5013ad6e5356daa5a9d6b60fa26cf73c74797f2dc3fbec112af13578d51f75228c1112b26c790a87b0488 + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.2": + version: 5.0.4 + resolution: "brace-expansion@npm:5.0.4" + dependencies: + balanced-match: ^4.0.2 + checksum: ded86c0f0b138734110d67437fee52c1f97bc19175644788b1d71afec2d87d405cf05424ce428f88ae3abe8e09e13ee55f2675534b38076ef70e1e583ed75686 + languageName: node + linkType: hard + +"braces@npm:^3.0.3": + version: 3.0.3 + resolution: "braces@npm:3.0.3" + dependencies: + fill-range: ^7.1.1 + checksum: b95aa0b3bd909f6cd1720ffcf031aeaf46154dd88b4da01f9a1d3f7ea866a79eba76a6d01cbc3c422b2ee5cdc39a4f02491058d5df0d7bf6e6a162a832df1f69 + languageName: node + linkType: hard + +"buffer-crc32@npm:~0.2.3": + version: 0.2.13 + resolution: "buffer-crc32@npm:0.2.13" + checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c + languageName: node + linkType: hard + +"buffer-equal-constant-time@npm:^1.0.1": + version: 1.0.1 + resolution: "buffer-equal-constant-time@npm:1.0.1" + checksum: 80bb945f5d782a56f374b292770901065bad21420e34936ecbe949e57724b4a13874f735850dd1cc61f078773c4fb5493a41391e7bda40d1fa388d6bd80daaab + languageName: node + linkType: hard + +"buffer@npm:^5.5.0": + version: 5.7.1 + resolution: "buffer@npm:5.7.1" + dependencies: + base64-js: ^1.3.1 + ieee754: ^1.1.13 + checksum: e2cf8429e1c4c7b8cbd30834ac09bd61da46ce35f5c22a78e6c2f04497d6d25541b16881e30a019c6fd3154150650ccee27a308eff3e26229d788bbdeb08ab84 + languageName: node + linkType: hard + +"bundle-name@npm:^4.1.0": + version: 4.1.0 + resolution: "bundle-name@npm:4.1.0" + dependencies: + run-applescript: ^7.0.0 + checksum: 1d966c8d2dbf4d9d394e53b724ac756c2414c45c01340b37743621f59cc565a435024b394ddcb62b9b335d1c9a31f4640eb648c3fec7f97ee74dc0694c9beb6c + languageName: node + linkType: hard + +"cacache@npm:^20.0.1": + version: 20.0.3 + resolution: "cacache@npm:20.0.3" + dependencies: + "@npmcli/fs": ^5.0.0 + fs-minipass: ^3.0.0 + glob: ^13.0.0 + lru-cache: ^11.1.0 + minipass: ^7.0.3 + minipass-collect: ^2.0.1 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + p-map: ^7.0.2 + ssri: ^13.0.0 + unique-filename: ^5.0.0 + checksum: 595e6b91d72972d596e1e9ccab8ddbf08b773f27240220b1b5b1b7b3f52173cfbcf095212e5d7acd86c3bd453c28e69b116469889c511615ef3589523d542639 + languageName: node + linkType: hard + +"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": + version: 1.0.2 + resolution: "call-bind-apply-helpers@npm:1.0.2" + dependencies: + es-errors: ^1.3.0 + function-bind: ^1.1.2 + checksum: b2863d74fcf2a6948221f65d95b91b4b2d90cfe8927650b506141e669f7d5de65cea191bf788838bc40d13846b7886c5bc5c84ab96c3adbcf88ad69a72fcdc6b + languageName: node + linkType: hard + +"call-bound@npm:^1.0.2": + version: 1.0.4 + resolution: "call-bound@npm:1.0.4" + dependencies: + call-bind-apply-helpers: ^1.0.2 + get-intrinsic: ^1.3.0 + checksum: 2f6399488d1c272f56306ca60ff696575e2b7f31daf23bc11574798c84d9f2759dceb0cb1f471a85b77f28962a7ac6411f51d283ea2e45319009a19b6ccab3b2 + languageName: node + linkType: hard + +"callsites@npm:^3.0.0": + version: 3.1.0 + resolution: "callsites@npm:3.1.0" + checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 + languageName: node + linkType: hard + +"chalk@npm:^4.0.0, chalk@npm:^4.1.2": + version: 4.1.2 + resolution: "chalk@npm:4.1.2" + dependencies: + ansi-styles: ^4.1.0 + supports-color: ^7.1.0 + checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + languageName: node + linkType: hard + +"chalk@npm:^5.4.1": + version: 5.6.2 + resolution: "chalk@npm:5.6.2" + checksum: 4ee2d47a626d79ca27cb5299ecdcce840ef5755e287412536522344db0fc51ca0f6d6433202332c29e2288c6a90a2b31f3bd626bc8c14743b6b6ee28abd3b796 + languageName: node + linkType: hard + +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + 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 + checksum: 843d6d479922f28a6c5342c935aff1347491156814de63c585a6eb73baf7bb4185c1b4383a1195dca0f12e3946d737c7763bcef0b9544c515d905c5c44c5308b + languageName: node + linkType: hard + +"cheerio@npm:^1.0.0-rc.9": + version: 1.2.0 + resolution: "cheerio@npm:1.2.0" + dependencies: + cheerio-select: ^2.1.0 + dom-serializer: ^2.0.0 + domhandler: ^5.0.3 + domutils: ^3.2.2 + encoding-sniffer: ^0.2.1 + htmlparser2: ^10.1.0 + parse5: ^7.3.0 + parse5-htmlparser2-tree-adapter: ^7.1.0 + parse5-parser-stream: ^7.1.2 + undici: ^7.19.0 + whatwg-mimetype: ^4.0.0 + checksum: d0e83ebd6c6533d3604e01ab5df22c1090a7adefc3f3f1d97bb6cdd25760f5f7f842f41cede377e159b093f4ad31e8dc1669f9e3b998b69eeb2aced702efd0ba + languageName: node + linkType: hard + +"chownr@npm:^1.1.1": + version: 1.1.4 + resolution: "chownr@npm:1.1.4" + checksum: 115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d + languageName: node + linkType: hard + +"chownr@npm:^3.0.0": + version: 3.0.0 + resolution: "chownr@npm:3.0.0" + checksum: fd73a4bab48b79e66903fe1cafbdc208956f41ea4f856df883d0c7277b7ab29fd33ee65f93b2ec9192fc0169238f2f8307b7735d27c155821d886b84aa97aa8d + languageName: node + linkType: hard + +"cockatiel@npm:^3.1.2": + version: 3.2.1 + resolution: "cockatiel@npm:3.2.1" + checksum: d31317616f996fe6328781c28302d0b1a38a69ef3938c0eea791fd8a1b8e1379487b3024d6a2f7a811d4fd2cb4cb5e4d672f5dface945e7f4ac9645819e1445b + languageName: node + linkType: hard + +"codeinput@workspace:.": + version: 0.0.0-use.local + resolution: "codeinput@workspace:." + dependencies: + "@types/node": ^20.x + "@types/vscode": ^1.74.0 + "@typescript-eslint/eslint-plugin": ^6.x + "@typescript-eslint/parser": ^6.x + "@vscode/vsce": ^3.7.1 + esbuild: ^0.27.3 + eslint: ^8.x + typescript: ^5.x + vscode-languageclient: ^9.0.1 + languageName: unknown + linkType: soft + +"color-convert@npm:^2.0.1": + version: 2.0.1 + resolution: "color-convert@npm:2.0.1" + dependencies: + color-name: ~1.1.4 + checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + languageName: node + linkType: hard + +"color-name@npm:~1.1.4": + version: 1.1.4 + resolution: "color-name@npm:1.1.4" + checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 + languageName: node + linkType: hard + +"combined-stream@npm:^1.0.8": + version: 1.0.8 + resolution: "combined-stream@npm:1.0.8" + dependencies: + delayed-stream: ~1.0.0 + checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + languageName: node + linkType: hard + +"commander@npm:^12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 68e9818b00fc1ed9cdab9eb16905551c2b768a317ae69a5e3c43924c2b20ac9bb65b27e1cab36aeda7b6496376d4da908996ba2c0b5d79463e0fb1e77935d514 + languageName: node + linkType: hard + +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + languageName: node + linkType: hard + +"cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.6": + version: 7.0.6 + resolution: "cross-spawn@npm:7.0.6" + dependencies: + path-key: ^3.1.0 + shebang-command: ^2.0.0 + which: ^2.0.1 + checksum: 8d306efacaf6f3f60e0224c287664093fa9185680b2d195852ba9a863f85d02dcc737094c6e512175f8ee0161f9b87c73c6826034c2422e39de7d6569cf4503b + languageName: node + linkType: hard + +"css-select@npm:^5.1.0": + version: 5.2.2 + resolution: "css-select@npm:5.2.2" + dependencies: + boolbase: ^1.0.0 + css-what: ^6.1.0 + domhandler: ^5.0.2 + domutils: ^3.0.1 + nth-check: ^2.0.1 + checksum: 0ab672620c6bdfe4129dfecf202f6b90f92018b24a1a93cfbb295c24026d0163130ba4b98d7443f87246a2c1d67413798a7a5920cd102b0cfecfbc89896515aa + languageName: node + linkType: hard + +"css-what@npm:^6.1.0": + version: 6.2.2 + resolution: "css-what@npm:6.2.2" + checksum: 4d1f07b348a638e1f8b4c72804a1e93881f35e0f541256aec5ac0497c5855df7db7ab02da030de950d4813044f6d029a14ca657e0f92c3987e4b604246235b2b + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.1, debug@npm:^4.4.3": + version: 4.4.3 + resolution: "debug@npm:4.4.3" + dependencies: + ms: ^2.1.3 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 4805abd570e601acdca85b6aa3757186084a45cff9b2fa6eee1f3b173caa776b45f478b2a71a572d616d2010cea9211d0ac4a02a610e4c18ac4324bde3760834 + languageName: node + linkType: hard + +"decompress-response@npm:^6.0.0": + version: 6.0.0 + resolution: "decompress-response@npm:6.0.0" + dependencies: + mimic-response: ^3.1.0 + checksum: d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 + languageName: node + linkType: hard + +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 + languageName: node + linkType: hard + +"deep-is@npm:^0.1.3": + version: 0.1.4 + resolution: "deep-is@npm:0.1.4" + checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 + languageName: node + linkType: hard + +"default-browser-id@npm:^5.0.0": + version: 5.0.1 + resolution: "default-browser-id@npm:5.0.1" + checksum: 52c637637bcd76bfe974462a2f1dd75cb04784c2852935575760f82e1fd338e5e80d3c45a9b01fdbb1e450553a830bb163b004d2eca223c5573989f82232a072 + languageName: node + linkType: hard + +"default-browser@npm:^5.2.1": + version: 5.5.0 + resolution: "default-browser@npm:5.5.0" + dependencies: + bundle-name: ^4.1.0 + default-browser-id: ^5.0.0 + checksum: c5c5d84a4abd82850e98f06798a55dee87fc1064538bea00cc14c0fb2dccccbff5e9e07eeea80385fa653202d5d92509838b4239d610ddfa1c76a04a1f65e767 + languageName: node + linkType: hard + +"define-lazy-prop@npm:^3.0.0": + version: 3.0.0 + resolution: "define-lazy-prop@npm:3.0.0" + checksum: 54884f94caac0791bf6395a3ec530ce901cf71c47b0196b8754f3fd17edb6c0e80149c1214429d851873bb0d689dbe08dcedbb2306dc45c8534a5934723851b6 + languageName: node + linkType: hard + +"delayed-stream@npm:~1.0.0": + version: 1.0.0 + resolution: "delayed-stream@npm:1.0.0" + checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 + languageName: node + linkType: hard + +"detect-libc@npm:^2.0.0": + version: 2.1.2 + resolution: "detect-libc@npm:2.1.2" + checksum: 471740d52365084c4b2ae359e507b863f2b1d79b08a92835ebdf701918e08fc9cfba175b3db28483ca33b155e1311a91d69dc42c6d192b476f41a9e1f094ce6a + languageName: node + linkType: hard + +"dir-glob@npm:^3.0.1": + version: 3.0.1 + resolution: "dir-glob@npm:3.0.1" + dependencies: + path-type: ^4.0.0 + checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 + languageName: node + linkType: hard + +"doctrine@npm:^3.0.0": + version: 3.0.0 + resolution: "doctrine@npm:3.0.0" + dependencies: + esutils: ^2.0.2 + checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce + languageName: node + linkType: hard + +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + languageName: node + linkType: hard + +"domutils@npm:^3.0.1, domutils@npm:^3.2.2": + version: 3.2.2 + resolution: "domutils@npm:3.2.2" + dependencies: + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + checksum: ae941d56f03d857077d55dde9297e960a625229fc2b933187cc4123084d7c2d2517f58283a7336567127029f1e008449bac8ac8506d44341e29e3bb18e02f906 + languageName: node + linkType: hard + +"dunder-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "dunder-proto@npm:1.0.1" + dependencies: + call-bind-apply-helpers: ^1.0.1 + es-errors: ^1.3.0 + gopd: ^1.2.0 + checksum: 149207e36f07bd4941921b0ca929e3a28f1da7bd6b6ff8ff7f4e2f2e460675af4576eeba359c635723dc189b64cdd4787e0255897d5b135ccc5d15cb8685fc90 + languageName: node + linkType: hard + +"ecdsa-sig-formatter@npm:1.0.11": + version: 1.0.11 + resolution: "ecdsa-sig-formatter@npm:1.0.11" + dependencies: + safe-buffer: ^5.0.1 + checksum: 207f9ab1c2669b8e65540bce29506134613dd5f122cccf1e6a560f4d63f2732d427d938f8481df175505aad94583bcb32c688737bb39a6df0625f903d6d93c03 + languageName: node + linkType: hard + +"editions@npm:^6.21.0": + version: 6.22.0 + resolution: "editions@npm:6.22.0" + dependencies: + version-range: ^4.15.0 + checksum: 994284f5bedaa34831c6a2f321488ecd0de70bd792c1f9376874a53c18d9b78001dec448da1f2f3c175a2e135caf538a7fc86bb0b139acc96088d4e47c5b9d11 + languageName: node + linkType: hard + +"emoji-regex@npm:^8.0.0": + version: 8.0.0 + resolution: "emoji-regex@npm:8.0.0" + checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + languageName: node + linkType: hard + +"encoding-sniffer@npm:^0.2.1": + version: 0.2.1 + resolution: "encoding-sniffer@npm:0.2.1" + dependencies: + iconv-lite: ^0.6.3 + whatwg-encoding: ^3.1.1 + checksum: d96cc88bbab6a88f57805491fa948b7b1c30f8488939fe4397c58c79ce766a1027f4c10de1893a9b5e489c4ad8ed927f6a8a87f1d114b6f3d5cb3bbbc73601d7 + languageName: node + linkType: hard + +"end-of-stream@npm:^1.1.0, end-of-stream@npm:^1.4.1": + version: 1.4.5 + resolution: "end-of-stream@npm:1.4.5" + dependencies: + once: ^1.4.0 + checksum: 1e0cfa6e7f49887544e03314f9dfc56a8cb6dde910cbb445983ecc2ff426fc05946df9d75d8a21a3a64f2cecfe1bf88f773952029f46756b2ed64a24e95b1fb8 + languageName: node + linkType: hard + +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + languageName: node + linkType: hard + +"entities@npm:^6.0.0": + version: 6.0.1 + resolution: "entities@npm:6.0.1" + checksum: 937b952e81aca641660a6a07f70001c6821973dea3ae7f6a5013eadce94620f3ed2e9c745832d503c8811ce6e97704d8a0396159580c0e567d815234de7fdecf + languageName: node + linkType: hard + +"entities@npm:^7.0.1": + version: 7.0.1 + resolution: "entities@npm:7.0.1" + checksum: 5ee49e52e64eafc63251585f74eae50f259ea2169dbbf5380843dcd97c79bfe430a58e7f34012ab67a8e258f6ef9f92d721d149ffc88c89039e155f1bcf48a53 + languageName: node + linkType: hard + +"env-paths@npm:^2.2.0": + version: 2.2.1 + resolution: "env-paths@npm:2.2.1" + checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + languageName: node + linkType: hard + +"environment@npm:^1.0.0": + version: 1.1.0 + resolution: "environment@npm:1.1.0" + checksum: dd3c1b9825e7f71f1e72b03c2344799ac73f2e9ef81b78ea8b373e55db021786c6b9f3858ea43a436a2c4611052670ec0afe85bc029c384cc71165feee2f4ba6 + languageName: node + linkType: hard + +"es-define-property@npm:^1.0.1": + version: 1.0.1 + resolution: "es-define-property@npm:1.0.1" + checksum: 0512f4e5d564021c9e3a644437b0155af2679d10d80f21adaf868e64d30efdfbd321631956f20f42d655fedb2e3a027da479fad3fa6048f768eb453a80a5f80a + languageName: node + linkType: hard + +"es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: ec1414527a0ccacd7f15f4a3bc66e215f04f595ba23ca75cdae0927af099b5ec865f9f4d33e9d7e86f512f252876ac77d4281a7871531a50678132429b1271b5 + languageName: node + linkType: hard + +"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": + version: 1.1.1 + resolution: "es-object-atoms@npm:1.1.1" + dependencies: + es-errors: ^1.3.0 + checksum: 214d3767287b12f36d3d7267ef342bbbe1e89f899cfd67040309fc65032372a8e60201410a99a1645f2f90c1912c8c49c8668066f6bdd954bcd614dda2e3da97 + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.1.0": + version: 2.1.0 + resolution: "es-set-tostringtag@npm:2.1.0" + dependencies: + es-errors: ^1.3.0 + get-intrinsic: ^1.2.6 + has-tostringtag: ^1.0.2 + hasown: ^2.0.2 + checksum: 789f35de4be3dc8d11fdcb91bc26af4ae3e6d602caa93299a8c45cf05d36cc5081454ae2a6d3afa09cceca214b76c046e4f8151e092e6fc7feeb5efb9e794fc6 + languageName: node + linkType: hard + +"esbuild@npm:^0.27.3": + version: 0.27.3 + resolution: "esbuild@npm:0.27.3" + dependencies: + "@esbuild/aix-ppc64": 0.27.3 + "@esbuild/android-arm": 0.27.3 + "@esbuild/android-arm64": 0.27.3 + "@esbuild/android-x64": 0.27.3 + "@esbuild/darwin-arm64": 0.27.3 + "@esbuild/darwin-x64": 0.27.3 + "@esbuild/freebsd-arm64": 0.27.3 + "@esbuild/freebsd-x64": 0.27.3 + "@esbuild/linux-arm": 0.27.3 + "@esbuild/linux-arm64": 0.27.3 + "@esbuild/linux-ia32": 0.27.3 + "@esbuild/linux-loong64": 0.27.3 + "@esbuild/linux-mips64el": 0.27.3 + "@esbuild/linux-ppc64": 0.27.3 + "@esbuild/linux-riscv64": 0.27.3 + "@esbuild/linux-s390x": 0.27.3 + "@esbuild/linux-x64": 0.27.3 + "@esbuild/netbsd-arm64": 0.27.3 + "@esbuild/netbsd-x64": 0.27.3 + "@esbuild/openbsd-arm64": 0.27.3 + "@esbuild/openbsd-x64": 0.27.3 + "@esbuild/openharmony-arm64": 0.27.3 + "@esbuild/sunos-x64": 0.27.3 + "@esbuild/win32-arm64": 0.27.3 + "@esbuild/win32-ia32": 0.27.3 + "@esbuild/win32-x64": 0.27.3 + dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true + "@esbuild/android-arm": + optional: true + "@esbuild/android-arm64": + optional: true + "@esbuild/android-x64": + optional: true + "@esbuild/darwin-arm64": + optional: true + "@esbuild/darwin-x64": + optional: true + "@esbuild/freebsd-arm64": + optional: true + "@esbuild/freebsd-x64": + optional: true + "@esbuild/linux-arm": + optional: true + "@esbuild/linux-arm64": + optional: true + "@esbuild/linux-ia32": + optional: true + "@esbuild/linux-loong64": + optional: true + "@esbuild/linux-mips64el": + optional: true + "@esbuild/linux-ppc64": + optional: true + "@esbuild/linux-riscv64": + optional: true + "@esbuild/linux-s390x": + optional: true + "@esbuild/linux-x64": + optional: true + "@esbuild/netbsd-arm64": + optional: true + "@esbuild/netbsd-x64": + optional: true + "@esbuild/openbsd-arm64": + optional: true + "@esbuild/openbsd-x64": + optional: true + "@esbuild/openharmony-arm64": + optional: true + "@esbuild/sunos-x64": + optional: true + "@esbuild/win32-arm64": + optional: true + "@esbuild/win32-ia32": + optional: true + "@esbuild/win32-x64": + optional: true + bin: + esbuild: bin/esbuild + checksum: 3a45334b00ca235ad96843738c4698970aacde92058aee28ab1fa57ad823c29667070af90b6071cc876e492bebdeed79f593a273c39b419097afd2a772296085 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^4.0.0": + version: 4.0.0 + resolution: "escape-string-regexp@npm:4.0.0" + checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 + languageName: node + linkType: hard + +"eslint-scope@npm:^7.2.2": + version: 7.2.2 + resolution: "eslint-scope@npm:7.2.2" + dependencies: + esrecurse: ^4.3.0 + estraverse: ^5.2.0 + checksum: ec97dbf5fb04b94e8f4c5a91a7f0a6dd3c55e46bfc7bbcd0e3138c3a76977570e02ed89a1810c778dcd72072ff0e9621ba1379b4babe53921d71e2e4486fda3e + languageName: node + linkType: hard + +"eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 36e9ef87fca698b6fd7ca5ca35d7b2b6eeaaf106572e2f7fd31c12d3bfdaccdb587bba6d3621067e5aece31c8c3a348b93922ab8f7b2cbc6aaab5e1d89040c60 + languageName: node + linkType: hard + +"eslint@npm:^8.x": + version: 8.57.1 + resolution: "eslint@npm:8.57.1" + 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 + checksum: e2489bb7f86dd2011967759a09164e65744ef7688c310bc990612fc26953f34cc391872807486b15c06833bdff737726a23e9b4cdba5de144c311377dc41d91b + languageName: node + linkType: hard + +"espree@npm:^9.6.0, espree@npm:^9.6.1": + version: 9.6.1 + resolution: "espree@npm:9.6.1" + dependencies: + acorn: ^8.9.0 + acorn-jsx: ^5.3.2 + eslint-visitor-keys: ^3.4.1 + checksum: eb8c149c7a2a77b3f33a5af80c10875c3abd65450f60b8af6db1bfcfa8f101e21c1e56a561c6dc13b848e18148d43469e7cd208506238554fb5395a9ea5a1ab9 + languageName: node + linkType: hard + +"esquery@npm:^1.4.2": + version: 1.7.0 + resolution: "esquery@npm:1.7.0" + dependencies: + estraverse: ^5.1.0 + checksum: 3239792b68cf39fe18966d0ca01549bb15556734f0144308fd213739b0f153671ae916013fce0bca032044a4dbcda98b43c1c667f20c20a54dec3597ac0d7c27 + languageName: node + linkType: hard + +"esrecurse@npm:^4.3.0": + version: 4.3.0 + resolution: "esrecurse@npm:4.3.0" + dependencies: + estraverse: ^5.2.0 + checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 + languageName: node + linkType: hard + +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": + version: 5.3.0 + resolution: "estraverse@npm:5.3.0" + checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 + languageName: node + linkType: hard + +"expand-template@npm:^2.0.3": + version: 2.0.3 + resolution: "expand-template@npm:2.0.3" + checksum: 588c19847216421ed92befb521767b7018dc88f88b0576df98cb242f20961425e96a92cbece525ef28cc5becceae5d544ae0f5b9b5e2aa05acb13716ca5b3099 + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.3 + resolution: "exponential-backoff@npm:3.1.3" + checksum: 471fdb70fd3d2c08a74a026973bdd4105b7832911f610ca67bbb74e39279411c1eed2f2a110c9d41c2edd89459ba58fdaba1c174beed73e7a42d773882dcff82 + languageName: node + linkType: hard + +"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": + version: 3.1.3 + resolution: "fast-deep-equal@npm:3.1.3" + checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d + languageName: node + linkType: hard + +"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.3": + version: 3.3.3 + resolution: "fast-glob@npm:3.3.3" + 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 + checksum: 0704d7b85c0305fd2cef37777337dfa26230fdd072dce9fb5c82a4b03156f3ffb8ed3e636033e65d45d2a5805a4e475825369a27404c0307f2db0c8eb3366fbd + languageName: node + linkType: hard + +"fast-json-stable-stringify@npm:^2.0.0": + version: 2.1.0 + resolution: "fast-json-stable-stringify@npm:2.1.0" + checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb + languageName: node + linkType: hard + +"fast-levenshtein@npm:^2.0.6": + version: 2.0.6 + resolution: "fast-levenshtein@npm:2.0.6" + checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c + languageName: node + linkType: hard + +"fast-uri@npm:^3.0.1": + version: 3.1.0 + resolution: "fast-uri@npm:3.1.0" + checksum: daab0efd3548cc53d0db38ecc764d125773f8bd70c34552ff21abdc6530f26fa4cb1771f944222ca5e61a0a1a85d01a104848ff88c61736de445d97bd616ea7e + languageName: node + linkType: hard + +"fastq@npm:^1.6.0": + version: 1.20.1 + resolution: "fastq@npm:1.20.1" + dependencies: + reusify: ^1.0.4 + checksum: 49128edbf05e682bee3c1db3d2dfc7da195469065ef014d8368c555d829932313ae2ddf584bb03146409b0d5d9fdb387c471075483a7319b52f777ad91128ed8 + languageName: node + linkType: hard + +"fd-slicer@npm:~1.1.0": + version: 1.1.0 + resolution: "fd-slicer@npm:1.1.0" + dependencies: + pend: ~1.2.0 + checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 + languageName: node + linkType: hard + +"fdir@npm:^6.5.0": + version: 6.5.0 + resolution: "fdir@npm:6.5.0" + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + checksum: bd537daa9d3cd53887eed35efa0eab2dbb1ca408790e10e024120e7a36c6e9ae2b33710cb8381e35def01bc9c1d7eaba746f886338413e68ff6ebaee07b9a6e8 + languageName: node + linkType: hard + +"file-entry-cache@npm:^6.0.1": + version: 6.0.1 + resolution: "file-entry-cache@npm:6.0.1" + dependencies: + flat-cache: ^3.0.4 + checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 + languageName: node + linkType: hard + +"fill-range@npm:^7.1.1": + version: 7.1.1 + resolution: "fill-range@npm:7.1.1" + dependencies: + to-regex-range: ^5.0.1 + checksum: b4abfbca3839a3d55e4ae5ec62e131e2e356bf4859ce8480c64c4876100f4df292a63e5bb1618e1d7460282ca2b305653064f01654474aa35c68000980f17798 + languageName: node + linkType: hard + +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: ^6.0.0 + path-exists: ^4.0.0 + checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 + languageName: node + linkType: hard + +"flat-cache@npm:^3.0.4": + version: 3.2.0 + resolution: "flat-cache@npm:3.2.0" + dependencies: + flatted: ^3.2.9 + keyv: ^4.5.3 + rimraf: ^3.0.2 + checksum: e7e0f59801e288b54bee5cb9681e9ee21ee28ef309f886b312c9d08415b79fc0f24ac842f84356ce80f47d6a53de62197ce0e6e148dc42d5db005992e2a756ec + languageName: node + linkType: hard + +"flatted@npm:^3.2.9": + version: 3.3.4 + resolution: "flatted@npm:3.3.4" + checksum: 67f1da2949782ead8cb6846b08b941c9569a8232bf43f1cd754736473400377b24b371939a251095c6df59f99a9dd667552b2008ae252d1b0a821ef5ecb5498d + languageName: node + linkType: hard + +"foreground-child@npm:^3.3.1": + version: 3.3.1 + resolution: "foreground-child@npm:3.3.1" + dependencies: + cross-spawn: ^7.0.6 + signal-exit: ^4.0.1 + checksum: b2c1a6fc0bf0233d645d9fefdfa999abf37db1b33e5dab172b3cbfb0662b88bfbd2c9e7ab853533d199050ec6b65c03fcf078fc212d26e4990220e98c6930eef + languageName: node + linkType: hard + +"form-data@npm:^4.0.0": + version: 4.0.5 + resolution: "form-data@npm:4.0.5" + dependencies: + asynckit: ^0.4.0 + combined-stream: ^1.0.8 + es-set-tostringtag: ^2.1.0 + hasown: ^2.0.2 + mime-types: ^2.1.12 + checksum: af8328413c16d0cded5fccc975a44d227c5120fd46a9e81de8acf619d43ed838414cc6d7792195b30b248f76a65246949a129a4dadd148721948f90cd6d4fb69 + languageName: node + linkType: hard + +"fs-constants@npm:^1.0.0": + version: 1.0.0 + resolution: "fs-constants@npm:1.0.0" + checksum: 18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d + languageName: node + linkType: hard + +"fs-extra@npm:^11.1.1": + version: 11.3.3 + resolution: "fs-extra@npm:11.3.3" + dependencies: + graceful-fs: ^4.2.0 + jsonfile: ^6.0.1 + universalify: ^2.0.0 + checksum: fb2acabbd1e04bcaca90eadfe98e6ffba1523b8009afbb9f4c0aae5efbca0bd0bf6c9a6831df5af5aaacb98d3e499898be848fb0c03d31ae7b9d1b053e81c151 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: ^7.0.3 + checksum: 8722a41109130851d979222d3ec88aabaceeaaf8f57b2a8f744ef8bd2d1ce95453b04a61daa0078822bc5cd21e008814f06fe6586f56fef511e71b8d2394d802 + languageName: node + linkType: hard + +"fs.realpath@npm:^1.0.0": + version: 1.0.0 + resolution: "fs.realpath@npm:1.0.0" + checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + languageName: node + linkType: hard + +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 2b0ff4ce708d99715ad14a6d1f894e2a83242e4a52ccfcefaee5e40050562e5f6dafc1adbb4ce2d4ab47279a45dc736ab91ea5042d843c3c092820dfe032efb1 + languageName: node + linkType: hard + +"generator-function@npm:^2.0.0": + version: 2.0.1 + resolution: "generator-function@npm:2.0.1" + checksum: 3bf87f7b0230de5d74529677e6c3ceb3b7b5d9618b5a22d92b45ce3876defbaf5a77791b25a61b0fa7d13f95675b5ff67a7769f3b9af33f096e34653519e873d + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0": + version: 1.3.1 + resolution: "get-intrinsic@npm:1.3.1" + dependencies: + async-function: ^1.0.0 + async-generator-function: ^1.0.0 + 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 + generator-function: ^2.0.0 + get-proto: ^1.0.1 + gopd: ^1.2.0 + has-symbols: ^1.1.0 + hasown: ^2.0.2 + math-intrinsics: ^1.1.0 + checksum: c02b3b6a445f9cd53e14896303794ac60f9751f58a69099127248abdb0251957174c6524245fc68579dc8e6a35161d3d94c93e665f808274716f4248b269436a + languageName: node + linkType: hard + +"get-proto@npm:^1.0.1": + version: 1.0.1 + resolution: "get-proto@npm:1.0.1" + dependencies: + dunder-proto: ^1.0.1 + es-object-atoms: ^1.0.0 + checksum: 4fc96afdb58ced9a67558698b91433e6b037aaa6f1493af77498d7c85b141382cf223c0e5946f334fb328ee85dfe6edd06d218eaf09556f4bc4ec6005d7f5f7b + languageName: node + linkType: hard + +"github-from-package@npm:0.0.0": + version: 0.0.0 + resolution: "github-from-package@npm:0.0.0" + checksum: 14e448192a35c1e42efee94c9d01a10f42fe790375891a24b25261246ce9336ab9df5d274585aedd4568f7922246c2a78b8a8cd2571bfe99c693a9718e7dd0e3 + languageName: node + linkType: hard + +"glob-parent@npm:^5.1.2": + version: 5.1.2 + resolution: "glob-parent@npm:5.1.2" + dependencies: + is-glob: ^4.0.1 + checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e + languageName: node + linkType: hard + +"glob-parent@npm:^6.0.2": + version: 6.0.2 + resolution: "glob-parent@npm:6.0.2" + dependencies: + is-glob: ^4.0.3 + checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 + languageName: node + linkType: hard + +"glob@npm:^11.0.0": + version: 11.1.0 + resolution: "glob@npm:11.1.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 + checksum: 1cfbdc743db77688727411f00233404eb9c67d7c89a4ff1f8b8e60031382d4f695ecf60f279d0d45e5ba2377610572d013a858a433b45a133cf20aba6e3206e0 + languageName: node + linkType: hard + +"glob@npm:^13.0.0": + version: 13.0.6 + resolution: "glob@npm:13.0.6" + dependencies: + minimatch: ^10.2.2 + minipass: ^7.1.3 + path-scurry: ^2.0.2 + checksum: 1eb421c696c66af3c26e4845dbdd222d3b982ede17448456b49272722d872e9a91741b50e4e827370c57d17a39a69790061f45033523f085c076d8fcc0f69d2b + languageName: node + linkType: hard + +"glob@npm:^7.1.3": + version: 7.2.3 + resolution: "glob@npm:7.2.3" + 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 + checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 + languageName: node + linkType: hard + +"globals@npm:^13.19.0": + version: 13.24.0 + resolution: "globals@npm:13.24.0" + dependencies: + type-fest: ^0.20.2 + checksum: 56066ef058f6867c04ff203b8a44c15b038346a62efbc3060052a1016be9f56f4cf0b2cd45b74b22b81e521a889fc7786c73691b0549c2f3a6e825b3d394f43c + languageName: node + linkType: hard + +"globby@npm:^11.1.0": + version: 11.1.0 + resolution: "globby@npm:11.1.0" + 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 + checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + languageName: node + linkType: hard + +"globby@npm:^14.1.0": + version: 14.1.0 + resolution: "globby@npm:14.1.0" + 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 + checksum: b1f27dccc999c010ee7e0ce7c6581fd2326ac86cf0508474d526d699a029b66b35d6fa4361c8b4ad8e80809582af71d5e2080e671cf03c26e98ca67aba8834bd + languageName: node + linkType: hard + +"gopd@npm:^1.2.0": + version: 1.2.0 + resolution: "gopd@npm:1.2.0" + checksum: cc6d8e655e360955bdccaca51a12a474268f95bb793fc3e1f2bdadb075f28bfd1fd988dab872daf77a61d78cbaf13744bc8727a17cfb1d150d76047d805375f3 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: ac85f94da92d8eb6b7f5a8b20ce65e43d66761c55ce85ac96df6865308390da45a8d3f0296dd3a663de65d30ba497bd46c696cc1e248c72b13d6d567138a4fc7 + languageName: node + linkType: hard + +"graphemer@npm:^1.4.0": + version: 1.4.0 + resolution: "graphemer@npm:1.4.0" + checksum: bab8f0be9b568857c7bec9fda95a89f87b783546d02951c40c33f84d05bb7da3fd10f863a9beb901463669b6583173a8c8cc6d6b306ea2b9b9d5d3d943c3a673 + languageName: node + linkType: hard + +"has-flag@npm:^4.0.0": + version: 4.0.0 + resolution: "has-flag@npm:4.0.0" + checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + languageName: node + linkType: hard + +"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": + version: 1.1.0 + resolution: "has-symbols@npm:1.1.0" + checksum: b2316c7302a0e8ba3aaba215f834e96c22c86f192e7310bdf689dd0e6999510c89b00fbc5742571507cebf25764d68c988b3a0da217369a73596191ac0ce694b + languageName: node + linkType: hard + +"has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" + dependencies: + has-symbols: ^1.0.3 + checksum: 999d60bb753ad714356b2c6c87b7fb74f32463b8426e159397da4bde5bca7e598ab1073f4d8d4deafac297f2eb311484cd177af242776bf05f0d11565680468d + languageName: node + linkType: hard + +"hasown@npm:^2.0.2": + version: 2.0.2 + resolution: "hasown@npm:2.0.2" + dependencies: + function-bind: ^1.1.2 + checksum: e8516f776a15149ca6c6ed2ae3110c417a00b62260e222590e54aa367cbcd6ed99122020b37b7fbdf05748df57b265e70095d7bf35a47660587619b15ffb93db + languageName: node + linkType: hard + +"hosted-git-info@npm:^4.0.2": + version: 4.1.0 + resolution: "hosted-git-info@npm:4.1.0" + dependencies: + lru-cache: ^6.0.0 + checksum: c3f87b3c2f7eb8c2748c8f49c0c2517c9a95f35d26f4bf54b2a8cba05d2e668f3753548b6ea366b18ec8dadb4e12066e19fa382a01496b0ffa0497eb23cbe461 + languageName: node + linkType: hard + +"hosted-git-info@npm:^7.0.0": + version: 7.0.2 + resolution: "hosted-git-info@npm:7.0.2" + dependencies: + lru-cache: ^10.0.1 + checksum: 467cf908a56556417b18e86ae3b8dee03c2360ef1d51e61c4028fe87f6f309b6ff038589c94b5666af207da9d972d5107698906aabeb78aca134641962a5c6f8 + languageName: node + linkType: hard + +"htmlparser2@npm:^10.1.0": + version: 10.1.0 + resolution: "htmlparser2@npm:10.1.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.2.2 + entities: ^7.0.1 + checksum: 49b8fa62dcd833b89535523c437d04069400e618b22b8dc8cd48bf6ef820752bb026c4f1fc7309d08b6016bfcd3cc0eca4ed48d5eeff4a3e010be19027d51c70 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.1.1": + version: 4.2.0 + resolution: "http-cache-semantics@npm:4.2.0" + checksum: 7a7246ddfce629f96832791176fd643589d954e6f3b49548dadb4290451961237fab8fcea41cd2008fe819d95b41c1e8b97f47d088afc0a1c81705287b4ddbcc + languageName: node + linkType: hard + +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: ^7.1.0 + debug: ^4.3.4 + checksum: 670858c8f8f3146db5889e1fa117630910101db601fff7d5a8aa637da0abedf68c899f03d3451cac2f83bcc4c3d2dabf339b3aa00ff8080571cceb02c3ce02f3 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^7.0.0, https-proxy-agent@npm:^7.0.1": + version: 7.0.6 + resolution: "https-proxy-agent@npm:7.0.6" + dependencies: + agent-base: ^7.1.2 + debug: 4 + checksum: b882377a120aa0544846172e5db021fa8afbf83fea2a897d397bd2ddd8095ab268c24bc462f40a15f2a8c600bf4aa05ce52927f70038d4014e68aefecfa94e8d + languageName: node + linkType: hard + +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.3": + version: 0.6.3 + resolution: "iconv-lite@npm:0.6.3" + dependencies: + safer-buffer: ">= 2.1.2 < 3.0.0" + checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + languageName: node + linkType: hard + +"iconv-lite@npm:^0.7.2": + version: 0.7.2 + resolution: "iconv-lite@npm:0.7.2" + dependencies: + safer-buffer: ">= 2.1.2 < 3.0.0" + checksum: faf884c1f631a5d676e3e64054bed891c7c5f616b790082d99ccfbfd017c661a39db8009160268fd65fae57c9154d4d491ebc9c301f3446a078460ef114dc4b8 + languageName: node + linkType: hard + +"ieee754@npm:^1.1.13": + version: 1.2.1 + resolution: "ieee754@npm:1.2.1" + checksum: 5144c0c9815e54ada181d80a0b810221a253562422e7c6c3a60b1901154184f49326ec239d618c416c1c5945a2e197107aee8d986a3dd836b53dffefd99b5e7e + languageName: node + linkType: hard + +"ignore@npm:^5.2.0, ignore@npm:^5.2.4": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be + languageName: node + linkType: hard + +"ignore@npm:^7.0.3": + version: 7.0.5 + resolution: "ignore@npm:7.0.5" + checksum: d0862bf64d3d58bf34d5fb0a9f725bec9ca5ce8cd1aecc8f28034269e8f69b8009ffd79ca3eda96962a6a444687781cd5efdb8c7c8ddc0a6996e36d31c217f14 + languageName: node + linkType: hard + +"import-fresh@npm:^3.2.1": + version: 3.3.1 + resolution: "import-fresh@npm:3.3.1" + dependencies: + parent-module: ^1.0.0 + resolve-from: ^4.0.0 + checksum: a06b19461b4879cc654d46f8a6244eb55eb053437afd4cbb6613cad6be203811849ed3e4ea038783092879487299fda24af932b86bdfff67c9055ba3612b8c87 + languageName: node + linkType: hard + +"imurmurhash@npm:^0.1.4": + version: 0.1.4 + resolution: "imurmurhash@npm:0.1.4" + checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + languageName: node + linkType: hard + +"index-to-position@npm:^1.1.0": + version: 1.2.0 + resolution: "index-to-position@npm:1.2.0" + checksum: 2026188af74d4f4c19de44ca29116f093daf072ff4f4b8dda61668463bd28b097164d43f819684cb2f65ff749bc0dec14fb3956da0299a36faa68255c4eb6858 + languageName: node + linkType: hard + +"inflight@npm:^1.0.4": + version: 1.0.6 + resolution: "inflight@npm:1.0.6" + dependencies: + once: ^1.3.0 + wrappy: 1 + checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + languageName: node + linkType: hard + +"inherits@npm:2, inherits@npm:^2.0.3, inherits@npm:^2.0.4": + version: 2.0.4 + resolution: "inherits@npm:2.0.4" + checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + languageName: node + linkType: hard + +"ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: dfd98b0ca3a4fc1e323e38a6c8eb8936e31a97a918d3b377649ea15bdb15d481207a0dda1021efbd86b464cae29a0d33c1d7dcaf6c5672bee17fa849bc50a1b3 + languageName: node + linkType: hard + +"ip-address@npm:^10.0.1": + version: 10.1.0 + resolution: "ip-address@npm:10.1.0" + checksum: 76b1abcdf52a32e2e05ca1f202f3a8ab8547e5651a9233781b330271bd7f1a741067748d71c4cbb9d9906d9f1fa69e7ddc8b4a11130db4534fdab0e908c84e0d + languageName: node + linkType: hard + +"is-docker@npm:^3.0.0": + version: 3.0.0 + resolution: "is-docker@npm:3.0.0" + bin: + is-docker: cli.js + checksum: b698118f04feb7eaf3338922bd79cba064ea54a1c3db6ec8c0c8d8ee7613e7e5854d802d3ef646812a8a3ace81182a085dfa0a71cc68b06f3fa794b9783b3c90 + languageName: node + linkType: hard + +"is-extglob@npm:^2.1.1": + version: 2.1.1 + resolution: "is-extglob@npm:2.1.1" + checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 + languageName: node + linkType: hard + +"is-fullwidth-code-point@npm:^3.0.0": + version: 3.0.0 + resolution: "is-fullwidth-code-point@npm:3.0.0" + checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + languageName: node + linkType: hard + +"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: ^2.1.1 + checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 + languageName: node + linkType: hard + +"is-inside-container@npm:^1.0.0": + version: 1.0.0 + resolution: "is-inside-container@npm:1.0.0" + dependencies: + is-docker: ^3.0.0 + bin: + is-inside-container: cli.js + checksum: c50b75a2ab66ab3e8b92b3bc534e1ea72ca25766832c0623ac22d134116a98bcf012197d1caabe1d1c4bd5f84363d4aa5c36bb4b585fbcaf57be172cd10a1a03 + languageName: node + linkType: hard + +"is-number@npm:^7.0.0": + version: 7.0.0 + resolution: "is-number@npm:7.0.0" + checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.3": + version: 3.0.3 + resolution: "is-path-inside@npm:3.0.3" + checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 + languageName: node + linkType: hard + +"is-wsl@npm:^3.1.0": + version: 3.1.1 + resolution: "is-wsl@npm:3.1.1" + dependencies: + is-inside-container: ^1.0.0 + checksum: 513d95b89af0e60b43d7b17ecb7eb78edea0a439136a3da37b1b56e215379cc46a9221474ad5b2de044824ca72d7869dee6e015273dc3f71f2bb87c715f9f1dc + languageName: node + linkType: hard + +"isexe@npm:^2.0.0": + version: 2.0.0 + resolution: "isexe@npm:2.0.0" + checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + languageName: node + linkType: hard + +"isexe@npm:^4.0.0": + version: 4.0.0 + resolution: "isexe@npm:4.0.0" + checksum: 2ead327ef596042ef9c9ec5f236b316acfaedb87f4bb61b3c3d574fb2e9c8a04b67305e04733bde52c24d9622fdebd3270aadb632adfbf9cadef88fe30f479e5 + languageName: node + linkType: hard + +"istextorbinary@npm:^9.5.0": + version: 9.5.0 + resolution: "istextorbinary@npm:9.5.0" + dependencies: + binaryextensions: ^6.11.0 + editions: ^6.21.0 + textextensions: ^6.11.0 + checksum: 37100831caceab9f55f089e497d5020e6979598a60f3f2a64ef4a9f7b3c88dea3e75412a5ec9db271350c555505a6d90855f7d8b1e19c870a088b9cc49de8d2e + languageName: node + linkType: hard + +"jackspeak@npm:^4.1.1": + version: 4.2.3 + resolution: "jackspeak@npm:4.2.3" + dependencies: + "@isaacs/cliui": ^9.0.0 + checksum: 256c2a35b781b61a368b29cff30c901163f2726c768920d160a743429ea7ff4a02f254fa5a27ebbf6444c1a544ec45b0f46d5c6a44f6cc23b0bcd2b6b919ccb0 + languageName: node + linkType: hard + +"js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 + languageName: node + linkType: hard + +"js-yaml@npm:^4.1.0, js-yaml@npm:^4.1.1": + version: 4.1.1 + resolution: "js-yaml@npm:4.1.1" + dependencies: + argparse: ^2.0.1 + bin: + js-yaml: bin/js-yaml.js + checksum: ea2339c6930fe048ec31b007b3c90be2714ab3e7defcc2c27ebf30c74fd940358f29070b4345af0019ef151875bf3bc3f8644bea1bab0372652b5044813ac02d + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 9026b03edc2847eefa2e37646c579300a1f3a4586cfb62bf857832b60c852042d0d6ae55d1afb8926163fa54c2b01d83ae24705f34990348bdac6273a29d4581 + languageName: node + linkType: hard + +"json-schema-traverse@npm:^0.4.1": + version: 0.4.1 + resolution: "json-schema-traverse@npm:0.4.1" + checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b + languageName: node + linkType: hard + +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad + languageName: node + linkType: hard + +"json-stable-stringify-without-jsonify@npm:^1.0.1": + version: 1.0.1 + resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" + checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 + languageName: node + linkType: hard + +"json5@npm:^2.2.3": + version: 2.2.3 + resolution: "json5@npm:2.2.3" + bin: + json5: lib/cli.js + checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + languageName: node + linkType: hard + +"jsonc-parser@npm:^3.2.0": + version: 3.3.1 + resolution: "jsonc-parser@npm:3.3.1" + checksum: 81ef19d98d9c6bd6e4a37a95e2753c51c21705cbeffd895e177f4b542cca9cda5fda12fb942a71a2e824a9132cf119dc2e642e9286386055e1365b5478f49a47 + languageName: node + linkType: hard + +"jsonfile@npm:^6.0.1": + version: 6.2.0 + resolution: "jsonfile@npm:6.2.0" + dependencies: + graceful-fs: ^4.1.6 + universalify: ^2.0.0 + dependenciesMeta: + graceful-fs: + optional: true + checksum: c3028ec5c770bb41290c9bb9ca04bdd0a1b698ddbdf6517c9453d3f90fc9e000c9675959fb46891d317690a93c62de03ff1735d8dbe02be83e51168ce85815d3 + languageName: node + linkType: hard + +"jsonwebtoken@npm:^9.0.0": + version: 9.0.3 + resolution: "jsonwebtoken@npm:9.0.3" + dependencies: + jws: ^4.0.1 + lodash.includes: ^4.3.0 + lodash.isboolean: ^3.0.3 + lodash.isinteger: ^4.0.4 + lodash.isnumber: ^3.0.3 + lodash.isplainobject: ^4.0.6 + lodash.isstring: ^4.0.1 + lodash.once: ^4.0.0 + ms: ^2.1.1 + semver: ^7.5.4 + checksum: 22d306335aeba0a0a1a4f7abbc4ee36b4bed3b98c67cdf078f0854845bf5646732e08f1cf1fae802a71c4efb1daef72aa1055d36bce6806caad7b1308b14bcd8 + languageName: node + linkType: hard + +"jwa@npm:^2.0.1": + version: 2.0.1 + resolution: "jwa@npm:2.0.1" + dependencies: + buffer-equal-constant-time: ^1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: ^5.0.1 + checksum: 6a9828c054c407f6718057089bd3d46dfcb1394e1553e3867abd4579dbec7728b4b0759e7253422ab7d824d95615a86427b35c43f94b83fc3a76470ca4bd2037 + languageName: node + linkType: hard + +"jws@npm:^4.0.1": + version: 4.0.1 + resolution: "jws@npm:4.0.1" + dependencies: + jwa: ^2.0.1 + safe-buffer: ^5.0.1 + checksum: c33a060b2cce1e0e49f85054a49a951f9d52a9e2ae732d720f0fc51843c9ac07a68aacd8e9d086ef4c7c4437d42978b698b57a3e7c9bc4a91c0b74276ea85a9a + languageName: node + linkType: hard + +"keytar@npm:^7.7.0": + version: 7.9.0 + resolution: "keytar@npm:7.9.0" + dependencies: + node-addon-api: ^4.3.0 + node-gyp: latest + prebuild-install: ^7.0.1 + checksum: 4dbdd21f69e21a53032cbc949847f57338e42df763c5eec04e1b5d7142a689f95d8c3d74fb3b7dc321b5d678271d8d8d1a0dcaa919673ebc50ef8ce76f354e21 + languageName: node + linkType: hard + +"keyv@npm:^4.5.3": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: 3.0.1 + checksum: 74a24395b1c34bd44ad5cb2b49140d087553e170625240b86755a6604cd65aa16efdbdeae5cdb17ba1284a0fbb25ad06263755dbc71b8d8b06f74232ce3cdd72 + languageName: node + linkType: hard + +"leven@npm:^3.1.0": + version: 3.1.0 + resolution: "leven@npm:3.1.0" + checksum: 638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 + languageName: node + linkType: hard + +"levn@npm:^0.4.1": + version: 0.4.1 + resolution: "levn@npm:0.4.1" + dependencies: + prelude-ls: ^1.2.1 + type-check: ~0.4.0 + checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 + languageName: node + linkType: hard + +"linkify-it@npm:^5.0.0": + version: 5.0.0 + resolution: "linkify-it@npm:5.0.0" + dependencies: + uc.micro: ^2.0.0 + checksum: b0b86cadaf816b64c947a83994ceaad1c15f9fe7e079776ab88699fb71afd7b8fc3fd3d0ae5ebec8c92c1d347be9ba257b8aef338c0ebf81b0d27dcf429a765a + languageName: node + linkType: hard + +"locate-path@npm:^6.0.0": + version: 6.0.0 + resolution: "locate-path@npm:6.0.0" + dependencies: + p-locate: ^5.0.0 + checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a + languageName: node + linkType: hard + +"lodash.includes@npm:^4.3.0": + version: 4.3.0 + resolution: "lodash.includes@npm:4.3.0" + checksum: 71092c130515a67ab3bd928f57f6018434797c94def7f46aafa417771e455ce3a4834889f4267b17887d7f75297dfabd96231bf704fd2b8c5096dc4a913568b6 + languageName: node + linkType: hard + +"lodash.isboolean@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isboolean@npm:3.0.3" + checksum: b70068b4a8b8837912b54052557b21fc4774174e3512ed3c5b94621e5aff5eb6c68089d0a386b7e801d679cd105d2e35417978a5e99071750aa2ed90bffd0250 + languageName: node + linkType: hard + +"lodash.isinteger@npm:^4.0.4": + version: 4.0.4 + resolution: "lodash.isinteger@npm:4.0.4" + checksum: 6034821b3fc61a2ffc34e7d5644bb50c5fd8f1c0121c554c21ac271911ee0c0502274852845005f8651d51e199ee2e0cfebfe40aaa49c7fe617f603a8a0b1691 + languageName: node + linkType: hard + +"lodash.isnumber@npm:^3.0.3": + version: 3.0.3 + resolution: "lodash.isnumber@npm:3.0.3" + checksum: 913784275b565346255e6ae6a6e30b760a0da70abc29f3e1f409081585875105138cda4a429ff02577e1bc0a7ae2a90e0a3079a37f3a04c3d6c5aaa532f4cab2 + languageName: node + linkType: hard + +"lodash.isplainobject@npm:^4.0.6": + version: 4.0.6 + resolution: "lodash.isplainobject@npm:4.0.6" + checksum: 29c6351f281e0d9a1d58f1a4c8f4400924b4c79f18dfc4613624d7d54784df07efaff97c1ff2659f3e085ecf4fff493300adc4837553104cef2634110b0d5337 + languageName: node + linkType: hard + +"lodash.isstring@npm:^4.0.1": + version: 4.0.1 + resolution: "lodash.isstring@npm:4.0.1" + checksum: eaac87ae9636848af08021083d796e2eea3d02e80082ab8a9955309569cb3a463ce97fd281d7dc119e402b2e7d8c54a23914b15d2fc7fff56461511dc8937ba0 + languageName: node + linkType: hard + +"lodash.merge@npm:^4.6.2": + version: 4.6.2 + resolution: "lodash.merge@npm:4.6.2" + checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 + languageName: node + linkType: hard + +"lodash.once@npm:^4.0.0": + version: 4.1.1 + resolution: "lodash.once@npm:4.1.1" + checksum: d768fa9f9b4e1dc6453be99b753906f58990e0c45e7b2ca5a3b40a33111e5d17f6edf2f768786e2716af90a8e78f8f91431ab8435f761fef00f9b0c256f6d245 + languageName: node + linkType: hard + +"lodash.truncate@npm:^4.4.2": + version: 4.4.2 + resolution: "lodash.truncate@npm:4.4.2" + checksum: b463d8a382cfb5f0e71c504dcb6f807a7bd379ff1ea216669aa42c52fc28c54e404bfbd96791aa09e6df0de2c1d7b8f1b7f4b1a61f324d38fe98bc535aeee4f5 + languageName: node + linkType: hard + +"lodash@npm:^4.17.23": + version: 4.17.23 + resolution: "lodash@npm:4.17.23" + checksum: 7daad39758a72872e94651630fbb54ba76868f904211089721a64516ce865506a759d9ad3d8ff22a2a49a50a09db5d27c36f22762d21766e47e3ba918d6d7bab + languageName: node + linkType: hard + +"lru-cache@npm:^10.0.1": + version: 10.4.3 + resolution: "lru-cache@npm:10.4.3" + checksum: 6476138d2125387a6d20f100608c2583d415a4f64a0fecf30c9e2dda976614f09cad4baa0842447bd37dd459a7bd27f57d9d8f8ce558805abd487c583f3d774a + languageName: node + linkType: hard + +"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": + version: 11.2.6 + resolution: "lru-cache@npm:11.2.6" + checksum: 26fe602c92a0cb7a8da9a85db162ddd810d84507d9c4ef8d95a785a805648f9579e1148aaeac260f6b6315197bcf27c1b7e60a0a066621d6e95b3587699a0c70 + languageName: node + linkType: hard + +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" + dependencies: + yallist: ^4.0.0 + checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 + languageName: node + linkType: hard + +"make-fetch-happen@npm:^15.0.0": + version: 15.0.4 + resolution: "make-fetch-happen@npm:15.0.4" + dependencies: + "@gar/promise-retry": ^1.0.0 + "@npmcli/agent": ^4.0.0 + cacache: ^20.0.1 + http-cache-semantics: ^4.1.1 + minipass: ^7.0.2 + minipass-fetch: ^5.0.0 + minipass-flush: ^1.0.5 + minipass-pipeline: ^1.2.4 + negotiator: ^1.0.0 + proc-log: ^6.0.0 + ssri: ^13.0.0 + checksum: eb875e1fbdf58b4d6d7c6c2ee97a2521b407f85d1fb2c0e6bc2c2d9d13fa34c3198eff3512589dc26e8fb32684e4e52f3c9d844a704ac96b393559a88b5e57ca + languageName: node + linkType: hard + +"markdown-it@npm:^14.1.0": + version: 14.1.1 + resolution: "markdown-it@npm:14.1.1" + 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 + checksum: d6d55865c60debc4cc21d7288f0f6ea04ca055af79c58c467a29c949a289b7e679912c2575d79edb20f55ff3b4548f75b1e1184f939223fa32b08331c5fee81c + languageName: node + linkType: hard + +"math-intrinsics@npm:^1.1.0": + version: 1.1.0 + resolution: "math-intrinsics@npm:1.1.0" + checksum: 0e513b29d120f478c85a70f49da0b8b19bc638975eca466f2eeae0071f3ad00454c621bf66e16dd435896c208e719fc91ad79bbfba4e400fe0b372e7c1c9c9a2 + languageName: node + linkType: hard + +"mdurl@npm:^2.0.0": + version: 2.0.0 + resolution: "mdurl@npm:2.0.0" + checksum: 880bc289ef668df0bb34c5b2b5aaa7b6ea755052108cdaf4a5e5968ad01cf27e74927334acc9ebcc50a8628b65272ae6b1fd51fae1330c130e261c0466e1a3b2 + languageName: node + linkType: hard + +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": + version: 1.4.1 + resolution: "merge2@npm:1.4.1" + checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 + languageName: node + linkType: hard + +"micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: ^3.0.3 + picomatch: ^2.3.1 + checksum: 79920eb634e6f400b464a954fcfa589c4e7c7143209488e44baf627f9affc8b1e306f41f4f0deedde97e69cb725920879462d3e750ab3bd3c1aed675bb3a8966 + languageName: node + linkType: hard + +"mime-db@npm:1.52.0": + version: 1.52.0 + resolution: "mime-db@npm:1.52.0" + checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + languageName: node + linkType: hard + +"mime-types@npm:^2.1.12": + version: 2.1.35 + resolution: "mime-types@npm:2.1.35" + dependencies: + mime-db: 1.52.0 + checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + languageName: node + linkType: hard + +"mime@npm:^1.3.4": + version: 1.6.0 + resolution: "mime@npm:1.6.0" + bin: + mime: cli.js + checksum: fef25e39263e6d207580bdc629f8872a3f9772c923c7f8c7e793175cee22777bbe8bba95e5d509a40aaa292d8974514ce634ae35769faa45f22d17edda5e8557 + languageName: node + linkType: hard + +"mimic-response@npm:^3.1.0": + version: 3.1.0 + resolution: "mimic-response@npm:3.1.0" + checksum: 25739fee32c17f433626bf19f016df9036b75b3d84a3046c7d156e72ec963dd29d7fc8a302f55a3d6c5a4ff24259676b15d915aad6480815a969ff2ec0836867 + languageName: node + linkType: hard + +"minimatch@npm:9.0.3": + version: 9.0.3 + resolution: "minimatch@npm:9.0.3" + dependencies: + brace-expansion: ^2.0.1 + checksum: 253487976bf485b612f16bf57463520a14f512662e592e95c571afdab1442a6a6864b6c88f248ce6fc4ff0b6de04ac7aa6c8bb51e868e99d1d65eb0658a708b5 + languageName: node + linkType: hard + +"minimatch@npm:^10.1.1, minimatch@npm:^10.2.2": + version: 10.2.4 + resolution: "minimatch@npm:10.2.4" + dependencies: + brace-expansion: ^5.0.2 + checksum: 56dce6b04c6b30b500d81d7a29822c108b7d58c46696ec7332d04a2bd104a5cb69e5c7ce93e1783dc66d61400d831e6e226ca101ac23665aff32ca303619dc3d + languageName: node + linkType: hard + +"minimatch@npm:^3.0.3, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" + dependencies: + brace-expansion: ^1.1.7 + checksum: 47ef6f412c08be045a7291d11b1c40777925accf7252dc6d3caa39b1bfbb3a7ea390ba7aba464d762d783265c644143d2c8a204e6b5763145024d52ee65a1941 + languageName: node + linkType: hard + +"minimatch@npm:^5.1.0": + version: 5.1.9 + resolution: "minimatch@npm:5.1.9" + dependencies: + brace-expansion: ^2.0.1 + checksum: 418438bd7701ba811f1108f28fcd3a638a6065c7b1245b85e25bcdb674410b4bebd8763c90c91bc8d22d93260c02cc129b354267a463c3399be5732d6e11e120 + languageName: node + linkType: hard + +"minimist@npm:^1.2.0, minimist@npm:^1.2.3": + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 75a6d645fb122dad29c06a7597bddea977258957ed88d7a6df59b5cd3fe4a527e253e9bbf2e783e4b73657f9098b96a5fe96ab8a113655d4109108577ecf85b0 + languageName: node + linkType: hard + +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" + dependencies: + minipass: ^7.0.3 + checksum: b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 + languageName: node + linkType: hard + +"minipass-fetch@npm:^5.0.0": + version: 5.0.2 + resolution: "minipass-fetch@npm:5.0.2" + dependencies: + iconv-lite: ^0.7.2 + minipass: ^7.0.3 + minipass-sized: ^2.0.0 + minizlib: ^3.0.1 + dependenciesMeta: + iconv-lite: + optional: true + checksum: d4dfdd9700fc8aba445834f75f2abaf9e5d404c10eda06e2db4a8ba89fc66a26956d19703d0edf9be864cb30dec22356d343509ad0a105446516c0ead4330328 + languageName: node + linkType: hard + +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" + dependencies: + minipass: ^3.0.0 + checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + languageName: node + linkType: hard + +"minipass-pipeline@npm:^1.2.4": + version: 1.2.4 + resolution: "minipass-pipeline@npm:1.2.4" + dependencies: + minipass: ^3.0.0 + checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + languageName: node + linkType: hard + +"minipass-sized@npm:^2.0.0": + version: 2.0.0 + resolution: "minipass-sized@npm:2.0.0" + dependencies: + minipass: ^7.1.2 + checksum: 1a1fd251aef4e24050a04ea03fdc0514960f7304a374fd01f352bfdb72c0a2c084ad05d63e76011c181cadfb38dbf487f8782e1e778337f6a099ac2da26b6d5d + languageName: node + linkType: hard + +"minipass@npm:^3.0.0": + version: 3.3.6 + resolution: "minipass@npm:3.3.6" + dependencies: + yallist: ^4.0.0 + checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + languageName: node + linkType: hard + +"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": + version: 7.1.3 + resolution: "minipass@npm:7.1.3" + checksum: 2ede17c0bf8fec499be3360fd07f0ec7666189e3907320a9b653f1530cf84af98928c5b12d80bfb75f321833bf2e97785b940540213ebdafe97a5f10327e664d + languageName: node + linkType: hard + +"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": + version: 3.1.0 + resolution: "minizlib@npm:3.1.0" + dependencies: + minipass: ^7.1.2 + checksum: a15e6f0128f514b7d41a1c68ce531155447f4669e32d279bba1c1c071ef6c2abd7e4d4579bb59ccc2ed1531346749665968fdd7be8d83eb6b6ae2fe1f3d370a7 + languageName: node + linkType: hard + +"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": + version: 0.5.3 + resolution: "mkdirp-classic@npm:0.5.3" + checksum: 3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac + languageName: node + linkType: hard + +"ms@npm:^2.1.1, ms@npm:^2.1.3": + version: 2.1.3 + resolution: "ms@npm:2.1.3" + checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + languageName: node + linkType: hard + +"mute-stream@npm:~0.0.4": + version: 0.0.8 + resolution: "mute-stream@npm:0.0.8" + checksum: ff48d251fc3f827e5b1206cda0ffdaec885e56057ee86a3155e1951bc940fd5f33531774b1cc8414d7668c10a8907f863f6561875ee6e8768931a62121a531a1 + languageName: node + linkType: hard + +"napi-build-utils@npm:^2.0.0": + version: 2.0.0 + resolution: "napi-build-utils@npm:2.0.0" + checksum: 532121efd2dd2272595580bca48859e404bdd4ed455a72a28432ba44868c38d0e64fac3026a8f82bf8563d2a18b32eb9a1d59e601a9da4e84ba4d45b922297f5 + languageName: node + linkType: hard + +"natural-compare@npm:^1.4.0": + version: 1.4.0 + resolution: "natural-compare@npm:1.4.0" + checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d + languageName: node + linkType: hard + +"negotiator@npm:^1.0.0": + version: 1.0.0 + resolution: "negotiator@npm:1.0.0" + checksum: 20ebfe79b2d2e7cf9cbc8239a72662b584f71164096e6e8896c8325055497c96f6b80cd22c258e8a2f2aa382a787795ec3ee8b37b422a302c7d4381b0d5ecfbb + languageName: node + linkType: hard + +"node-abi@npm:^3.3.0": + version: 3.87.0 + resolution: "node-abi@npm:3.87.0" + dependencies: + semver: ^7.3.5 + checksum: ffe24d2e9e9fcf46c9aff7ddd93cbd5b128ce0a7a4032019ce2eeef3d5fad34cfc7f48650e3051fc87bb28621f6d2be166d0a19135ba80d39182897cb4bd29e1 + languageName: node + linkType: hard + +"node-addon-api@npm:^4.3.0": + version: 4.3.0 + resolution: "node-addon-api@npm:4.3.0" + dependencies: + node-gyp: latest + checksum: 3de396e23cc209f539c704583e8e99c148850226f6e389a641b92e8967953713228109f919765abc1f4355e801e8f41842f96210b8d61c7dcc10a477002dcf00 + languageName: node + linkType: hard + +"node-gyp@npm:latest": + version: 12.2.0 + resolution: "node-gyp@npm:12.2.0" + dependencies: + env-paths: ^2.2.0 + exponential-backoff: ^3.1.1 + graceful-fs: ^4.2.6 + make-fetch-happen: ^15.0.0 + nopt: ^9.0.0 + proc-log: ^6.0.0 + semver: ^7.3.5 + tar: ^7.5.4 + tinyglobby: ^0.2.12 + which: ^6.0.0 + bin: + node-gyp: bin/node-gyp.js + checksum: d4ce0acd08bd41004f45e10cef468f4bd15eaafb3acc388a0c567416e1746dc005cc080b8a3495e4e2ae2eed170a2123ff622c2d6614062f4a839837dcf1dd9d + languageName: node + linkType: hard + +"node-sarif-builder@npm:^3.2.0": + version: 3.4.0 + resolution: "node-sarif-builder@npm:3.4.0" + dependencies: + "@types/sarif": ^2.1.7 + fs-extra: ^11.1.1 + checksum: 394e70cc19be7f9c6c796a1467ec2bac8bd5522c8bc6926b27c4731a64aa168129fa7d919c819aecf1aecb920a2f79c0766716a3375ae8040cc1823326229d83 + languageName: node + linkType: hard + +"nopt@npm:^9.0.0": + version: 9.0.0 + resolution: "nopt@npm:9.0.0" + dependencies: + abbrev: ^4.0.0 + bin: + nopt: bin/nopt.js + checksum: 7a5d9ab0629eaec1944a95438cc4efa6418ed2834aa8eb21a1bea579a7d8ac3e30120131855376a96ef59ab0e23ad8e0bc94d3349770a95e5cb7119339f7c7fb + languageName: node + linkType: hard + +"normalize-package-data@npm:^6.0.0": + version: 6.0.2 + resolution: "normalize-package-data@npm:6.0.2" + dependencies: + hosted-git-info: ^7.0.0 + semver: ^7.3.5 + validate-npm-package-license: ^3.0.4 + checksum: ea35f8de68e03fc845f545c8197857c0cd256207fdb809ca63c2b39fe76ae77765ee939eb21811fb6c3b533296abf49ebe3cd617064f98a775adaccb24ff2e03 + languageName: node + linkType: hard + +"nth-check@npm:^2.0.1": + version: 2.1.1 + resolution: "nth-check@npm:2.1.1" + dependencies: + boolbase: ^1.0.0 + checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 + languageName: node + linkType: hard + +"object-inspect@npm:^1.13.3": + version: 1.13.4 + resolution: "object-inspect@npm:1.13.4" + checksum: 582810c6a8d2ef988ea0a39e69e115a138dad8f42dd445383b394877e5816eb4268489f316a6f74ee9c4e0a984b3eab1028e3e79d62b1ed67c726661d55c7a8b + languageName: node + linkType: hard + +"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": + version: 1.4.0 + resolution: "once@npm:1.4.0" + dependencies: + wrappy: 1 + checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + languageName: node + linkType: hard + +"open@npm:^10.1.0": + version: 10.2.0 + resolution: "open@npm:10.2.0" + dependencies: + default-browser: ^5.2.1 + define-lazy-prop: ^3.0.0 + is-inside-container: ^1.0.0 + wsl-utils: ^0.1.0 + checksum: 64e2e1fb1dc5ab82af06c990467237b8fd349b1b9ecc6324d12df337a005d039cec11f758abea148be68878ccd616977005682c48ef3c5c7ba48bd3e5d6a3dbb + languageName: node + linkType: hard + +"optionator@npm:^0.9.3": + version: 0.9.4 + resolution: "optionator@npm:0.9.4" + 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 + checksum: ecbd010e3dc73e05d239976422d9ef54a82a13f37c11ca5911dff41c98a6c7f0f163b27f922c37e7f8340af9d36febd3b6e9cef508f3339d4c393d7276d716bb + languageName: node + linkType: hard + +"p-limit@npm:^3.0.2": + version: 3.1.0 + resolution: "p-limit@npm:3.1.0" + dependencies: + yocto-queue: ^0.1.0 + checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 + languageName: node + linkType: hard + +"p-locate@npm:^5.0.0": + version: 5.0.0 + resolution: "p-locate@npm:5.0.0" + dependencies: + p-limit: ^3.0.2 + checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 + languageName: node + linkType: hard + +"p-map@npm:^7.0.2, p-map@npm:^7.0.3": + version: 7.0.4 + resolution: "p-map@npm:7.0.4" + checksum: 4be2097e942f2fd3a4f4b0c6585c721f23851de8ad6484d20c472b3ea4937d5cd9a59914c832b1bceac7bf9d149001938036b82a52de0bc381f61ff2d35d26a5 + languageName: node + linkType: hard + +"package-json-from-dist@npm:^1.0.0": + version: 1.0.1 + resolution: "package-json-from-dist@npm:1.0.1" + checksum: 58ee9538f2f762988433da00e26acc788036914d57c71c246bf0be1b60cdbd77dd60b6a3e1a30465f0b248aeb80079e0b34cb6050b1dfa18c06953bb1cbc7602 + languageName: node + linkType: hard + +"parent-module@npm:^1.0.0": + version: 1.0.1 + resolution: "parent-module@npm:1.0.1" + dependencies: + callsites: ^3.0.0 + checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff + languageName: node + linkType: hard + +"parse-json@npm:^8.0.0": + version: 8.3.0 + resolution: "parse-json@npm:8.3.0" + dependencies: + "@babel/code-frame": ^7.26.2 + index-to-position: ^1.1.0 + type-fest: ^4.39.1 + checksum: 23812dd66a8ceedfeb0fd8a92c96b88b18bc1030cf1f07cd29146b711a208ef91ac995cf14517422f908fa930f84324086bf22fdcc1013029776cc01d589bae4 + languageName: node + linkType: hard + +"parse-semver@npm:^1.1.1": + version: 1.1.1 + resolution: "parse-semver@npm:1.1.1" + dependencies: + semver: ^5.1.0 + checksum: 0a9abc24b829b4db6dfd733727c2dd15b085c388b7c0bcc03e801412c1ebfe53a087613240f90af0dbed3a3283057bd320014b0df4b9222e01b4e3757b5c6e6a + languageName: node + linkType: hard + +"parse5-htmlparser2-tree-adapter@npm:^7.1.0": + version: 7.1.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.1.0" + dependencies: + domhandler: ^5.0.3 + parse5: ^7.0.0 + checksum: 98326fc5443e2149e10695adbfd0b0b3383c54398799f858b4ac2914adb199af8fcc90c2143aa5f7fd5f9482338f26ef253b468722f34d50bb215ec075d89fe9 + languageName: node + linkType: hard + +"parse5-parser-stream@npm:^7.1.2": + version: 7.1.2 + resolution: "parse5-parser-stream@npm:7.1.2" + dependencies: + parse5: ^7.0.0 + checksum: 75b232d460bce6bd0e35012750a78ef034f40ccf550b7c6cec3122395af6b4553202ad3663ad468cf537ead5a2e13b6727670395fd0ff548faccad1dc2dc93cf + languageName: node + linkType: hard + +"parse5@npm:^7.0.0, parse5@npm:^7.3.0": + version: 7.3.0 + resolution: "parse5@npm:7.3.0" + dependencies: + entities: ^6.0.0 + checksum: ffd040c4695d93f0bc370e3d6d75c1b352178514af41be7afa212475ea5cead1d6e377cd9d4cec6a5e2bcf497ca50daf9e0088eadaa37dbc271f60def08fdfcd + languageName: node + linkType: hard + +"path-exists@npm:^4.0.0": + version: 4.0.0 + resolution: "path-exists@npm:4.0.0" + checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 + languageName: node + linkType: hard + +"path-is-absolute@npm:^1.0.0": + version: 1.0.1 + resolution: "path-is-absolute@npm:1.0.1" + checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + languageName: node + linkType: hard + +"path-key@npm:^3.1.0": + version: 3.1.1 + resolution: "path-key@npm:3.1.1" + checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + languageName: node + linkType: hard + +"path-scurry@npm:^2.0.0, path-scurry@npm:^2.0.2": + version: 2.0.2 + resolution: "path-scurry@npm:2.0.2" + dependencies: + lru-cache: ^11.0.0 + minipass: ^7.1.2 + checksum: a723afe86e342e19dd1b49ce4f5b64a9a84b1e2e07ffc62f051c11623ecd461b1bf1599eee1ecacfce03dda8b6bb866a5df80c0ded45375d258ff22f631920a7 + languageName: node + linkType: hard + +"path-type@npm:^4.0.0": + version: 4.0.0 + resolution: "path-type@npm:4.0.0" + checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 + languageName: node + linkType: hard + +"path-type@npm:^6.0.0": + version: 6.0.0 + resolution: "path-type@npm:6.0.0" + checksum: b9f6eaf7795c48d5c9bc4c6bc3ac61315b8d36975a73497ab2e02b764c0836b71fb267ea541863153f633a069a1c2ed3c247cb781633842fc571c655ac57c00e + languageName: node + linkType: hard + +"pend@npm:~1.2.0": + version: 1.2.0 + resolution: "pend@npm:1.2.0" + checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d + languageName: node + linkType: hard + +"picocolors@npm:^1.1.1": + version: 1.1.1 + resolution: "picocolors@npm:1.1.1" + checksum: e1cf46bf84886c79055fdfa9dcb3e4711ad259949e3565154b004b260cd356c5d54b31a1437ce9782624bf766272fe6b0154f5f0c744fb7af5d454d2b60db045 + languageName: node + linkType: hard + +"picomatch@npm:^2.3.1": + version: 2.3.1 + resolution: "picomatch@npm:2.3.1" + checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf + languageName: node + linkType: hard + +"picomatch@npm:^4.0.3": + version: 4.0.3 + resolution: "picomatch@npm:4.0.3" + checksum: 6817fb74eb745a71445debe1029768de55fd59a42b75606f478ee1d0dc1aa6e78b711d041a7c9d5550e042642029b7f373dc1a43b224c4b7f12d23436735dba0 + languageName: node + linkType: hard + +"pluralize@npm:^2.0.0": + version: 2.0.0 + resolution: "pluralize@npm:2.0.0" + checksum: 4fa9c30830ef913c01b9cf576375225701a62002fc3ec8848e78bd5e1763529bef8ffc2c48fcd72ba06fc3b1058981b4d98cb06701d56a7edfe69cf14c4b8dc1 + languageName: node + linkType: hard + +"pluralize@npm:^8.0.0": + version: 8.0.0 + resolution: "pluralize@npm:8.0.0" + checksum: 08931d4a6a4a5561a7f94f67a31c17e6632cb21e459ab3ff4f6f629d9a822984cf8afef2311d2005fbea5d7ef26016ebb090db008e2d8bce39d0a9a9d218736e + languageName: node + linkType: hard + +"prebuild-install@npm:^7.0.1": + version: 7.1.3 + resolution: "prebuild-install@npm:7.1.3" + 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 + checksum: 300740ca415e9ddbf2bd363f1a6d2673cc11dd0665c5ec431bbb5bf024c2f13c56791fb939ce2b2a2c12f2d2a09c91316169e8063a80eb4482a44b8fe5b265e1 + languageName: node + linkType: hard + +"prelude-ls@npm:^1.2.1": + version: 1.2.1 + resolution: "prelude-ls@npm:1.2.1" + checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a + languageName: node + linkType: hard + +"proc-log@npm:^6.0.0": + version: 6.1.0 + resolution: "proc-log@npm:6.1.0" + checksum: ac450ff8244e95b0c9935b52d629fef92ae69b7e39aea19972a8234259614d644402dd62ce9cb094f4a637d8a4514cba90c1456ad785a40ad5b64d502875a817 + languageName: node + linkType: hard + +"pump@npm:^3.0.0": + version: 3.0.4 + resolution: "pump@npm:3.0.4" + dependencies: + end-of-stream: ^1.1.0 + once: ^1.3.1 + checksum: d043c3e710c56ffd280711e98a94e863ab334f79ea43cee0fb70e1349b2355ffd2ff287c7522e4c960a247699d5b7825f00fa090b85d6179c973be13f78a6c49 + languageName: node + linkType: hard + +"punycode.js@npm:^2.3.1": + version: 2.3.1 + resolution: "punycode.js@npm:2.3.1" + checksum: 13466d7ed5e8dacdab8c4cc03837e7dd14218a59a40eb14a837f1f53ca396e18ef2c4ee6d7766b8ed2fc391d6a3ac489eebf2de83b3596f5a54e86df4a251b72 + languageName: node + linkType: hard + +"punycode@npm:^2.1.0": + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2 + languageName: node + linkType: hard + +"qs@npm:^6.9.1": + version: 6.15.0 + resolution: "qs@npm:6.15.0" + dependencies: + side-channel: ^1.1.0 + checksum: 65e797e3747fa1092e062da7b3e0684a9194e07ccab3a9467d416d2579d2feab0adf3aa4b94446e9f69ba7426589a8728f78a10a549308c97563a79d1c0d8595 + languageName: node + linkType: hard + +"queue-microtask@npm:^1.2.2": + version: 1.2.3 + resolution: "queue-microtask@npm:1.2.3" + checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 + languageName: node + linkType: hard + +"rc-config-loader@npm:^4.1.3": + version: 4.1.4 + resolution: "rc-config-loader@npm:4.1.4" + dependencies: + debug: ^4.4.3 + js-yaml: ^4.1.1 + json5: ^2.2.3 + require-from-string: ^2.0.2 + checksum: 3541eebd7c790bcdfee73f9220ca7894c041a37260a1a2cbc7f9c3c3fc6596df67efd27205262234b0417744abb1f84dd98e9baf781d84e25e062123dccf9a86 + languageName: node + linkType: hard + +"rc@npm:^1.2.7": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: ^0.6.0 + ini: ~1.3.0 + minimist: ^1.2.0 + strip-json-comments: ~2.0.1 + bin: + rc: ./cli.js + checksum: 2e26e052f8be2abd64e6d1dabfbd7be03f80ec18ccbc49562d31f617d0015fbdbcf0f9eed30346ea6ab789e0fdfe4337f033f8016efdbee0df5354751842080e + languageName: node + linkType: hard + +"read-pkg@npm:^9.0.1": + version: 9.0.1 + resolution: "read-pkg@npm:9.0.1" + 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 + checksum: 5544bea2a58c6e5706db49a96137e8f0768c69395f25363f934064fbba00bdcdaa326fcd2f4281741df38cf81dbf27b76138240dc6de0ed718cf650475e0de3c + languageName: node + linkType: hard + +"read@npm:^1.0.7": + version: 1.0.7 + resolution: "read@npm:1.0.7" + dependencies: + mute-stream: ~0.0.4 + checksum: 2777c254e5732cac96f5d0a1c0f6b836c89ae23d8febd405b206f6f24d5de1873420f1a0795e0e3721066650d19adf802c7882c4027143ee0acf942a4f34f97b + languageName: node + linkType: hard + +"readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" + dependencies: + inherits: ^2.0.3 + string_decoder: ^1.1.1 + util-deprecate: ^1.0.1 + checksum: bdcbe6c22e846b6af075e32cf8f4751c2576238c5043169a1c221c92ee2878458a816a4ea33f4c67623c0b6827c8a400409bfb3cf0bf3381392d0b1dfb52ac8d + languageName: node + linkType: hard + +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b + languageName: node + linkType: hard + +"resolve-from@npm:^4.0.0": + version: 4.0.0 + resolution: "resolve-from@npm:4.0.0" + checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f + languageName: node + linkType: hard + +"retry@npm:^0.13.1": + version: 0.13.1 + resolution: "retry@npm:0.13.1" + checksum: 47c4d5be674f7c13eee4cfe927345023972197dbbdfba5d3af7e461d13b44de1bfd663bfc80d2f601f8ef3fc8164c16dd99655a221921954a65d044a2fc1233b + languageName: node + linkType: hard + +"reusify@npm:^1.0.4": + version: 1.1.0 + resolution: "reusify@npm:1.1.0" + checksum: 64cb3142ac5e9ad689aca289585cb41d22521f4571f73e9488af39f6b1bd62f0cbb3d65e2ecc768ec6494052523f473f1eb4b55c3e9014b3590c17fc6a03e22a + languageName: node + linkType: hard + +"rimraf@npm:^3.0.2": + version: 3.0.2 + resolution: "rimraf@npm:3.0.2" + dependencies: + glob: ^7.1.3 + bin: + rimraf: bin.js + checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + languageName: node + linkType: hard + +"run-applescript@npm:^7.0.0": + version: 7.1.0 + resolution: "run-applescript@npm:7.1.0" + checksum: 8659fb5f2717b2b37a68cbfe5f678254cf24b5a82a6df3372b180c80c7c137dcd757a4166c3887e459f59a090ca414e8ea7ca97cf3ee5123db54b3b4006d7b7a + languageName: node + linkType: hard + +"run-parallel@npm:^1.1.9": + version: 1.2.0 + resolution: "run-parallel@npm:1.2.0" + dependencies: + queue-microtask: ^1.2.2 + checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d + languageName: node + linkType: hard + +"safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": + version: 5.2.1 + resolution: "safe-buffer@npm:5.2.1" + checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + languageName: node + linkType: hard + +"safer-buffer@npm:>= 2.1.2 < 3.0.0": + version: 2.1.2 + resolution: "safer-buffer@npm:2.1.2" + checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + languageName: node + linkType: hard + +"sax@npm:>=0.6.0": + version: 1.5.0 + resolution: "sax@npm:1.5.0" + checksum: e143cbeb6ca59345db142d97d1bbb620553beb8b166eda36ffeaba4b01af47dcf0423cd8781d0805b75feea69462cf80d0db7bf0a7e6dd87b711fda51b9153df + languageName: node + linkType: hard + +"secretlint@npm:^10.1.2": + version: 10.2.2 + resolution: "secretlint@npm:10.2.2" + dependencies: + "@secretlint/config-creator": ^10.2.2 + "@secretlint/formatter": ^10.2.2 + "@secretlint/node": ^10.2.2 + "@secretlint/profiler": ^10.2.2 + debug: ^4.4.1 + globby: ^14.1.0 + read-pkg: ^9.0.1 + bin: + secretlint: ./bin/secretlint.js + checksum: cb3dfc4d4070145ecd45b724b79e6913734bf5b4e289f8537ef6db86086e8b2c06c0ee5e5c4c8b5afba9dc8a905df0f6f78dfff2047c8d812bb2a9f9dbc16131 + languageName: node + linkType: hard + +"semver@npm:^5.1.0": + version: 5.7.2 + resolution: "semver@npm:5.7.2" + bin: + semver: bin/semver + checksum: fb4ab5e0dd1c22ce0c937ea390b4a822147a9c53dbd2a9a0132f12fe382902beef4fbf12cf51bb955248d8d15874ce8cd89532569756384f994309825f10b686 + languageName: node + linkType: hard + +"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.2, semver@npm:^7.5.4": + version: 7.7.4 + resolution: "semver@npm:7.7.4" + bin: + semver: bin/semver.js + checksum: 9b4a6a58e98b9723fafcafa393c9d4e8edefaa60b8dfbe39e30892a3604cf1f45f52df9cfb1ae1a22b44c8b3d57fec8a9bb7b3e1645431587cb272399ede152e + languageName: node + linkType: hard + +"shebang-command@npm:^2.0.0": + version: 2.0.0 + resolution: "shebang-command@npm:2.0.0" + dependencies: + shebang-regex: ^3.0.0 + checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + languageName: node + linkType: hard + +"shebang-regex@npm:^3.0.0": + version: 3.0.0 + resolution: "shebang-regex@npm:3.0.0" + checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + languageName: node + linkType: hard + +"side-channel-list@npm:^1.0.0": + version: 1.0.0 + resolution: "side-channel-list@npm:1.0.0" + dependencies: + es-errors: ^1.3.0 + object-inspect: ^1.13.3 + checksum: 603b928997abd21c5a5f02ae6b9cc36b72e3176ad6827fab0417ead74580cc4fb4d5c7d0a8a2ff4ead34d0f9e35701ed7a41853dac8a6d1a664fcce1a044f86f + languageName: node + linkType: hard + +"side-channel-map@npm:^1.0.1": + version: 1.0.1 + resolution: "side-channel-map@npm:1.0.1" + dependencies: + call-bound: ^1.0.2 + es-errors: ^1.3.0 + get-intrinsic: ^1.2.5 + object-inspect: ^1.13.3 + checksum: 42501371cdf71f4ccbbc9c9e2eb00aaaab80a4c1c429d5e8da713fd4d39ef3b8d4a4b37ed4f275798a65260a551a7131fd87fe67e922dba4ac18586d6aab8b06 + languageName: node + linkType: hard + +"side-channel-weakmap@npm:^1.0.2": + version: 1.0.2 + resolution: "side-channel-weakmap@npm:1.0.2" + 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 + checksum: a815c89bc78c5723c714ea1a77c938377ea710af20d4fb886d362b0d1f8ac73a17816a5f6640f354017d7e292a43da9c5e876c22145bac00b76cfb3468001736 + languageName: node + linkType: hard + +"side-channel@npm:^1.1.0": + version: 1.1.0 + resolution: "side-channel@npm:1.1.0" + 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 + checksum: bf73d6d6682034603eb8e99c63b50155017ed78a522d27c2acec0388a792c3ede3238b878b953a08157093b85d05797217d270b7666ba1f111345fbe933380ff + languageName: node + linkType: hard + +"signal-exit@npm:^4.0.1": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 64c757b498cb8629ffa5f75485340594d2f8189e9b08700e69199069c8e3070fb3e255f7ab873c05dc0b3cec412aea7402e10a5990cb6a050bd33ba062a6c549 + languageName: node + linkType: hard + +"simple-concat@npm:^1.0.0": + version: 1.0.1 + resolution: "simple-concat@npm:1.0.1" + checksum: 4d211042cc3d73a718c21ac6c4e7d7a0363e184be6a5ad25c8a1502e49df6d0a0253979e3d50dbdd3f60ef6c6c58d756b5d66ac1e05cda9cacd2e9fc59e3876a + languageName: node + linkType: hard + +"simple-get@npm:^4.0.0": + version: 4.0.1 + resolution: "simple-get@npm:4.0.1" + dependencies: + decompress-response: ^6.0.0 + once: ^1.3.1 + simple-concat: ^1.0.0 + checksum: e4132fd27cf7af230d853fa45c1b8ce900cb430dd0a3c6d3829649fe4f2b26574c803698076c4006450efb0fad2ba8c5455fbb5755d4b0a5ec42d4f12b31d27e + languageName: node + linkType: hard + +"slash@npm:^3.0.0": + version: 3.0.0 + resolution: "slash@npm:3.0.0" + checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c + languageName: node + linkType: hard + +"slash@npm:^5.1.0": + version: 5.1.0 + resolution: "slash@npm:5.1.0" + checksum: 70434b34c50eb21b741d37d455110258c42d2cf18c01e6518aeb7299f3c6e626330c889c0c552b5ca2ef54a8f5a74213ab48895f0640717cacefeef6830a1ba4 + languageName: node + linkType: hard + +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" + dependencies: + ansi-styles: ^4.0.0 + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 + languageName: node + linkType: hard + +"smart-buffer@npm:^4.2.0": + version: 4.2.0 + resolution: "smart-buffer@npm:4.2.0" + checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + languageName: node + linkType: hard + +"socks-proxy-agent@npm:^8.0.3": + version: 8.0.5 + resolution: "socks-proxy-agent@npm:8.0.5" + dependencies: + agent-base: ^7.1.2 + debug: ^4.3.4 + socks: ^2.8.3 + checksum: b4fbcdb7ad2d6eec445926e255a1fb95c975db0020543fbac8dfa6c47aecc6b3b619b7fb9c60a3f82c9b2969912a5e7e174a056ae4d98cb5322f3524d6036e1d + languageName: node + linkType: hard + +"socks@npm:^2.8.3": + version: 2.8.7 + resolution: "socks@npm:2.8.7" + dependencies: + ip-address: ^10.0.1 + smart-buffer: ^4.2.0 + checksum: 4bbe2c88cf0eeaf49f94b7f11564a99b2571bde6fd1e714ff95b38f89e1f97858c19e0ab0e6d39eb7f6a984fa67366825895383ed563fe59962a1d57a1d55318 + languageName: node + linkType: hard + +"spdx-correct@npm:^3.0.0": + version: 3.2.0 + resolution: "spdx-correct@npm:3.2.0" + dependencies: + spdx-expression-parse: ^3.0.0 + spdx-license-ids: ^3.0.0 + checksum: e9ae98d22f69c88e7aff5b8778dc01c361ef635580e82d29e5c60a6533cc8f4d820803e67d7432581af0cc4fb49973125076ee3b90df191d153e223c004193b2 + languageName: node + linkType: hard + +"spdx-exceptions@npm:^2.1.0": + version: 2.5.0 + resolution: "spdx-exceptions@npm:2.5.0" + checksum: bb127d6e2532de65b912f7c99fc66097cdea7d64c10d3ec9b5e96524dbbd7d20e01cba818a6ddb2ae75e62bb0c63d5e277a7e555a85cbc8ab40044984fa4ae15 + languageName: node + linkType: hard + +"spdx-expression-parse@npm:^3.0.0": + version: 3.0.1 + resolution: "spdx-expression-parse@npm:3.0.1" + dependencies: + spdx-exceptions: ^2.1.0 + spdx-license-ids: ^3.0.0 + checksum: a1c6e104a2cbada7a593eaa9f430bd5e148ef5290d4c0409899855ce8b1c39652bcc88a725259491a82601159d6dc790bedefc9016c7472f7de8de7361f8ccde + languageName: node + linkType: hard + +"spdx-license-ids@npm:^3.0.0": + version: 3.0.23 + resolution: "spdx-license-ids@npm:3.0.23" + checksum: e385962db43467942250e2d5be2631bca280913f747a9216543b9410f27daf114c928884f7e5dfc512e829fb9dc05297df1297d46f2cf03626e99f8264b303bf + languageName: node + linkType: hard + +"ssri@npm:^13.0.0": + version: 13.0.1 + resolution: "ssri@npm:13.0.1" + dependencies: + minipass: ^7.0.3 + checksum: 42acbdbd485e9a5a198de2198b6fd474d1e84bff6bea5d95aa0a8aa26ea78ce44f2097ac481e767f0406de7ceccfa4669584116d4fcf2d4e2dba7034d7c34930 + languageName: node + linkType: hard + +"string-width@npm:^4.2.3": + version: 4.2.3 + resolution: "string-width@npm:4.2.3" + dependencies: + emoji-regex: ^8.0.0 + is-fullwidth-code-point: ^3.0.0 + strip-ansi: ^6.0.1 + checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + languageName: node + linkType: hard + +"string_decoder@npm:^1.1.1": + version: 1.3.0 + resolution: "string_decoder@npm:1.3.0" + dependencies: + safe-buffer: ~5.2.0 + checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 + languageName: node + linkType: hard + +"strip-ansi@npm:^6.0.1": + version: 6.0.1 + resolution: "strip-ansi@npm:6.0.1" + dependencies: + ansi-regex: ^5.0.1 + checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + languageName: node + linkType: hard + +"strip-ansi@npm:^7.1.0": + version: 7.2.0 + resolution: "strip-ansi@npm:7.2.0" + dependencies: + ansi-regex: ^6.2.2 + checksum: 96da3bc6d73cfba1218625a3d66cf7d37a69bf0920d8735b28f9eeaafcdb6c1fe8440e1ae9eb1ba0ca355dbe8702da872e105e2e939fa93e7851b3cb5dd7d316 + languageName: node + linkType: hard + +"strip-json-comments@npm:^3.1.1": + version: 3.1.1 + resolution: "strip-json-comments@npm:3.1.1" + checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 + languageName: node + linkType: hard + +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 1074ccb63270d32ca28edfb0a281c96b94dc679077828135141f27d52a5a398ef5e78bcf22809d23cadc2b81dfbe345eb5fd8699b385c8b1128907dec4a7d1e1 + languageName: node + linkType: hard + +"structured-source@npm:^4.0.0": + version: 4.0.0 + resolution: "structured-source@npm:4.0.0" + dependencies: + boundary: ^2.0.0 + checksum: 83871c9912d4f0ab27b557959132a85286f1d554eb8395a37642ca5845baf8a2e81ee376d86bdf6d20a2627efd21dc2db2056f6d631bc5a557d37e48068e8e40 + languageName: node + linkType: hard + +"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": + version: 7.2.0 + resolution: "supports-color@npm:7.2.0" + dependencies: + has-flag: ^4.0.0 + checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + languageName: node + linkType: hard + +"supports-hyperlinks@npm:^3.2.0": + version: 3.2.0 + resolution: "supports-hyperlinks@npm:3.2.0" + dependencies: + has-flag: ^4.0.0 + supports-color: ^7.0.0 + checksum: 460594ec0024f041f61105d40f1e5fc55ffcc2d94b6048faf25a616ec8fbaea71e74d909a6851c721776f24eed67c59fd3b7c47af22a487ebab85640abdb5d3f + languageName: node + linkType: hard + +"table@npm:^6.9.0": + version: 6.9.0 + resolution: "table@npm:6.9.0" + 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 + checksum: f54a7d1c11cda8c676e1e9aff5e723646905ed4579cca14b3ce12d2b12eac3e18f5dbe2549fe0b79697164858e18961145db4dd0660bbeb0fb4032af0aaf32b4 + languageName: node + linkType: hard + +"tar-fs@npm:^2.0.0": + version: 2.1.4 + resolution: "tar-fs@npm:2.1.4" + dependencies: + chownr: ^1.1.1 + mkdirp-classic: ^0.5.2 + pump: ^3.0.0 + tar-stream: ^2.1.4 + checksum: a9e18e2e6114b8ac2568d7c2b42d006b1fe30d83957e4e75ba2361a889c2fc54e54236476782d06494e081358a393feacdf19311df12b3056c8a64dc1f7ed309 + languageName: node + linkType: hard + +"tar-stream@npm:^2.1.4": + version: 2.2.0 + resolution: "tar-stream@npm:2.2.0" + 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 + checksum: 699831a8b97666ef50021c767f84924cfee21c142c2eb0e79c63254e140e6408d6d55a065a2992548e72b06de39237ef2b802b99e3ece93ca3904a37622a66f3 + languageName: node + linkType: hard + +"tar@npm:^7.5.4": + version: 7.5.9 + resolution: "tar@npm:7.5.9" + dependencies: + "@isaacs/fs-minipass": ^4.0.0 + chownr: ^3.0.0 + minipass: ^7.1.2 + minizlib: ^3.1.0 + yallist: ^5.0.0 + checksum: 26fbbdf536895814167d03e4883f80febb6520729169c54d0f29ee8a163557283862752493f0e5b60800a6f3608aac3250c41fac8e20a4f056ba4fa63f3dbad7 + languageName: node + linkType: hard + +"terminal-link@npm:^4.0.0": + version: 4.0.0 + resolution: "terminal-link@npm:4.0.0" + dependencies: + ansi-escapes: ^7.0.0 + supports-hyperlinks: ^3.2.0 + checksum: d3990757c41c2504dcca1d8bd92886e1911b7d0684da26436f2061a48d63bfa91019fa486de48e81feafcdfe9d4605f5b9669759b75d8986057af87841f09ab6 + languageName: node + linkType: hard + +"text-table@npm:^0.2.0": + version: 0.2.0 + resolution: "text-table@npm:0.2.0" + checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a + languageName: node + linkType: hard + +"textextensions@npm:^6.11.0": + version: 6.11.0 + resolution: "textextensions@npm:6.11.0" + dependencies: + editions: ^6.21.0 + checksum: 6d24c675b352264d67d36fafce2212839ea968874ed58b92c679d860a849183aa87d6f7b120fcca390416095f9af66fbe4c825e7b26796ed4ef6ea5e632c81fc + languageName: node + linkType: hard + +"tinyglobby@npm:^0.2.12": + version: 0.2.15 + resolution: "tinyglobby@npm:0.2.15" + dependencies: + fdir: ^6.5.0 + picomatch: ^4.0.3 + checksum: 0e33b8babff966c6ab86e9b825a350a6a98a63700fa0bb7ae6cf36a7770a508892383adc272f7f9d17aaf46a9d622b455e775b9949a3f951eaaf5dfb26331d44 + languageName: node + linkType: hard + +"tmp@npm:^0.2.3": + version: 0.2.5 + resolution: "tmp@npm:0.2.5" + checksum: 9d18e58060114154939930457b9e198b34f9495bcc05a343bc0a0a29aa546d2c1c2b343dae05b87b17c8fde0af93ab7d8fe8574a8f6dc2cd8fd3f2ca1ad0d8e1 + languageName: node + linkType: hard + +"to-regex-range@npm:^5.0.1": + version: 5.0.1 + resolution: "to-regex-range@npm:5.0.1" + dependencies: + is-number: ^7.0.0 + checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed + languageName: node + linkType: hard + +"ts-api-utils@npm:^1.0.1": + version: 1.4.3 + resolution: "ts-api-utils@npm:1.4.3" + peerDependencies: + typescript: ">=4.2.0" + checksum: ea00dee382d19066b2a3d8929f1089888b05fec797e32e7a7004938eda1dccf2e77274ee2afcd4166f53fab9b8d7ee90ebb225a3183f9ba8817d636f688a148d + languageName: node + linkType: hard + +"tslib@npm:^2.2.0, tslib@npm:^2.6.2": + version: 2.8.1 + resolution: "tslib@npm:2.8.1" + checksum: e4aba30e632b8c8902b47587fd13345e2827fa639e7c3121074d5ee0880723282411a8838f830b55100cbe4517672f84a2472667d355b81e8af165a55dc6203a + languageName: node + linkType: hard + +"tunnel-agent@npm:^0.6.0": + version: 0.6.0 + resolution: "tunnel-agent@npm:0.6.0" + dependencies: + safe-buffer: ^5.0.1 + checksum: 05f6510358f8afc62a057b8b692f05d70c1782b70db86d6a1e0d5e28a32389e52fa6e7707b6c5ecccacc031462e4bc35af85ecfe4bbc341767917b7cf6965711 + languageName: node + linkType: hard + +"tunnel@npm:0.0.6": + version: 0.0.6 + resolution: "tunnel@npm:0.0.6" + checksum: c362948df9ad34b649b5585e54ce2838fa583aa3037091aaed66793c65b423a264e5229f0d7e9a95513a795ac2bd4cb72cda7e89a74313f182c1e9ae0b0994fa + languageName: node + linkType: hard + +"type-check@npm:^0.4.0, type-check@npm:~0.4.0": + version: 0.4.0 + resolution: "type-check@npm:0.4.0" + dependencies: + prelude-ls: ^1.2.1 + checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a + languageName: node + linkType: hard + +"type-fest@npm:^0.20.2": + version: 0.20.2 + resolution: "type-fest@npm:0.20.2" + checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 + languageName: node + linkType: hard + +"type-fest@npm:^4.39.1, type-fest@npm:^4.6.0": + version: 4.41.0 + resolution: "type-fest@npm:4.41.0" + checksum: 7055c0e3eb188425d07403f1d5dc175ca4c4f093556f26871fe22041bc93d137d54bef5851afa320638ca1379106c594f5aa153caa654ac1a7f22c71588a4e80 + languageName: node + linkType: hard + +"typed-rest-client@npm:^1.8.4": + version: 1.8.11 + resolution: "typed-rest-client@npm:1.8.11" + dependencies: + qs: ^6.9.1 + tunnel: 0.0.6 + underscore: ^1.12.1 + checksum: baba87806381cb8e686e07dc0907bbc4a7588410f13f73f5a9fe662274d1961b84d0037bf2cb3966cb288ed6146b3350edcd896c42422f7dbc06625c347f3035 + languageName: node + linkType: hard + +"typescript@npm:^5.x": + version: 5.9.3 + resolution: "typescript@npm:5.9.3" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 0d0ffb84f2cd072c3e164c79a2e5a1a1f4f168e84cb2882ff8967b92afe1def6c2a91f6838fb58b168428f9458c57a2ba06a6737711fdd87a256bbe83e9a217f + languageName: node + linkType: hard + +"typescript@patch:typescript@^5.x#~builtin": + version: 5.9.3 + resolution: "typescript@patch:typescript@npm%3A5.9.3#~builtin::version=5.9.3&hash=f3b441" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 8bb8d86819ac86a498eada254cad7fb69c5f74778506c700c2a712daeaff21d3a6f51fd0d534fe16903cb010d1b74f89437a3d02d4d0ff5ca2ba9a4660de8497 + languageName: node + linkType: hard + +"uc.micro@npm:^2.0.0, uc.micro@npm:^2.1.0": + version: 2.1.0 + resolution: "uc.micro@npm:2.1.0" + checksum: 37197358242eb9afe367502d4638ac8c5838b78792ab218eafe48287b0ed28aaca268ec0392cc5729f6c90266744de32c06ae938549aee041fc93b0f9672d6b2 + languageName: node + linkType: hard + +"underscore@npm:^1.12.1": + version: 1.13.8 + resolution: "underscore@npm:1.13.8" + checksum: 52a165aa5e468cf64eb5117b9eb484d56c2102343eb67452ddb6edefa0ff2356afa0e41e30589d4f47005d473739fcb9cfcb6df3c0bca5c4ac19539b035a8ec2 + languageName: node + linkType: hard + +"undici-types@npm:~6.21.0": + version: 6.21.0 + resolution: "undici-types@npm:6.21.0" + checksum: 46331c7d6016bf85b3e8f20c159d62f5ae471aba1eb3dc52fff35a0259d58dcc7d592d4cc4f00c5f9243fa738a11cfa48bd20203040d4a9e6bc25e807fab7ab3 + languageName: node + linkType: hard + +"undici@npm:^7.19.0": + version: 7.22.0 + resolution: "undici@npm:7.22.0" + checksum: 3eaad0283f946ce12d4aa70da49d23870fcab9a3de5ae0b2855710b58fece570b1675913268dfa8b97589385ff4fb706c004a0614c3b193b617475e7d0a34e3a + languageName: node + linkType: hard + +"unicorn-magic@npm:^0.1.0": + version: 0.1.0 + resolution: "unicorn-magic@npm:0.1.0" + checksum: 48c5882ca3378f380318c0b4eb1d73b7e3c5b728859b060276e0a490051d4180966beeb48962d850fd0c6816543bcdfc28629dcd030bb62a286a2ae2acb5acb6 + languageName: node + linkType: hard + +"unicorn-magic@npm:^0.3.0": + version: 0.3.0 + resolution: "unicorn-magic@npm:0.3.0" + checksum: bdd7d7c522f9456f32a0b77af23f8854f9a7db846088c3868ec213f9550683ab6a2bdf3803577eacbafddb4e06900974385841ccb75338d17346ccef45f9cb01 + languageName: node + linkType: hard + +"unique-filename@npm:^5.0.0": + version: 5.0.0 + resolution: "unique-filename@npm:5.0.0" + dependencies: + unique-slug: ^6.0.0 + checksum: a5f67085caef74bdd2a6869a200ed5d68d171f5cc38435a836b5fd12cce4e4eb55e6a190298035c325053a5687ed7a3c96f0a91e82215fd14729769d9ac57d9b + languageName: node + linkType: hard + +"unique-slug@npm:^6.0.0": + version: 6.0.0 + resolution: "unique-slug@npm:6.0.0" + dependencies: + imurmurhash: ^0.1.4 + checksum: ad6cf238b10292d944521714d31bc9f3ca79fa80cb7a154aad183056493f98e85de669412c6bbfe527ffa9bdeff36d3dd4d5bccaf562c794f2580ab11932b691 + languageName: node + linkType: hard + +"universalify@npm:^2.0.0": + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: ecd8469fe0db28e7de9e5289d32bd1b6ba8f7183db34f3bfc4ca53c49891c2d6aa05f3fb3936a81285a905cc509fb641a0c3fc131ec786167eff41236ae32e60 + languageName: node + linkType: hard + +"uri-js@npm:^4.2.2": + version: 4.4.1 + resolution: "uri-js@npm:4.4.1" + dependencies: + punycode: ^2.1.0 + checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 + languageName: node + linkType: hard + +"url-join@npm:^4.0.1": + version: 4.0.1 + resolution: "url-join@npm:4.0.1" + checksum: f74e868bf25dbc8be6a8d7237d4c36bb5b6c62c72e594d5ab1347fe91d6af7ccd9eb5d621e30152e4da45c2e9a26bec21390e911ab54a62d4d82e76028374ee5 + languageName: node + linkType: hard + +"util-deprecate@npm:^1.0.1": + version: 1.0.2 + resolution: "util-deprecate@npm:1.0.2" + checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 + languageName: node + linkType: hard + +"uuid@npm:^8.3.0": + version: 8.3.2 + resolution: "uuid@npm:8.3.2" + bin: + uuid: dist/bin/uuid + checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + languageName: node + linkType: hard + +"validate-npm-package-license@npm:^3.0.4": + version: 3.0.4 + resolution: "validate-npm-package-license@npm:3.0.4" + dependencies: + spdx-correct: ^3.0.0 + spdx-expression-parse: ^3.0.0 + checksum: 35703ac889d419cf2aceef63daeadbe4e77227c39ab6287eeb6c1b36a746b364f50ba22e88591f5d017bc54685d8137bc2d328d0a896e4d3fd22093c0f32a9ad + languageName: node + linkType: hard + +"version-range@npm:^4.15.0": + version: 4.15.0 + resolution: "version-range@npm:4.15.0" + checksum: e92dfb0aeb7a504b9d064571f67bd5dcdb86173ebde9e7c08d3a426fb3bcd243af5902345751f99472f1c4b0f56a69208107775154c30f933a14816e3f1462b9 + languageName: node + linkType: hard + +"vscode-jsonrpc@npm:8.2.0": + version: 8.2.0 + resolution: "vscode-jsonrpc@npm:8.2.0" + checksum: f302a01e59272adc1ae6494581fa31c15499f9278df76366e3b97b2236c7c53ebfc71efbace9041cfd2caa7f91675b9e56f2407871a1b3c7f760a2e2ee61484a + languageName: node + linkType: hard + +"vscode-languageclient@npm:^9.0.1": + version: 9.0.1 + resolution: "vscode-languageclient@npm:9.0.1" + dependencies: + minimatch: ^5.1.0 + semver: ^7.3.7 + vscode-languageserver-protocol: 3.17.5 + checksum: ff30e5a9aac6726a88fe443fd631fe7e6130225299667c13162547f0a13ca2548d3f277d68cfb3ef6dc1810c048b2cf0e05024e1bcbd11982cd8acf681a67873 + languageName: node + linkType: hard + +"vscode-languageserver-protocol@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-protocol@npm:3.17.5" + dependencies: + vscode-jsonrpc: 8.2.0 + vscode-languageserver-types: 3.17.5 + checksum: dfb42d276df5dfea728267885b99872ecff62f6c20448b8539fae71bb196b420f5351c5aca7c1047bf8fb1f89fa94a961dce2bc5bf7e726198f4be0bb86a1e71 + languageName: node + linkType: hard + +"vscode-languageserver-types@npm:3.17.5": + version: 3.17.5 + resolution: "vscode-languageserver-types@npm:3.17.5" + checksum: 79b420e7576398d396579ca3a461c9ed70e78db4403cd28bbdf4d3ed2b66a2b4114031172e51fad49f0baa60a2180132d7cb2ea35aa3157d7af3c325528210ac + languageName: node + linkType: hard + +"whatwg-encoding@npm:^3.1.1": + version: 3.1.1 + resolution: "whatwg-encoding@npm:3.1.1" + dependencies: + iconv-lite: 0.6.3 + checksum: f75a61422421d991e4aec775645705beaf99a16a88294d68404866f65e92441698a4f5b9fa11dd609017b132d7b286c3c1534e2de5b3e800333856325b549e3c + languageName: node + linkType: hard + +"whatwg-mimetype@npm:^4.0.0": + version: 4.0.0 + resolution: "whatwg-mimetype@npm:4.0.0" + checksum: f97edd4b4ee7e46a379f3fb0e745de29fe8b839307cc774300fd49059fcdd560d38cb8fe21eae5575b8f39b022f23477cc66e40b0355c2851ce84760339cef30 + languageName: node + linkType: hard + +"which@npm:^2.0.1": + version: 2.0.2 + resolution: "which@npm:2.0.2" + dependencies: + isexe: ^2.0.0 + bin: + node-which: ./bin/node-which + checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + languageName: node + linkType: hard + +"which@npm:^6.0.0": + version: 6.0.1 + resolution: "which@npm:6.0.1" + dependencies: + isexe: ^4.0.0 + bin: + node-which: bin/which.js + checksum: dbea77c7d3058bf6c78bf9659d2dce4d2b57d39a15b826b2af6ac2e5a219b99dc8a831b79fdbc453c0598adb4f3f84cf9c2491fd52beb9f5d2dececcad117f68 + languageName: node + linkType: hard + +"word-wrap@npm:^1.2.5": + version: 1.2.5 + resolution: "word-wrap@npm:1.2.5" + checksum: f93ba3586fc181f94afdaff3a6fef27920b4b6d9eaefed0f428f8e07adea2a7f54a5f2830ce59406c8416f033f86902b91eb824072354645eea687dff3691ccb + languageName: node + linkType: hard + +"wrappy@npm:1": + version: 1.0.2 + resolution: "wrappy@npm:1.0.2" + checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + languageName: node + linkType: hard + +"wsl-utils@npm:^0.1.0": + version: 0.1.0 + resolution: "wsl-utils@npm:0.1.0" + dependencies: + is-wsl: ^3.1.0 + checksum: de4c92187e04c3c27b4478f410a02e81c351dc85efa3447bf1666f34fc80baacd890a6698ec91995631714086992036013286aea3d77e6974020d40a08e00aec + languageName: node + linkType: hard + +"xml2js@npm:^0.5.0": + version: 0.5.0 + resolution: "xml2js@npm:0.5.0" + dependencies: + sax: ">=0.6.0" + xmlbuilder: ~11.0.0 + checksum: 1aa71d62e5bc2d89138e3929b9ea46459157727759cbc62ef99484b778641c0cd21fb637696c052d901a22f82d092a3e740a16b4ce218e81ac59b933535124ea + languageName: node + linkType: hard + +"xmlbuilder@npm:~11.0.0": + version: 11.0.1 + resolution: "xmlbuilder@npm:11.0.1" + checksum: 7152695e16f1a9976658215abab27e55d08b1b97bca901d58b048d2b6e106b5af31efccbdecf9b07af37c8377d8e7e821b494af10b3a68b0ff4ae60331b415b0 + languageName: node + linkType: hard + +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + languageName: node + linkType: hard + +"yallist@npm:^5.0.0": + version: 5.0.0 + resolution: "yallist@npm:5.0.0" + checksum: eba51182400b9f35b017daa7f419f434424410691bbc5de4f4240cc830fdef906b504424992700dc047f16b4d99100a6f8b8b11175c193f38008e9c96322b6a5 + languageName: node + linkType: hard + +"yauzl@npm:^2.3.1": + version: 2.10.0 + resolution: "yauzl@npm:2.10.0" + dependencies: + buffer-crc32: ~0.2.3 + fd-slicer: ~1.1.0 + checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b + languageName: node + linkType: hard + +"yazl@npm:^2.2.2": + version: 2.5.1 + resolution: "yazl@npm:2.5.1" + dependencies: + buffer-crc32: ~0.2.3 + checksum: daec5154b5485d8621bfea359e905ddca0b2f068430a4aa0a802bf5d67391157a383e0c2767acccbf5964264851da643bc740155a9458e2d8dce55b94c1cc2ed + languageName: node + linkType: hard + +"yocto-queue@npm:^0.1.0": + version: 0.1.0 + resolution: "yocto-queue@npm:0.1.0" + checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 + languageName: node + linkType: hard From ba6387889b8ab8f5d60f880d4f41fe8609affa6a Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 3 Mar 2026 17:34:18 +0800 Subject: [PATCH 05/21] feat(neovim): add initial Neovim plugin for CODEOWNERS LSP integration --- extensions/neovim/.gitignore | 8 + extensions/neovim/examples/init.lua | 87 ++++++++++ extensions/neovim/lua/codeinput/init.lua | 158 ++++++++++++++++++ .../neovim/lua/codeinput/statusline.lua | 122 ++++++++++++++ extensions/neovim/package.json | 17 ++ extensions/neovim/test_init.lua | 19 +++ 6 files changed, 411 insertions(+) create mode 100644 extensions/neovim/.gitignore create mode 100644 extensions/neovim/examples/init.lua create mode 100644 extensions/neovim/lua/codeinput/init.lua create mode 100644 extensions/neovim/lua/codeinput/statusline.lua create mode 100644 extensions/neovim/package.json create mode 100644 extensions/neovim/test_init.lua diff --git a/extensions/neovim/.gitignore b/extensions/neovim/.gitignore new file mode 100644 index 0000000..edb86fe --- /dev/null +++ b/extensions/neovim/.gitignore @@ -0,0 +1,8 @@ +*.swp +*.swo +*~ +.*.sw[a-z] +.un~ + + +neovim diff --git a/extensions/neovim/examples/init.lua b/extensions/neovim/examples/init.lua new file mode 100644 index 0000000..abc12e8 --- /dev/null +++ b/extensions/neovim/examples/init.lua @@ -0,0 +1,87 @@ +# Example Neovim Configuration + +This directory contains example configurations for using CodeInput with Neovim. + +## Minimal Setup + +```lua +-- init.lua +require("codeinput").setup() +``` + +## With Status Line + +Using the built-in status line: + +```lua +-- init.lua +require("codeinput").setup() + +-- Add to status line +vim.o.statusline = "%<%f %h%m%r%=%{v:lua.require('codeinput.statusline').get_status()} %-14.(%l,%c%V%) %P" +``` + +## With lualine.nvim + +```lua +-- init.lua with lualine +require("codeinput").setup() + +require('lualine').setup { + sections = { + lualine_c = { + 'filename', + { + function() + return require('codeinput.statusline').get_status() + end, + cond = function() + local status = require('codeinput.statusline').get_status() + return status ~= "" and status ~= nil + end, + color = { gui = "bold" }, + } + } + } +} +``` + +## Advanced Configuration + +```lua +-- init.lua with custom settings +require("codeinput").setup({ + binary_path = "/usr/local/bin/ci-lsp", -- Custom binary path + cache_file = ".codeowners.cache", -- Cache file name + show_diagnostics = true, -- Show diagnostics + show_in_statusline = true, -- Enable status line +}) + +-- Key mappings +vim.api.nvim_set_keymap('n', 'ci', ':CodeInputInfo', { noremap = true, silent = true }) +vim.api.nvim_set_keymap('n', 'cr', ':CodeInputRefresh', { noremap = true, silent = true }) +``` + +## With nvim-tree + +Show ownership info in file tree (requires nvim-tree): + +```lua +-- This is a more advanced example +local codeinput = require("codeinput") + +require("nvim-tree").setup { + view = { + float = { + enable = true, + } + }, + renderer = { + icons = { + show = { + git = true, + } + } + } +} +``` diff --git a/extensions/neovim/lua/codeinput/init.lua b/extensions/neovim/lua/codeinput/init.lua new file mode 100644 index 0000000..3165df3 --- /dev/null +++ b/extensions/neovim/lua/codeinput/init.lua @@ -0,0 +1,158 @@ +local M = {} + +local config = { + binary_path = "ci", + cache_file = ".codeowners.cache", + show_diagnostics = true, + show_in_statusline = true, +} + +local client_id = nil + +local function get_root_dir() + local fname = vim.api.nvim_buf_get_name(0) + if fname == "" then + return nil + end + + local root = vim.fs.dirname(vim.fs.find({ "CODEOWNERS", ".git" }, { upward = true, path = fname })[1]) + return root +end + +local function start_lsp() + if client_id then + return + end + + local root_dir = get_root_dir() + if not root_dir then + return + end + + client_id = vim.lsp.start_client({ + name = "codeinput", + cmd = { config.binary_path, "lsp" }, + root_dir = root_dir, + on_exit = function(code, signal, client_id) + client_id = nil + if code ~= 0 then + vim.notify("CodeInput LSP exited with code " .. code, vim.log.levels.ERROR) + end + end, + on_error = function(code, err) + vim.notify("CodeInput LSP error: " .. err, vim.log.levels.ERROR) + end, + }) +end + +local function attach_to_buffer(bufnr) + bufnr = bufnr or vim.api.nvim_get_current_buf() + + if not client_id then + start_lsp() + end + + if client_id then + vim.lsp.buf_attach_client(bufnr, client_id) + end +end + +function M.setup(opts) + config = vim.tbl_deep_extend("force", config, opts or {}) + + local lsp_group = vim.api.nvim_create_augroup("CodeInputLSP", { clear = true }) + + vim.api.nvim_create_autocmd("FileType", { + group = lsp_group, + pattern = "*", + callback = function() + local root = get_root_dir() + if root then + attach_to_buffer() + end + end, + }) + + vim.api.nvim_create_user_command("CodeInputInfo", function() + M.show_info() + end, { desc = "Show CODEOWNERS info for current file" }) + + vim.api.nvim_create_user_command("CodeInputRefresh", function() + M.refresh_cache() + end, { desc = "Refresh CODEOWNERS cache" }) + + vim.api.nvim_create_autocmd("BufWritePost", { + group = lsp_group, + pattern = "CODEOWNERS", + callback = function() + vim.notify("CODEOWNERS file changed, refreshing cache...", vim.log.levels.INFO) + end, + }) +end + +function M.show_info() + local params = vim.lsp.util.make_position_params(0, "utf-16") + + vim.lsp.buf_request(0, "textDocument/hover", params, function(err, result, ctx) + if err then + vim.api.nvim_echo({{"Error: " .. err.message, "ErrorMsg"}}, true, {}) + return + end + + if not result or not result.contents then + vim.api.nvim_echo({{"No CODEOWNERS info for this file", "Normal"}}, true, {}) + return + end + + local lines = {} + if type(result.contents) == "table" then + if result.contents.kind == "markdown" then + for line in result.contents.value:gmatch("[^\r\n]+") do + table.insert(lines, line) + end + else + for _, item in ipairs(result.contents) do + if type(item) == "string" then + table.insert(lines, item) + elseif item.value then + table.insert(lines, item.value) + end + end + end + elseif type(result.contents) == "string" then + table.insert(lines, result.contents) + end + + -- Clean up markdown formatting + local clean_lines = {} + for _, line in ipairs(lines) do + line = line:gsub("%*%*", "") -- Remove bold + line = line:gsub("`", "") -- Remove code blocks + if line:match("%S") then -- Only non-empty lines + table.insert(clean_lines, line) + end + end + + vim.api.nvim_echo({{table.concat(clean_lines, " | "), "Normal"}}, true, {}) + end) +end + +function M.refresh_cache() + vim.notify("Refreshing CODEOWNERS cache...", vim.log.levels.INFO) + + local clients = vim.lsp.get_clients({ name = "codeinput" }) + if #clients > 0 then + vim.notify("Cache will be refreshed automatically when CODEOWNERS files change", vim.log.levels.INFO) + else + vim.notify("CodeInput LSP not running", vim.log.levels.WARN) + end +end + +function M.get_client() + if client_id then + return vim.lsp.get_client_by_id(client_id) + end + return nil +end + +return M diff --git a/extensions/neovim/lua/codeinput/statusline.lua b/extensions/neovim/lua/codeinput/statusline.lua new file mode 100644 index 0000000..ac2ef22 --- /dev/null +++ b/extensions/neovim/lua/codeinput/statusline.lua @@ -0,0 +1,122 @@ +local M = {} + +local function get_initials(identifier) + if identifier:sub(1, 1) == "@" then + local parts = {} + for part in identifier:gmatch("[^/]+") do + table.insert(parts, part) + end + + if #parts > 1 then + return parts[#parts]:sub(1, 1):upper() + else + return identifier:sub(2, 2):upper() + end + end + + if identifier:find("@") then + return identifier:sub(1, 1):upper() + end + + return identifier:sub(1, 1):upper() +end + +local function get_cached_ownership() + local bufnr = vim.api.nvim_get_current_buf() + local cached = vim.b[bufnr].codeinput_ownership + if cached and cached.timestamp and (os.time() - cached.timestamp) < 5 then + return cached.data + end + return nil +end + +local function set_cached_ownership(data) + local bufnr = vim.api.nvim_get_current_buf() + vim.b[bufnr].codeinput_ownership = { + data = data, + timestamp = os.time() + } +end + +function M.get_status() + local clients = vim.lsp.get_active_clients({ name = "codeinput" }) + if #clients == 0 then + return "" + end + + local cached = get_cached_ownership() + if cached then + return cached.status or "" + end + + local params = vim.lsp.util.make_position_params(0, "utf-16") + + vim.lsp.buf_request(0, "textDocument/hover", params, function(err, result, ctx) + if err or not result or not result.contents then + set_cached_ownership({ status = "" }) + return + end + + local status = "" + local is_unowned = false + local owners = {} + local tags = {} + + local contents = result.contents + if type(contents) == "table" then + if contents.kind == "markdown" then + contents = { contents } + end + + for _, item in ipairs(contents) do + local text = "" + if type(item) == "string" then + text = item + elseif item.value then + text = item.value + end + + if text:match("Owners:%s*%(none%)") then + is_unowned = true + elseif text:match("Owners:") then + local owner_str = text:match("%*%*Owners:%*%*%s*(.+)") + if owner_str and owner_str ~= "(none)" then + for owner in owner_str:gmatch("`([^`]+)`") do + table.insert(owners, owner) + end + end + end + + if text:match("Tags:") then + local tag_str = text:match("%*%*Tags:%*%*%s*(.+)") + if tag_str then + for tag in tag_str:gmatch("`#([^`]+)`") do + table.insert(tags, tag) + end + end + end + + if text:match("Warning") then + is_unowned = true + end + end + end + + if is_unowned or #owners == 0 then + status = "" + else + local initials = "" + for _, owner in ipairs(owners) do + initials = initials .. get_initials(owner) + end + status = " " .. initials + end + + set_cached_ownership({ status = status }) + end) + + local cached_now = get_cached_ownership() + return cached_now and cached_now.status or "" +end + +return M diff --git a/extensions/neovim/package.json b/extensions/neovim/package.json new file mode 100644 index 0000000..196d5b3 --- /dev/null +++ b/extensions/neovim/package.json @@ -0,0 +1,17 @@ +{ + "name": "codeinput-neovim", + "version": "0.1.0", + "description": "Minimal CODEOWNERS integration for Neovim", + "repository": { + "type": "git", + "url": "https://github.com/CodeInputCorp/cli.git", + "directory": "extensions/neovim" + }, + "keywords": [ + "neovim", + "codeowners", + "lsp" + ], + "author": "CodeInput", + "license": "MIT" +} diff --git a/extensions/neovim/test_init.lua b/extensions/neovim/test_init.lua new file mode 100644 index 0000000..830bb0a --- /dev/null +++ b/extensions/neovim/test_init.lua @@ -0,0 +1,19 @@ +-- Minimal test configuration for CodeInput Neovim plugin +-- Run with: nvim -u test_init.lua + +vim.opt.runtimepath:append(".") +vim.opt.runtimepath:append("../lua") + +require("codeinput").setup() + +vim.o.statusline = "%<%f %h%m%r%=%{v:lua.require('codeinput.statusline').get_status()} %-14.(%l,%c%V%) %P" + +vim.api.nvim_set_keymap('n', 'ci', ':CodeInputInfo', { noremap = true, silent = true }) +vim.api.nvim_set_keymap('n', 'cr', ':CodeInputRefresh', { noremap = true, silent = true }) + +print("CodeInput Neovim plugin loaded!") +print("Commands available:") +print(" :CodeInputInfo - Show ownership info") +print(" :CodeInputRefresh - Refresh cache") +print(" ci - Show info (keymap)") +print(" cr - Refresh cache (keymap)") From a28f8a2415f9f042eb21f728873b76894e3f13a9 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 3 Mar 2026 19:15:47 +0800 Subject: [PATCH 06/21] feat(lsp): add custom commands for listing files, owners, and tags Expose ownership data via executeCommand interface with codeinput.listFiles, codeinput.listOwners, and codeinput.listTags methods. --- codeinput/src/lsp/server.rs | 198 ++++++++++++++++++++++++++++++++---- 1 file changed, 178 insertions(+), 20 deletions(-) diff --git a/codeinput/src/lsp/server.rs b/codeinput/src/lsp/server.rs index dc4e37a..205eb5d 100644 --- a/codeinput/src/lsp/server.rs +++ b/codeinput/src/lsp/server.rs @@ -4,11 +4,17 @@ //! - textDocument/hover: Show owners/tags when hovering over file paths //! - textDocument/codeLens: Display ownership information above files //! - textDocument/publishDiagnostics: Warn about unowned files +//! - Custom methods: +//! - codeinput/listFiles: List all files with ownership info +//! - codeinput/listOwners: List all owners with their files +//! - codeinput/listTags: List all tags with their files use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; +use serde::{Deserialize, Serialize}; +use serde_json::Value; use tokio::sync::RwLock; use tower_lsp::jsonrpc::Result as LspResult; use tower_lsp::lsp_types::*; @@ -34,7 +40,7 @@ struct WorkspaceState { } /// Information about a file's ownership -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct FileOwnershipInfo { pub path: PathBuf, pub owners: Vec, @@ -42,6 +48,33 @@ pub struct FileOwnershipInfo { pub is_unowned: bool, } +#[derive(Debug, Serialize, Deserialize)] +pub struct ListFilesResponse { + pub files: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct OwnerInfo { + pub owner: Owner, + pub files: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ListOwnersResponse { + pub owners: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TagInfo { + pub tag: Tag, + pub files: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ListTagsResponse { + pub tags: Vec, +} + impl LspServer { /// Create a new LSP server instance pub fn new(client: Client) -> Self { @@ -52,20 +85,13 @@ impl LspServer { } /// Initialize a workspace by loading its CODEOWNERS cache - async fn initialize_workspace( - &self, - root_uri: Url, - cache_file: Option, - ) -> Result<()> { + async fn initialize_workspace(&self, root_uri: Url, cache_file: Option) -> Result<()> { let root_path = uri_to_path(&root_uri)?; // Load or create the cache let cache = sync_cache(&root_path, cache_file.as_deref())?; - let state = WorkspaceState { - cache, - cache_file, - }; + let state = WorkspaceState { cache, cache_file }; let mut workspaces = self.workspaces.write().await; workspaces.insert(root_uri, state); @@ -87,20 +113,16 @@ impl LspServer { // Cache stores relative paths like "./main.go" let cache_path = PathBuf::from(".").join(relative_path); - if let Some(file_entry) = state - .cache - .files - .iter() - .find(|f| f.path == cache_path) - { + if let Some(file_entry) = state.cache.files.iter().find(|f| f.path == cache_path) { return Some(FileOwnershipInfo { path: relative_path.to_path_buf(), owners: file_entry.owners.clone(), tags: file_entry.tags.clone(), is_unowned: file_entry.owners.is_empty() - || file_entry.owners.iter().any(|o| { - matches!(o.owner_type, OwnerType::Unowned) - }), + || file_entry + .owners + .iter() + .any(|o| matches!(o.owner_type, OwnerType::Unowned)), }); } } @@ -210,6 +232,16 @@ impl LanguageServer for LspServer { code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(false), }), + execute_command_provider: Some(ExecuteCommandOptions { + commands: vec![ + "codeinput.listFiles".to_string(), + "codeinput.listOwners".to_string(), + "codeinput.listTags".to_string(), + ], + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + }), workspace: Some(WorkspaceServerCapabilities { workspace_folders: Some(WorkspaceFoldersServerCapabilities { supported: Some(true), @@ -460,6 +492,130 @@ impl LanguageServer for LspServer { } } } + + async fn execute_command(&self, params: ExecuteCommandParams) -> LspResult> { + fn to_value(v: T) -> LspResult { + serde_json::to_value(v) + .map_err(|e| tower_lsp::jsonrpc::Error::invalid_params(e.to_string())) + } + + match params.command.as_str() { + "codeinput.listFiles" => { + let result = self.list_files(None).await?; + to_value(result).map(Some) + } + "codeinput.listOwners" => { + let result = self.list_owners(None).await?; + to_value(result).map(Some) + } + "codeinput.listTags" => { + let result = self.list_tags(None).await?; + to_value(result).map(Some) + } + _ => Err(tower_lsp::jsonrpc::Error::method_not_found()), + } + } +} + +impl LspServer { + pub async fn list_files(&self, workspace_uri: Option) -> LspResult { + let workspaces = self.workspaces.read().await; + + let files = if let Some(uri) = workspace_uri { + if let Some(state) = workspaces.get(&uri) { + Self::collect_files_from_cache(&state.cache) + } else { + Vec::new() + } + } else { + let mut all_files = Vec::new(); + for state in workspaces.values() { + all_files.extend(Self::collect_files_from_cache(&state.cache)); + } + all_files + }; + + Ok(ListFilesResponse { files }) + } + + pub async fn list_owners(&self, workspace_uri: Option) -> LspResult { + let workspaces = self.workspaces.read().await; + + let owners = if let Some(uri) = workspace_uri { + if let Some(state) = workspaces.get(&uri) { + Self::collect_owners_from_cache(&state.cache) + } else { + Vec::new() + } + } else { + let mut all_owners = Vec::new(); + for state in workspaces.values() { + all_owners.extend(Self::collect_owners_from_cache(&state.cache)); + } + all_owners + }; + + Ok(ListOwnersResponse { owners }) + } + + pub async fn list_tags(&self, workspace_uri: Option) -> LspResult { + let workspaces = self.workspaces.read().await; + + let tags = if let Some(uri) = workspace_uri { + if let Some(state) = workspaces.get(&uri) { + Self::collect_tags_from_cache(&state.cache) + } else { + Vec::new() + } + } else { + let mut all_tags = Vec::new(); + for state in workspaces.values() { + all_tags.extend(Self::collect_tags_from_cache(&state.cache)); + } + all_tags + }; + + Ok(ListTagsResponse { tags }) + } + + fn collect_files_from_cache(cache: &CodeownersCache) -> Vec { + cache + .files + .iter() + .map(|entry| FileOwnershipInfo { + path: entry.path.clone(), + owners: entry.owners.clone(), + tags: entry.tags.clone(), + is_unowned: entry.owners.is_empty() + || entry + .owners + .iter() + .any(|o| matches!(o.owner_type, OwnerType::Unowned)), + }) + .collect() + } + + fn collect_owners_from_cache(cache: &CodeownersCache) -> Vec { + cache + .owners_map + .iter() + .map(|(owner, files)| OwnerInfo { + owner: owner.clone(), + files: files.clone(), + }) + .collect() + } + + fn collect_tags_from_cache(cache: &CodeownersCache) -> Vec { + cache + .tags_map + .iter() + .map(|(tag, files)| TagInfo { + tag: tag.clone(), + files: files.clone(), + }) + .collect() + } } /// Convert a URL to a file path @@ -481,7 +637,9 @@ pub async fn run_lsp_server() -> Result<()> { let (service, socket) = tower_lsp::LspService::new(|client| LspServer::new(client)); - tower_lsp::Server::new(stdin, stdout, socket).serve(service).await; + tower_lsp::Server::new(stdin, stdout, socket) + .serve(service) + .await; Ok(()) } From 5ac233d17074b3d965a3ace76f5c41f52dc6066f Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 3 Mar 2026 19:38:42 +0800 Subject: [PATCH 07/21] feat(neovim): add telescope integration for browsing files by ownership Add telescope.nvim integration with three new commands: CodeInputFiles, CodeInputOwners, and CodeInputTags. Also improve error handling and update deprecated LSP API calls. --- extensions/neovim/lua/codeinput/init.lua | 22 +- .../neovim/lua/codeinput/statusline.lua | 84 ++++- extensions/neovim/lua/codeinput/telescope.lua | 304 ++++++++++++++++++ 3 files changed, 407 insertions(+), 3 deletions(-) create mode 100644 extensions/neovim/lua/codeinput/telescope.lua diff --git a/extensions/neovim/lua/codeinput/init.lua b/extensions/neovim/lua/codeinput/init.lua index 3165df3..009af17 100644 --- a/extensions/neovim/lua/codeinput/init.lua +++ b/extensions/neovim/lua/codeinput/init.lua @@ -81,6 +81,18 @@ function M.setup(opts) M.refresh_cache() end, { desc = "Refresh CODEOWNERS cache" }) + vim.api.nvim_create_user_command("CodeInputFiles", function() + require("codeinput.telescope").files() + end, { desc = "Browse all files with ownership" }) + + vim.api.nvim_create_user_command("CodeInputOwners", function() + require("codeinput.telescope").owners() + end, { desc = "Browse files by owner" }) + + vim.api.nvim_create_user_command("CodeInputTags", function() + require("codeinput.telescope").tags() + end, { desc = "Browse files by tag" }) + vim.api.nvim_create_autocmd("BufWritePost", { group = lsp_group, pattern = "CODEOWNERS", @@ -91,9 +103,15 @@ function M.setup(opts) end function M.show_info() + local client = M.get_client() + if not client then + vim.api.nvim_echo({{"CodeInput LSP not running", "ErrorMsg"}}, true, {}) + return + end + local params = vim.lsp.util.make_position_params(0, "utf-16") - vim.lsp.buf_request(0, "textDocument/hover", params, function(err, result, ctx) + client.request("textDocument/hover", params, function(err, result, ctx) if err then vim.api.nvim_echo({{"Error: " .. err.message, "ErrorMsg"}}, true, {}) return @@ -134,7 +152,7 @@ function M.show_info() end vim.api.nvim_echo({{table.concat(clean_lines, " | "), "Normal"}}, true, {}) - end) + end, 0) end function M.refresh_cache() diff --git a/extensions/neovim/lua/codeinput/statusline.lua b/extensions/neovim/lua/codeinput/statusline.lua index ac2ef22..b2c7b53 100644 --- a/extensions/neovim/lua/codeinput/statusline.lua +++ b/extensions/neovim/lua/codeinput/statusline.lua @@ -39,7 +39,7 @@ local function set_cached_ownership(data) end function M.get_status() - local clients = vim.lsp.get_active_clients({ name = "codeinput" }) + local clients = vim.lsp.get_clients({ name = "codeinput" }) if #clients == 0 then return "" end @@ -119,4 +119,86 @@ function M.get_status() return cached_now and cached_now.status or "" end +function M.get_lualine_component() + local clients = vim.lsp.get_clients({ name = "codeinput" }) + if #clients == 0 then + return "" + end + + local cached = get_cached_ownership() + if cached and cached.lualine then + return cached.lualine + end + + local params = vim.lsp.util.make_position_params(0, "utf-16") + + vim.lsp.buf_request(0, "textDocument/hover", params, function(err, result, ctx) + if err or not result or not result.contents then + set_cached_ownership({ lualine = "" }) + return + end + + local is_unowned = false + local owners = {} + local tags = {} + + local contents = result.contents + if type(contents) == "table" then + if contents.kind == "markdown" then + contents = { contents } + end + + for _, item in ipairs(contents) do + local text = "" + if type(item) == "string" then + text = item + elseif item.value then + text = item.value + end + + if text:match("Owners:%s*%(none%)") then + is_unowned = true + elseif text:match("Owners:") then + local owner_str = text:match("%*%*Owners:%*%*%s*(.+)") + if owner_str and owner_str ~= "(none)" then + for owner in owner_str:gmatch("`([^`]+)`") do + table.insert(owners, owner) + end + end + end + + if text:match("Tags:") then + local tag_str = text:match("%*%*Tags:%*%*%s*(.+)") + if tag_str then + for tag in tag_str:gmatch("`#([^`]+)`") do + table.insert(tags, tag) + end + end + end + + if text:match("Warning") then + is_unowned = true + end + end + end + + local lualine_str = "" + if is_unowned then + lualine_str = "⚠️ unowned" + elseif #owners > 0 then + local owner_list = table.concat(owners, " ") + lualine_str = "👥 " .. owner_list + if #tags > 0 then + local tag_list = table.concat(tags, " ") + lualine_str = lualine_str .. " 🏷️ " .. tag_list + end + end + + set_cached_ownership({ lualine = lualine_str }) + end) + + local cached_now = get_cached_ownership() + return cached_now and cached_now.lualine or "" +end + return M diff --git a/extensions/neovim/lua/codeinput/telescope.lua b/extensions/neovim/lua/codeinput/telescope.lua new file mode 100644 index 0000000..117e0c4 --- /dev/null +++ b/extensions/neovim/lua/codeinput/telescope.lua @@ -0,0 +1,304 @@ +local M = {} +local pickers = require("telescope.pickers") +local finders = require("telescope.finders") +local conf = require("telescope.config").values +local actions = require("telescope.actions") +local action_state = require("telescope.actions.state") +local previewers = require("telescope.previewers") + +local function path_to_string(path) + if type(path) == "table" then + return path[1] or "" + else + return tostring(path) + end +end + +local function make_ownership_previewer(ownership_map) + return previewers.new_buffer_previewer { + title = "Ownership Details", + define_preview = function(self, entry) + local lines = {} + local path = entry[1] + local owners_data = ownership_map and ownership_map[path] + + if owners_data then + table.insert(lines, "File: " .. path) + table.insert(lines, "") + + if owners_data.owners and #owners_data.owners > 0 then + table.insert(lines, "Owners:") + for _, owner in ipairs(owners_data.owners) do + table.insert(lines, " • " .. owner.identifier .. " (" .. owner.owner_type .. ")") + end + else + table.insert(lines, "Owners: (none)") + end + + table.insert(lines, "") + + if owners_data.tags and #owners_data.tags > 0 then + table.insert(lines, "Tags:") + for _, tag in ipairs(owners_data.tags) do + local tag_name = type(tag) == "table" and tag[1] or tostring(tag) + table.insert(lines, " • #" .. tag_name) + end + end + + if owners_data.is_unowned then + table.insert(lines, "") + table.insert(lines, "⚠️ This file has no CODEOWNERS assignment") + end + else + table.insert(lines, "No ownership data available") + end + + vim.api.nvim_buf_set_lines(self.state.bufnr, 0, -1, false, lines) + vim.api.nvim_buf_set_option(self.state.bufnr, "filetype", "markdown") + vim.api.nvim_buf_set_option(self.state.bufnr, "modifiable", false) + end, + } +end + +function M.files(opts) + opts = opts or {} + + local client = require("codeinput").get_client() + if not client then + vim.notify("CodeInput LSP not running", vim.log.levels.WARN) + return + end + + client.request("workspace/executeCommand", { + command = "codeinput.listFiles", + arguments = {}, + }, function(err, result) + if err then + vim.notify("Error listing files: " .. err.message, vim.log.levels.ERROR) + return + end + + if not result or not result.files then + vim.notify("No files found", vim.log.levels.INFO) + return + end + + show_files_picker(result.files, opts) + end) +end + +function M.owners(opts) + opts = opts or {} + + local client = require("codeinput").get_client() + if not client then + vim.notify("CodeInput LSP not running", vim.log.levels.WARN) + return + end + + client.request("workspace/executeCommand", { + command = "codeinput.listOwners", + arguments = {}, + }, function(err, result) + if err then + vim.notify("Error listing owners: " .. err.message, vim.log.levels.ERROR) + return + end + + if not result or not result.owners then + vim.notify("No owners found", vim.log.levels.INFO) + return + end + + show_owners_picker(result.owners, opts) + end) +end + +function M.tags(opts) + opts = opts or {} + + local client = require("codeinput").get_client() + if not client then + vim.notify("CodeInput LSP not running", vim.log.levels.WARN) + return + end + + client.request("workspace/executeCommand", { + command = "codeinput.listTags", + arguments = {}, + }, function(err, result) + if err then + vim.notify("Error listing tags: " .. vim.inspect(err), vim.log.levels.ERROR) + return + end + + if not result or not result.tags or #result.tags == 0 then + vim.notify("No tags found", vim.log.levels.INFO) + return + end + + show_tags_picker(result.tags, opts) + end) +end + +function show_files_picker(files, opts) + opts = opts or {} + + -- Convert to simple list of file paths + local file_paths = {} + local ownership_map = {} + + for _, entry in ipairs(files) do + local path_str = path_to_string(entry.path) + table.insert(file_paths, path_str) + ownership_map[path_str] = entry + end + + -- Use telescope's built-in file finder + local find_files = require("telescope.builtin").find_files + + -- Override attach_mappings to add custom previewer + local original_attach_mappings = opts.attach_mappings + opts.attach_mappings = function(prompt_bufnr, map) + if original_attach_mappings then + original_attach_mappings(prompt_bufnr, map) + end + + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + actions.close(prompt_bufnr) + vim.cmd("edit " .. vim.fn.fnameescape(selection[1])) + end) + + return true + end + + -- Use find_files but with our file list + pickers.new(opts, { + prompt_title = "Files with Ownership", + finder = finders.new_table { + results = file_paths, + entry_maker = require("telescope.make_entry").gen_from_file(opts), + }, + sorter = conf.file_sorter(opts), + previewer = make_ownership_previewer(ownership_map), + }):find() +end + +function show_owners_picker(owners, opts) + pickers.new(opts, { + prompt_title = "Browse by Owner", + finder = finders.new_table { + results = owners, + entry_maker = function(entry) + local display = string.format("%s (%d files)", entry.owner.identifier, #entry.files) + return { + value = entry, + display = display, + ordinal = entry.owner.identifier, + } + end, + }, + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + actions.close(prompt_bufnr) + show_files_for_owner(selection.value.files, selection.value.owner.identifier, opts) + end) + return true + end, + }):find() +end + +function show_tags_picker(tags, opts) + if not tags or #tags == 0 then + vim.notify("No tags found", vim.log.levels.INFO) + return + end + + pickers.new(opts, { + prompt_title = "Browse by Tag", + finder = finders.new_table { + results = tags, + entry_maker = function(entry) + local tag_name = type(entry.tag) == "table" and entry.tag[1] or tostring(entry.tag) + local file_count = entry.files and #entry.files or 0 + local display = string.format("#%s (%d files)", tag_name, file_count) + + return { + value = entry, + display = display, + ordinal = tag_name, + } + end, + }, + sorter = conf.generic_sorter(opts), + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + actions.close(prompt_bufnr) + local tag_name = type(selection.value.tag) == "table" and selection.value.tag[1] or tostring(selection.value.tag) + show_files_for_tag(selection.value.files, tag_name, opts) + end) + return true + end, + }):find() +end + +function show_files_for_owner(files, owner, opts) + local file_strings = vim.tbl_map(function(f) + if type(f) == "table" then + return f[1] or vim.inspect(f) + else + return tostring(f) + end + end, files) + + pickers.new(opts, { + prompt_title = string.format("Files owned by %s", owner), + finder = finders.new_table { + results = file_strings, + }, + sorter = conf.file_sorter(opts), + previewer = conf.file_previewer(opts), + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + actions.close(prompt_bufnr) + vim.cmd("edit " .. vim.fn.fnameescape(selection[1])) + end) + return true + end, + }):find() +end + +function show_files_for_tag(files, tag, opts) + local file_strings = vim.tbl_map(function(f) + if type(f) == "table" then + return f[1] or vim.inspect(f) + else + return tostring(f) + end + end, files) + + pickers.new(opts, { + prompt_title = string.format("Files tagged #%s", tag), + finder = finders.new_table { + results = file_strings, + }, + sorter = conf.file_sorter(opts), + previewer = conf.file_previewer(opts), + attach_mappings = function(prompt_bufnr, map) + actions.select_default:replace(function() + local selection = action_state.get_selected_entry() + actions.close(prompt_bufnr) + vim.cmd("edit " .. vim.fn.fnameescape(selection[1])) + end) + return true + end, + }):find() +end + +return M + From 4008d480c23b00168108a16f63d56bd69e3f8907 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Wed, 4 Mar 2026 13:08:01 +0800 Subject: [PATCH 08/21] refactor(neovim): improve telescope file pickers with proper entry_maker --- extensions/neovim/lua/codeinput/telescope.lua | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/extensions/neovim/lua/codeinput/telescope.lua b/extensions/neovim/lua/codeinput/telescope.lua index 117e0c4..c0e9ee0 100644 --- a/extensions/neovim/lua/codeinput/telescope.lua +++ b/extensions/neovim/lua/codeinput/telescope.lua @@ -247,18 +247,17 @@ function show_tags_picker(tags, opts) end function show_files_for_owner(files, owner, opts) + opts = opts or {} + local file_strings = vim.tbl_map(function(f) - if type(f) == "table" then - return f[1] or vim.inspect(f) - else - return tostring(f) - end + return path_to_string(f) end, files) pickers.new(opts, { prompt_title = string.format("Files owned by %s", owner), finder = finders.new_table { results = file_strings, + entry_maker = require("telescope.make_entry").gen_from_file(opts), }, sorter = conf.file_sorter(opts), previewer = conf.file_previewer(opts), @@ -274,18 +273,17 @@ function show_files_for_owner(files, owner, opts) end function show_files_for_tag(files, tag, opts) + opts = opts or {} + local file_strings = vim.tbl_map(function(f) - if type(f) == "table" then - return f[1] or vim.inspect(f) - else - return tostring(f) - end + return path_to_string(f) end, files) pickers.new(opts, { prompt_title = string.format("Files tagged #%s", tag), finder = finders.new_table { results = file_strings, + entry_maker = require("telescope.make_entry").gen_from_file(opts), }, sorter = conf.file_sorter(opts), previewer = conf.file_previewer(opts), From d00f1598efe8094477ff7b99e80d1dcc8ccdd40c Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Wed, 4 Mar 2026 13:28:18 +0800 Subject: [PATCH 09/21] feat(vim): add Vim plugin for CODEOWNERS LSP integration --- extensions/vim/autoload/codeinput.vim | 191 ++++++++++++++++++++++++++ extensions/vim/plugin/codeinput.vim | 20 +++ 2 files changed, 211 insertions(+) create mode 100644 extensions/vim/autoload/codeinput.vim create mode 100644 extensions/vim/plugin/codeinput.vim diff --git a/extensions/vim/autoload/codeinput.vim b/extensions/vim/autoload/codeinput.vim new file mode 100644 index 0000000..34d8ae5 --- /dev/null +++ b/extensions/vim/autoload/codeinput.vim @@ -0,0 +1,191 @@ +let s:job = v:null +let s:channel = v:null +let s:request_id = 0 +let s:pending_requests = {} +let s:initialized = v:false +let s:root_uri = '' + +function! codeinput#init() abort + let s:root_uri = 'file://' . getcwd() + let binary = get(g:, 'codeinput_binary', 'ci') + + if !executable(binary) + echoerr 'CodeInput: binary not found: ' . binary + return + endif + + let cmd = [binary, 'lsp'] + let s:job = job_start(cmd, { + \ 'out_cb': function('s:handle_message'), + \ 'err_cb': function('s:handle_error'), + \ 'out_mode': 'raw', + \ 'noblock': 1, + \ }) + + if job_status(s:job) !=# 'run' + echoerr 'CodeInput: failed to start LSP server' + let s:job = v:null + return + endif + + let s:channel = job_getchannel(s:job) + call s:send_request('initialize', { + \ 'processId': getpid(), + \ 'rootUri': s:root_uri, + \ 'capabilities': {}, + \ }) +endfunction + +function! codeinput#stop() abort + if s:job isnot v:null + call job_stop(s:job) + let s:job = v:null + let s:channel = v:null + let s:initialized = v:false + endif +endfunction + +function! codeinput#show_info() abort + if !s:initialized + echo 'CodeInput: not initialized' + return + endif + + let uri = 'file://' . expand('%:p') + call s:send_request('textDocument/hover', { + \ 'textDocument': {'uri': uri}, + \ 'position': {'line': line('.') - 1, 'character': col('.') - 1}, + \ }, function('s:show_hover')) +endfunction + +function! codeinput#refresh() abort + if !s:initialized + echo 'CodeInput: not initialized' + return + endif + + call s:send_notification('workspace/executeCommand', { + \ 'command': 'codeinput.refresh', + \ }) + echo 'CodeInput: cache refreshed' +endfunction + +function! s:send_request(method, params, ...) abort + let s:request_id += 1 + let request = { + \ 'jsonrpc': '2.0', + \ 'id': s:request_id, + \ 'method': a:method, + \ 'params': a:params, + \ } + + if a:0 > 0 + let s:pending_requests[s:request_id] = a:1 + endif + + call s:send_json(request) +endfunction + +function! s:send_notification(method, params) abort + let notification = { + \ 'jsonrpc': '2.0', + \ 'method': a:method, + \ 'params': a:params, + \ } + call s:send_json(notification) +endfunction + +function! s:send_json(data) abort + if s:channel is v:null + return + endif + + let json = json_encode(a:data) + let message = "Content-Length: " . strlen(json) . "\r\n\r\n" . json + call ch_sendraw(s:channel, message) +endfunction + +let s:buffer = '' + +function! s:handle_message(channel, data) abort + let s:buffer .= a:data + + while v:true + let header_end = stridx(s:buffer, "\r\n\r\n") + if header_end == -1 + break + endif + + let header = s:buffer[:header_end - 1] + let content_length = s:parse_content_length(header) + if content_length == -1 + let s:buffer = s:buffer[header_end + 4:] + continue + endif + + let body_start = header_end + 4 + let body_end = body_start + content_length + if strlen(s:buffer) < body_end + break + endif + + let body = s:buffer[body_start : body_end - 1] + let s:buffer = s:buffer[body_end :] + + try + let response = json_decode(body) + call s:handle_response(response) + catch + echoerr 'CodeInput: failed to parse LSP message' + endtry + endwhile +endfunction + +function! s:parse_content_length(header) abort + let lines = split(a:header, "\r\n") + for line in lines + if line =~? '^Content-Length:' + return str2nr(matchstr(line, '\d\+')) + endif + endfor + return -1 +endfunction + +function! s:handle_response(response) abort + if has_key(a:response, 'method') && a:response.method ==# 'initialize' + let s:initialized = v:true + call s:send_notification('initialized', {}) + return + endif + + if has_key(a:response, 'id') && has_key(s:pending_requests, a:response.id) + let Callback = s:pending_requests[a:response.id] + unlet s:pending_requests[a:response.id] + if has_key(a:response, 'result') + call Callback(a:response.result) + endif + endif +endfunction + +function! s:handle_error(channel, data) abort + " Ignore progress messages and non-error output + if a:data =~? 'error\|fail' && a:data !~? 'completed successfully' + echoerr 'CodeInput LSP: ' . a:data + endif +endfunction + +function! s:show_hover(result) abort + if type(a:result) == type(v:null) + echo 'CodeInput: no ownership info' + return + endif + + if has_key(a:result, 'contents') + let contents = a:result.contents + if type(contents) == type('') + echo contents + elseif type(contents) == type([]) + echo join(contents, "\n") + endif + endif +endfunction diff --git a/extensions/vim/plugin/codeinput.vim b/extensions/vim/plugin/codeinput.vim new file mode 100644 index 0000000..86bdd79 --- /dev/null +++ b/extensions/vim/plugin/codeinput.vim @@ -0,0 +1,20 @@ +if exists('g:loaded_codeinput') + finish +endif +let g:loaded_codeinput = 1 + +if !has('job') || !has('channel') + echoerr 'CodeInput requires Vim with +job and +channel features' + finish +endif + +command! CodeInputInfo call codeinput#show_info() +command! CodeInputRefresh call codeinput#refresh() +command! CodeInputStop call codeinput#stop() + +augroup CodeInput + autocmd! + autocmd VimLeavePre * call codeinput#stop() +augroup END + +call codeinput#init() From 1c6dc546d3ce43374c89d15fb2d2a072253f3142 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 17:27:34 +0800 Subject: [PATCH 10/21] feat(lsp): add inlay hints support for CODEOWNERS patterns --- codeinput/src/lsp/server.rs | 146 ++++++++++++++++++++++++++++++++++++ 1 file changed, 146 insertions(+) diff --git a/codeinput/src/lsp/server.rs b/codeinput/src/lsp/server.rs index 205eb5d..02d05ff 100644 --- a/codeinput/src/lsp/server.rs +++ b/codeinput/src/lsp/server.rs @@ -232,6 +232,7 @@ impl LanguageServer for LspServer { code_lens_provider: Some(CodeLensOptions { resolve_provider: Some(false), }), + inlay_hint_provider: Some(OneOf::Left(true)), execute_command_provider: Some(ExecuteCommandOptions { commands: vec![ "codeinput.listFiles".to_string(), @@ -470,6 +471,151 @@ impl LanguageServer for LspServer { Ok(None) } + async fn inlay_hint(&self, params: InlayHintParams) -> LspResult>> { + let file_uri = params.text_document.uri; + + self.client + .log_message( + MessageType::INFO, + format!("inlay_hint called for: {}", file_uri), + ) + .await; + + // Only show inlay hints in CODEOWNERS files + let path = uri_to_path(&file_uri); + if let Ok(path) = path { + let file_name = path + .file_name() + .map(|n| n.to_string_lossy()) + .unwrap_or_default(); + self.client + .log_message(MessageType::INFO, format!("file_name: {}", file_name)) + .await; + if file_name.to_lowercase() != "codeowners" { + self.client + .log_message(MessageType::INFO, "Not a CODEOWNERS file, skipping") + .await; + return Ok(None); + } + } else { + self.client + .log_message(MessageType::WARNING, "Failed to convert URI to path") + .await; + return Ok(None); + } + + let workspaces = self.workspaces.read().await; + self.client + .log_message( + MessageType::INFO, + format!("Workspace count: {}", workspaces.len()), + ) + .await; + + // Find the workspace that contains this file + for (root_uri, state) in workspaces.iter() { + self.client + .log_message( + MessageType::INFO, + format!("Checking workspace: {}", root_uri), + ) + .await; + let mut hints = vec![]; + + let file_path = match uri_to_path(&file_uri) { + Ok(p) => p, + Err(_) => continue, + }; + + // Read the CODEOWNERS file content + if let Ok(content) = std::fs::read_to_string(&file_path) { + self.client + .log_message( + MessageType::INFO, + format!("Read CODEOWNERS file, {} lines", content.lines().count()), + ) + .await; + for (line_num, line) in content.lines().enumerate() { + let trimmed = line.trim(); + + // Skip empty lines and comments + if trimmed.is_empty() || trimmed.starts_with('#') { + continue; + } + + // Parse pattern from line + let parts: Vec<&str> = trimmed.split_whitespace().collect(); + if !parts.is_empty() { + let pattern = parts[0]; + + // Count files matching this pattern using the cache + let match_count = state + .cache + .entries + .iter() + .filter(|entry| { + let rel_path = entry.source_file.to_string_lossy(); + // Simple pattern matching + if pattern == "*" { + return true; + } + if pattern.ends_with('/') { + let dir_pattern = &pattern[..pattern.len() - 1]; + rel_path.starts_with(dir_pattern) + } else if pattern.starts_with('*') { + let suffix = &pattern[1..]; + rel_path.ends_with(suffix) + } else if pattern.ends_with("/*") { + let prefix = &pattern[..pattern.len() - 2]; + rel_path.starts_with(prefix) + } else { + rel_path.contains(pattern.trim_start_matches('/')) + } + }) + .count(); + + if match_count > 0 { + let line_length = line.len() as u32; + hints.push(InlayHint { + position: Position::new(line_num as u32, line_length), + label: InlayHintLabel::String(format!( + " {} file{}", + match_count, + if match_count == 1 { "" } else { "s" } + )), + kind: Some(InlayHintKind::TYPE), + text_edits: None, + tooltip: Some(InlayHintTooltip::String(format!( + "This pattern matches {} file(s) in the repository", + match_count + ))), + padding_left: Some(true), + padding_right: Some(false), + data: None, + }); + } + } + } + + self.client + .log_message( + MessageType::INFO, + format!("Generated {} inlay hints", hints.len()), + ) + .await; + return Ok(Some(hints)); + } + } + + self.client + .log_message( + MessageType::WARNING, + "No workspace found for CODEOWNERS file", + ) + .await; + Ok(None) + } + async fn did_change_workspace_folders(&self, params: DidChangeWorkspaceFoldersParams) { // Handle removed workspaces - collect URIs first, then remove them let removed_uris: Vec = params.event.removed.iter().map(|f| f.uri.clone()).collect(); From 2e898684be24c506f3f883bca277f580e0352335 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 17:56:24 +0800 Subject: [PATCH 11/21] refactor(lsp): split server module into separate files for better organization Extract handlers, commands, and types from server.rs into dedicated modules to improve code maintainability and readability --- codeinput/src/lsp/commands.rs | 109 ++++++ codeinput/src/lsp/handlers.rs | 478 +++++++++++++++++++++++++ codeinput/src/lsp/mod.rs | 3 + codeinput/src/lsp/server.rs | 648 +--------------------------------- codeinput/src/lsp/types.rs | 40 +++ 5 files changed, 645 insertions(+), 633 deletions(-) create mode 100644 codeinput/src/lsp/commands.rs create mode 100644 codeinput/src/lsp/handlers.rs create mode 100644 codeinput/src/lsp/types.rs diff --git a/codeinput/src/lsp/commands.rs b/codeinput/src/lsp/commands.rs new file mode 100644 index 0000000..2c35a89 --- /dev/null +++ b/codeinput/src/lsp/commands.rs @@ -0,0 +1,109 @@ +use tower_lsp::jsonrpc::Result as LspResult; +use url::Url; + +use crate::core::types::{CodeownersCache, OwnerType}; + +use super::server::LspServer; +use super::types::*; + +impl LspServer { + pub async fn list_files(&self, workspace_uri: Option) -> LspResult { + let workspaces = self.workspaces.read().await; + + let files = if let Some(uri) = workspace_uri { + if let Some(state) = workspaces.get(&uri) { + Self::collect_files_from_cache(&state.cache) + } else { + Vec::new() + } + } else { + let mut all_files = Vec::new(); + for state in workspaces.values() { + all_files.extend(Self::collect_files_from_cache(&state.cache)); + } + all_files + }; + + Ok(ListFilesResponse { files }) + } + + pub async fn list_owners(&self, workspace_uri: Option) -> LspResult { + let workspaces = self.workspaces.read().await; + + let owners = if let Some(uri) = workspace_uri { + if let Some(state) = workspaces.get(&uri) { + Self::collect_owners_from_cache(&state.cache) + } else { + Vec::new() + } + } else { + let mut all_owners = Vec::new(); + for state in workspaces.values() { + all_owners.extend(Self::collect_owners_from_cache(&state.cache)); + } + all_owners + }; + + Ok(ListOwnersResponse { owners }) + } + + pub async fn list_tags(&self, workspace_uri: Option) -> LspResult { + let workspaces = self.workspaces.read().await; + + let tags = if let Some(uri) = workspace_uri { + if let Some(state) = workspaces.get(&uri) { + Self::collect_tags_from_cache(&state.cache) + } else { + Vec::new() + } + } else { + let mut all_tags = Vec::new(); + for state in workspaces.values() { + all_tags.extend(Self::collect_tags_from_cache(&state.cache)); + } + all_tags + }; + + Ok(ListTagsResponse { tags }) + } + + fn collect_files_from_cache(cache: &CodeownersCache) -> Vec { + cache + .files + .iter() + .map(|entry| FileOwnershipInfo { + path: entry.path.clone(), + owners: entry.owners.clone(), + tags: entry.tags.clone(), + is_unowned: entry.owners.is_empty() + || entry + .owners + .iter() + .any(|o| matches!(o.owner_type, OwnerType::Unowned)), + }) + .collect() + } + + fn collect_owners_from_cache(cache: &CodeownersCache) -> Vec { + cache + .owners_map + .iter() + .map(|(owner, files)| OwnerInfo { + owner: owner.clone(), + files: files.clone(), + }) + .collect() + } + + fn collect_tags_from_cache(cache: &CodeownersCache) -> Vec { + cache + .tags_map + .iter() + .map(|(tag, files)| TagInfo { + tag: tag.clone(), + files: files.clone(), + }) + .collect() + } +} + diff --git a/codeinput/src/lsp/handlers.rs b/codeinput/src/lsp/handlers.rs new file mode 100644 index 0000000..4b6d55f --- /dev/null +++ b/codeinput/src/lsp/handlers.rs @@ -0,0 +1,478 @@ +use serde::Serialize; +use serde_json::Value; +use tower_lsp::jsonrpc::Result as LspResult; +use tower_lsp::lsp_types::*; +use tower_lsp::LanguageServer; +use url::Url; + +use super::server::{is_codeowners_file, uri_to_path, LspServer}; + +#[tower_lsp::async_trait] +impl LanguageServer for LspServer { + async fn initialize(&self, params: InitializeParams) -> LspResult { + // Initialize workspaces from workspace folders + let workspace_folders = params.workspace_folders.unwrap_or_default(); + + for folder in workspace_folders { + if let Err(e) = self.initialize_workspace(folder.uri, None).await { + self.client + .log_message( + MessageType::WARNING, + format!("Failed to initialize workspace: {}", e), + ) + .await; + } + } + + // If no workspace folders, try to use root_uri + if let Some(root_uri) = params.root_uri { + if let Err(e) = self.initialize_workspace(root_uri, None).await { + self.client + .log_message( + MessageType::WARNING, + format!("Failed to initialize root workspace: {}", e), + ) + .await; + } + } + + Ok(InitializeResult { + capabilities: ServerCapabilities { + text_document_sync: Some(TextDocumentSyncCapability::Kind( + TextDocumentSyncKind::FULL, + )), + hover_provider: Some(HoverProviderCapability::Simple(true)), + code_lens_provider: Some(CodeLensOptions { + resolve_provider: Some(false), + }), + inlay_hint_provider: Some(OneOf::Left(true)), + execute_command_provider: Some(ExecuteCommandOptions { + commands: vec![ + "codeinput.listFiles".to_string(), + "codeinput.listOwners".to_string(), + "codeinput.listTags".to_string(), + ], + work_done_progress_options: WorkDoneProgressOptions { + work_done_progress: None, + }, + }), + workspace: Some(WorkspaceServerCapabilities { + workspace_folders: Some(WorkspaceFoldersServerCapabilities { + supported: Some(true), + change_notifications: Some(OneOf::Left(true)), + }), + file_operations: None, + }), + ..ServerCapabilities::default() + }, + server_info: Some(ServerInfo { + name: "codeinput-lsp".to_string(), + version: Some(env!("CARGO_PKG_VERSION").to_string()), + }), + }) + } + + async fn initialized(&self, _: InitializedParams) { + self.client + .log_message(MessageType::INFO, "codeinput LSP server initialized") + .await; + + // Publish initial diagnostics + self.publish_unowned_diagnostics().await; + } + + async fn shutdown(&self) -> LspResult<()> { + Ok(()) + } + + async fn did_open(&self, params: DidOpenTextDocumentParams) { + let file_uri = params.text_document.uri; + + // Check if this is a CODEOWNERS file and refresh cache if so + if is_codeowners_file(&file_uri) { + // Find which workspace this file belongs to + let matching_root = { + let workspaces = self.workspaces.read().await; + workspaces + .keys() + .find(|root_uri| file_uri.as_str().starts_with(root_uri.as_str())) + .cloned() + }; + + if let Some(root_uri) = matching_root { + if let Err(e) = self.refresh_workspace_cache(&root_uri).await { + self.client + .log_message( + MessageType::WARNING, + format!("Failed to refresh cache: {}", e), + ) + .await; + } + // Re-publish diagnostics after cache refresh + self.publish_unowned_diagnostics().await; + } + } + } + + async fn did_change(&self, _params: DidChangeTextDocumentParams) { + // We use full sync, so we don't need to handle incremental changes + } + + async fn did_save(&self, params: DidSaveTextDocumentParams) { + let file_uri = params.text_document.uri; + + // If CODEOWNERS file was saved, refresh the cache + if is_codeowners_file(&file_uri) { + let matching_root = { + let workspaces = self.workspaces.read().await; + workspaces + .keys() + .find(|root_uri| file_uri.as_str().starts_with(root_uri.as_str())) + .cloned() + }; + + if let Some(root_uri) = matching_root { + if let Err(e) = self.refresh_workspace_cache(&root_uri).await { + self.client + .log_message( + MessageType::WARNING, + format!("Failed to refresh cache: {}", e), + ) + .await; + } + self.publish_unowned_diagnostics().await; + } + } + } + + async fn hover(&self, params: HoverParams) -> LspResult> { + let file_uri = params.text_document_position_params.text_document.uri; + + // Get ownership info for this file + if let Some(info) = self.get_file_ownership(&file_uri).await { + let mut contents = vec![]; + + // Add owners section + if info.owners.is_empty() { + contents.push(MarkedString::String("**Owners:** (none)".to_string())); + } else { + let owners_str = info + .owners + .iter() + .map(|o| format!("`{}`", o.identifier)) + .collect::>() + .join(", "); + contents.push(MarkedString::String(format!("**Owners:** {}", owners_str))); + } + + // Add tags section + if !info.tags.is_empty() { + let tags_str = info + .tags + .iter() + .map(|t| format!("`#{}`", t.0)) + .collect::>() + .join(", "); + contents.push(MarkedString::String(format!("**Tags:** {}", tags_str))); + } + + // Add warning if unowned + if info.is_unowned { + contents.push(MarkedString::String( + "⚠️ **Warning:** This file has no CODEOWNERS assignment".to_string(), + )); + } + + return Ok(Some(Hover { + contents: HoverContents::Array(contents), + range: None, + })); + } + + Ok(None) + } + + async fn code_lens(&self, params: CodeLensParams) -> LspResult>> { + let file_uri = params.text_document.uri; + + // Get ownership info for this file + if let Some(info) = self.get_file_ownership(&file_uri).await { + let mut lenses = vec![]; + + // Create a CodeLens showing ownership at the top of the file + if !info.owners.is_empty() { + let owners_str = info + .owners + .iter() + .map(|o| o.identifier.clone()) + .collect::>() + .join(", "); + + // Safely serialize arguments + let args = ( + serde_json::to_value(file_uri.to_string()).ok(), + serde_json::to_value(&info.owners).ok(), + ); + if let (Some(uri_val), Some(owners_val)) = args { + lenses.push(CodeLens { + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 0), + }, + command: Some(Command { + title: format!("$(organization) {}", owners_str), + command: "codeinput.showOwners".to_string(), + arguments: Some(vec![uri_val, owners_val]), + }), + data: None, + }); + } + } + + // Add tags CodeLens if any + if !info.tags.is_empty() { + let tags_str = info + .tags + .iter() + .map(|t| format!("#{}", t.0)) + .collect::>() + .join(", "); + + // Safely serialize arguments + let args = ( + serde_json::to_value(file_uri.to_string()).ok(), + serde_json::to_value(&info.tags).ok(), + ); + if let (Some(uri_val), Some(tags_val)) = args { + lenses.push(CodeLens { + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 0), + }, + command: Some(Command { + title: format!("$(tag) {}", tags_str), + command: "codeinput.showTags".to_string(), + arguments: Some(vec![uri_val, tags_val]), + }), + data: None, + }); + } + } + + // Add unowned warning CodeLens + if info.is_unowned { + // Safely serialize arguments + if let Some(uri_val) = serde_json::to_value(file_uri.to_string()).ok() { + lenses.push(CodeLens { + range: Range { + start: Position::new(0, 0), + end: Position::new(0, 0), + }, + command: Some(Command { + title: "$(warning) Unowned file".to_string(), + command: "codeinput.addOwner".to_string(), + arguments: Some(vec![uri_val]), + }), + data: None, + }); + } + } + + return Ok(Some(lenses)); + } + + Ok(None) + } + + async fn inlay_hint(&self, params: InlayHintParams) -> LspResult>> { + let file_uri = params.text_document.uri; + + self.client + .log_message( + MessageType::INFO, + format!("inlay_hint called for: {}", file_uri), + ) + .await; + + // Only show inlay hints in CODEOWNERS files + let path = uri_to_path(&file_uri); + if let Ok(path) = path { + let file_name = path + .file_name() + .map(|n| n.to_string_lossy()) + .unwrap_or_default(); + self.client + .log_message(MessageType::INFO, format!("file_name: {}", file_name)) + .await; + if file_name.to_lowercase() != "codeowners" { + self.client + .log_message(MessageType::INFO, "Not a CODEOWNERS file, skipping") + .await; + return Ok(None); + } + } else { + self.client + .log_message(MessageType::WARNING, "Failed to convert URI to path") + .await; + return Ok(None); + } + + let workspaces = self.workspaces.read().await; + self.client + .log_message( + MessageType::INFO, + format!("Workspace count: {}", workspaces.len()), + ) + .await; + + // Find the workspace that contains this file + for (root_uri, state) in workspaces.iter() { + self.client + .log_message( + MessageType::INFO, + format!("Checking workspace: {}", root_uri), + ) + .await; + let mut hints = vec![]; + + let file_path = match uri_to_path(&file_uri) { + Ok(p) => p, + Err(_) => continue, + }; + + // Read the CODEOWNERS file content + if let Ok(content) = std::fs::read_to_string(&file_path) { + self.client + .log_message( + MessageType::INFO, + format!("Read CODEOWNERS file, {} lines", content.lines().count()), + ) + .await; + for (line_num, line) in content.lines().enumerate() { + let trimmed = line.trim(); + + // Skip empty lines and comments + if trimmed.is_empty() || trimmed.starts_with('#') { + continue; + } + + // Parse pattern from line + let parts: Vec<&str> = trimmed.split_whitespace().collect(); + if !parts.is_empty() { + let pattern = parts[0]; + + // Count files matching this pattern using the cache + let match_count = state + .cache + .entries + .iter() + .filter(|entry| { + let rel_path = entry.source_file.to_string_lossy(); + // Simple pattern matching + if pattern == "*" { + return true; + } + if pattern.ends_with('/') { + let dir_pattern = &pattern[..pattern.len() - 1]; + rel_path.starts_with(dir_pattern) + } else if pattern.starts_with('*') { + let suffix = &pattern[1..]; + rel_path.ends_with(suffix) + } else if pattern.ends_with("/*") { + let prefix = &pattern[..pattern.len() - 2]; + rel_path.starts_with(prefix) + } else { + rel_path.contains(pattern.trim_start_matches('/')) + } + }) + .count(); + + if match_count > 0 { + let line_length = line.len() as u32; + hints.push(InlayHint { + position: Position::new(line_num as u32, line_length), + label: InlayHintLabel::String(format!( + " {} file{}", + match_count, + if match_count == 1 { "" } else { "s" } + )), + kind: Some(InlayHintKind::TYPE), + text_edits: None, + tooltip: Some(InlayHintTooltip::String(format!( + "This pattern matches {} file(s) in the repository", + match_count + ))), + padding_left: Some(true), + padding_right: Some(false), + data: None, + }); + } + } + } + + self.client + .log_message( + MessageType::INFO, + format!("Generated {} inlay hints", hints.len()), + ) + .await; + return Ok(Some(hints)); + } + } + + self.client + .log_message( + MessageType::WARNING, + "No workspace found for CODEOWNERS file", + ) + .await; + Ok(None) + } + + async fn did_change_workspace_folders(&self, params: DidChangeWorkspaceFoldersParams) { + // Handle removed workspaces - collect URIs first, then remove them + let removed_uris: Vec = params.event.removed.iter().map(|f| f.uri.clone()).collect(); + { + let mut workspaces = self.workspaces.write().await; + for uri in removed_uris { + workspaces.remove(&uri); + } + } + + // Handle added workspaces + for folder in params.event.added { + if let Err(e) = self.initialize_workspace(folder.uri, None).await { + self.client + .log_message( + MessageType::WARNING, + format!("Failed to initialize workspace: {}", e), + ) + .await; + } + } + } + + async fn execute_command(&self, params: ExecuteCommandParams) -> LspResult> { + fn to_value(v: T) -> LspResult { + serde_json::to_value(v) + .map_err(|e| tower_lsp::jsonrpc::Error::invalid_params(e.to_string())) + } + + match params.command.as_str() { + "codeinput.listFiles" => { + let result = self.list_files(None).await?; + to_value(result).map(Some) + } + "codeinput.listOwners" => { + let result = self.list_owners(None).await?; + to_value(result).map(Some) + } + "codeinput.listTags" => { + let result = self.list_tags(None).await?; + to_value(result).map(Some) + } + _ => Err(tower_lsp::jsonrpc::Error::method_not_found()), + } + } +} + diff --git a/codeinput/src/lsp/mod.rs b/codeinput/src/lsp/mod.rs index c4ddcb3..5313819 100644 --- a/codeinput/src/lsp/mod.rs +++ b/codeinput/src/lsp/mod.rs @@ -3,6 +3,9 @@ //! This module provides an LSP server that integrates with the codeinput CLI //! to provide real-time CODEOWNERS information in editors like VS Code, Neovim, etc. +pub mod commands; +pub mod handlers; pub mod server; +pub mod types; pub use server::LspServer; diff --git a/codeinput/src/lsp/server.rs b/codeinput/src/lsp/server.rs index 02d05ff..54351c9 100644 --- a/codeinput/src/lsp/server.rs +++ b/codeinput/src/lsp/server.rs @@ -1,78 +1,30 @@ -//! LSP Server implementation for CODEOWNERS integration -//! -//! Provides LSP handlers for: -//! - textDocument/hover: Show owners/tags when hovering over file paths -//! - textDocument/codeLens: Display ownership information above files -//! - textDocument/publishDiagnostics: Warn about unowned files -//! - Custom methods: -//! - codeinput/listFiles: List all files with ownership info -//! - codeinput/listOwners: List all owners with their files -//! - codeinput/listTags: List all tags with their files - use std::collections::HashMap; use std::path::PathBuf; use std::sync::Arc; -use serde::{Deserialize, Serialize}; -use serde_json::Value; use tokio::sync::RwLock; -use tower_lsp::jsonrpc::Result as LspResult; use tower_lsp::lsp_types::*; -use tower_lsp::{Client, LanguageServer}; +use tower_lsp::Client; use url::Url; use crate::core::cache::sync_cache; -use crate::core::types::{CodeownersCache, Owner, OwnerType, Tag}; +use crate::core::types::{CodeownersCache, OwnerType}; use crate::utils::error::{Error, Result}; +use super::types::FileOwnershipInfo; + /// LSP Server state pub struct LspServer { - client: Client, + pub client: Client, /// Map of workspace root URIs to their cached CODEOWNERS data - workspaces: Arc>>, + pub workspaces: Arc>>, } /// State for a single workspace #[derive(Debug)] -struct WorkspaceState { - cache: CodeownersCache, - cache_file: Option, -} - -/// Information about a file's ownership -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct FileOwnershipInfo { - pub path: PathBuf, - pub owners: Vec, - pub tags: Vec, - pub is_unowned: bool, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ListFilesResponse { - pub files: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct OwnerInfo { - pub owner: Owner, - pub files: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ListOwnersResponse { - pub owners: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct TagInfo { - pub tag: Tag, - pub files: Vec, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ListTagsResponse { - pub tags: Vec, +pub struct WorkspaceState { + pub cache: CodeownersCache, + pub cache_file: Option, } impl LspServer { @@ -85,7 +37,7 @@ impl LspServer { } /// Initialize a workspace by loading its CODEOWNERS cache - async fn initialize_workspace(&self, root_uri: Url, cache_file: Option) -> Result<()> { + pub async fn initialize_workspace(&self, root_uri: Url, cache_file: Option) -> Result<()> { let root_path = uri_to_path(&root_uri)?; // Load or create the cache @@ -100,7 +52,7 @@ impl LspServer { } /// Get file ownership information for a specific file - async fn get_file_ownership(&self, file_uri: &Url) -> Option { + pub async fn get_file_ownership(&self, file_uri: &Url) -> Option { let file_path = uri_to_path(file_uri).ok()?; let workspaces = self.workspaces.read().await; @@ -132,7 +84,7 @@ impl LspServer { } /// Refresh the cache for a workspace - async fn refresh_workspace_cache(&self, root_uri: &Url) -> Result<()> { + pub async fn refresh_workspace_cache(&self, root_uri: &Url) -> Result<()> { let root_path = uri_to_path(root_uri)?; let mut workspaces = self.workspaces.write().await; @@ -145,7 +97,7 @@ impl LspServer { } /// Publish diagnostics for unowned files in all workspaces - async fn publish_unowned_diagnostics(&self) { + pub async fn publish_unowned_diagnostics(&self) { let workspaces = self.workspaces.read().await; for (root_uri, state) in workspaces.iter() { @@ -194,584 +146,14 @@ impl LspServer { } } -#[tower_lsp::async_trait] -impl LanguageServer for LspServer { - async fn initialize(&self, params: InitializeParams) -> LspResult { - // Initialize workspaces from workspace folders - let workspace_folders = params.workspace_folders.unwrap_or_default(); - - for folder in workspace_folders { - if let Err(e) = self.initialize_workspace(folder.uri, None).await { - self.client - .log_message( - MessageType::WARNING, - format!("Failed to initialize workspace: {}", e), - ) - .await; - } - } - - // If no workspace folders, try to use root_uri - if let Some(root_uri) = params.root_uri { - if let Err(e) = self.initialize_workspace(root_uri, None).await { - self.client - .log_message( - MessageType::WARNING, - format!("Failed to initialize root workspace: {}", e), - ) - .await; - } - } - - Ok(InitializeResult { - capabilities: ServerCapabilities { - text_document_sync: Some(TextDocumentSyncCapability::Kind( - TextDocumentSyncKind::FULL, - )), - hover_provider: Some(HoverProviderCapability::Simple(true)), - code_lens_provider: Some(CodeLensOptions { - resolve_provider: Some(false), - }), - inlay_hint_provider: Some(OneOf::Left(true)), - execute_command_provider: Some(ExecuteCommandOptions { - commands: vec![ - "codeinput.listFiles".to_string(), - "codeinput.listOwners".to_string(), - "codeinput.listTags".to_string(), - ], - work_done_progress_options: WorkDoneProgressOptions { - work_done_progress: None, - }, - }), - workspace: Some(WorkspaceServerCapabilities { - workspace_folders: Some(WorkspaceFoldersServerCapabilities { - supported: Some(true), - change_notifications: Some(OneOf::Left(true)), - }), - file_operations: None, - }), - ..ServerCapabilities::default() - }, - server_info: Some(ServerInfo { - name: "codeinput-lsp".to_string(), - version: Some(env!("CARGO_PKG_VERSION").to_string()), - }), - }) - } - - async fn initialized(&self, _: InitializedParams) { - self.client - .log_message(MessageType::INFO, "codeinput LSP server initialized") - .await; - - // Publish initial diagnostics - self.publish_unowned_diagnostics().await; - } - - async fn shutdown(&self) -> LspResult<()> { - Ok(()) - } - - async fn did_open(&self, params: DidOpenTextDocumentParams) { - let file_uri = params.text_document.uri; - - // Check if this is a CODEOWNERS file and refresh cache if so - if is_codeowners_file(&file_uri) { - // Find which workspace this file belongs to - let matching_root = { - let workspaces = self.workspaces.read().await; - workspaces - .keys() - .find(|root_uri| file_uri.as_str().starts_with(root_uri.as_str())) - .cloned() - }; - - if let Some(root_uri) = matching_root { - if let Err(e) = self.refresh_workspace_cache(&root_uri).await { - self.client - .log_message( - MessageType::WARNING, - format!("Failed to refresh cache: {}", e), - ) - .await; - } - // Re-publish diagnostics after cache refresh - self.publish_unowned_diagnostics().await; - } - } - } - - async fn did_change(&self, _params: DidChangeTextDocumentParams) { - // We use full sync, so we don't need to handle incremental changes - } - - async fn did_save(&self, params: DidSaveTextDocumentParams) { - let file_uri = params.text_document.uri; - - // If CODEOWNERS file was saved, refresh the cache - if is_codeowners_file(&file_uri) { - let matching_root = { - let workspaces = self.workspaces.read().await; - workspaces - .keys() - .find(|root_uri| file_uri.as_str().starts_with(root_uri.as_str())) - .cloned() - }; - - if let Some(root_uri) = matching_root { - if let Err(e) = self.refresh_workspace_cache(&root_uri).await { - self.client - .log_message( - MessageType::WARNING, - format!("Failed to refresh cache: {}", e), - ) - .await; - } - self.publish_unowned_diagnostics().await; - } - } - } - - async fn hover(&self, params: HoverParams) -> LspResult> { - let file_uri = params.text_document_position_params.text_document.uri; - - // Get ownership info for this file - if let Some(info) = self.get_file_ownership(&file_uri).await { - let mut contents = vec![]; - - // Add owners section - if info.owners.is_empty() { - contents.push(MarkedString::String("**Owners:** (none)".to_string())); - } else { - let owners_str = info - .owners - .iter() - .map(|o| format!("`{}`", o.identifier)) - .collect::>() - .join(", "); - contents.push(MarkedString::String(format!("**Owners:** {}", owners_str))); - } - - // Add tags section - if !info.tags.is_empty() { - let tags_str = info - .tags - .iter() - .map(|t| format!("`#{}`", t.0)) - .collect::>() - .join(", "); - contents.push(MarkedString::String(format!("**Tags:** {}", tags_str))); - } - - // Add warning if unowned - if info.is_unowned { - contents.push(MarkedString::String( - "⚠️ **Warning:** This file has no CODEOWNERS assignment".to_string(), - )); - } - - return Ok(Some(Hover { - contents: HoverContents::Array(contents), - range: None, - })); - } - - Ok(None) - } - - async fn code_lens(&self, params: CodeLensParams) -> LspResult>> { - let file_uri = params.text_document.uri; - - // Get ownership info for this file - if let Some(info) = self.get_file_ownership(&file_uri).await { - let mut lenses = vec![]; - - // Create a CodeLens showing ownership at the top of the file - if !info.owners.is_empty() { - let owners_str = info - .owners - .iter() - .map(|o| o.identifier.clone()) - .collect::>() - .join(", "); - - // Safely serialize arguments - let args = ( - serde_json::to_value(file_uri.to_string()).ok(), - serde_json::to_value(&info.owners).ok(), - ); - if let (Some(uri_val), Some(owners_val)) = args { - lenses.push(CodeLens { - range: Range { - start: Position::new(0, 0), - end: Position::new(0, 0), - }, - command: Some(Command { - title: format!("$(organization) {}", owners_str), - command: "codeinput.showOwners".to_string(), - arguments: Some(vec![uri_val, owners_val]), - }), - data: None, - }); - } - } - - // Add tags CodeLens if any - if !info.tags.is_empty() { - let tags_str = info - .tags - .iter() - .map(|t| format!("#{}", t.0)) - .collect::>() - .join(", "); - - // Safely serialize arguments - let args = ( - serde_json::to_value(file_uri.to_string()).ok(), - serde_json::to_value(&info.tags).ok(), - ); - if let (Some(uri_val), Some(tags_val)) = args { - lenses.push(CodeLens { - range: Range { - start: Position::new(0, 0), - end: Position::new(0, 0), - }, - command: Some(Command { - title: format!("$(tag) {}", tags_str), - command: "codeinput.showTags".to_string(), - arguments: Some(vec![uri_val, tags_val]), - }), - data: None, - }); - } - } - - // Add unowned warning CodeLens - if info.is_unowned { - // Safely serialize arguments - if let Some(uri_val) = serde_json::to_value(file_uri.to_string()).ok() { - lenses.push(CodeLens { - range: Range { - start: Position::new(0, 0), - end: Position::new(0, 0), - }, - command: Some(Command { - title: "$(warning) Unowned file".to_string(), - command: "codeinput.addOwner".to_string(), - arguments: Some(vec![uri_val]), - }), - data: None, - }); - } - } - - return Ok(Some(lenses)); - } - - Ok(None) - } - - async fn inlay_hint(&self, params: InlayHintParams) -> LspResult>> { - let file_uri = params.text_document.uri; - - self.client - .log_message( - MessageType::INFO, - format!("inlay_hint called for: {}", file_uri), - ) - .await; - - // Only show inlay hints in CODEOWNERS files - let path = uri_to_path(&file_uri); - if let Ok(path) = path { - let file_name = path - .file_name() - .map(|n| n.to_string_lossy()) - .unwrap_or_default(); - self.client - .log_message(MessageType::INFO, format!("file_name: {}", file_name)) - .await; - if file_name.to_lowercase() != "codeowners" { - self.client - .log_message(MessageType::INFO, "Not a CODEOWNERS file, skipping") - .await; - return Ok(None); - } - } else { - self.client - .log_message(MessageType::WARNING, "Failed to convert URI to path") - .await; - return Ok(None); - } - - let workspaces = self.workspaces.read().await; - self.client - .log_message( - MessageType::INFO, - format!("Workspace count: {}", workspaces.len()), - ) - .await; - - // Find the workspace that contains this file - for (root_uri, state) in workspaces.iter() { - self.client - .log_message( - MessageType::INFO, - format!("Checking workspace: {}", root_uri), - ) - .await; - let mut hints = vec![]; - - let file_path = match uri_to_path(&file_uri) { - Ok(p) => p, - Err(_) => continue, - }; - - // Read the CODEOWNERS file content - if let Ok(content) = std::fs::read_to_string(&file_path) { - self.client - .log_message( - MessageType::INFO, - format!("Read CODEOWNERS file, {} lines", content.lines().count()), - ) - .await; - for (line_num, line) in content.lines().enumerate() { - let trimmed = line.trim(); - - // Skip empty lines and comments - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } - - // Parse pattern from line - let parts: Vec<&str> = trimmed.split_whitespace().collect(); - if !parts.is_empty() { - let pattern = parts[0]; - - // Count files matching this pattern using the cache - let match_count = state - .cache - .entries - .iter() - .filter(|entry| { - let rel_path = entry.source_file.to_string_lossy(); - // Simple pattern matching - if pattern == "*" { - return true; - } - if pattern.ends_with('/') { - let dir_pattern = &pattern[..pattern.len() - 1]; - rel_path.starts_with(dir_pattern) - } else if pattern.starts_with('*') { - let suffix = &pattern[1..]; - rel_path.ends_with(suffix) - } else if pattern.ends_with("/*") { - let prefix = &pattern[..pattern.len() - 2]; - rel_path.starts_with(prefix) - } else { - rel_path.contains(pattern.trim_start_matches('/')) - } - }) - .count(); - - if match_count > 0 { - let line_length = line.len() as u32; - hints.push(InlayHint { - position: Position::new(line_num as u32, line_length), - label: InlayHintLabel::String(format!( - " {} file{}", - match_count, - if match_count == 1 { "" } else { "s" } - )), - kind: Some(InlayHintKind::TYPE), - text_edits: None, - tooltip: Some(InlayHintTooltip::String(format!( - "This pattern matches {} file(s) in the repository", - match_count - ))), - padding_left: Some(true), - padding_right: Some(false), - data: None, - }); - } - } - } - - self.client - .log_message( - MessageType::INFO, - format!("Generated {} inlay hints", hints.len()), - ) - .await; - return Ok(Some(hints)); - } - } - - self.client - .log_message( - MessageType::WARNING, - "No workspace found for CODEOWNERS file", - ) - .await; - Ok(None) - } - - async fn did_change_workspace_folders(&self, params: DidChangeWorkspaceFoldersParams) { - // Handle removed workspaces - collect URIs first, then remove them - let removed_uris: Vec = params.event.removed.iter().map(|f| f.uri.clone()).collect(); - { - let mut workspaces = self.workspaces.write().await; - for uri in removed_uris { - workspaces.remove(&uri); - } - } - - // Handle added workspaces - for folder in params.event.added { - if let Err(e) = self.initialize_workspace(folder.uri, None).await { - self.client - .log_message( - MessageType::WARNING, - format!("Failed to initialize workspace: {}", e), - ) - .await; - } - } - } - - async fn execute_command(&self, params: ExecuteCommandParams) -> LspResult> { - fn to_value(v: T) -> LspResult { - serde_json::to_value(v) - .map_err(|e| tower_lsp::jsonrpc::Error::invalid_params(e.to_string())) - } - - match params.command.as_str() { - "codeinput.listFiles" => { - let result = self.list_files(None).await?; - to_value(result).map(Some) - } - "codeinput.listOwners" => { - let result = self.list_owners(None).await?; - to_value(result).map(Some) - } - "codeinput.listTags" => { - let result = self.list_tags(None).await?; - to_value(result).map(Some) - } - _ => Err(tower_lsp::jsonrpc::Error::method_not_found()), - } - } -} - -impl LspServer { - pub async fn list_files(&self, workspace_uri: Option) -> LspResult { - let workspaces = self.workspaces.read().await; - - let files = if let Some(uri) = workspace_uri { - if let Some(state) = workspaces.get(&uri) { - Self::collect_files_from_cache(&state.cache) - } else { - Vec::new() - } - } else { - let mut all_files = Vec::new(); - for state in workspaces.values() { - all_files.extend(Self::collect_files_from_cache(&state.cache)); - } - all_files - }; - - Ok(ListFilesResponse { files }) - } - - pub async fn list_owners(&self, workspace_uri: Option) -> LspResult { - let workspaces = self.workspaces.read().await; - - let owners = if let Some(uri) = workspace_uri { - if let Some(state) = workspaces.get(&uri) { - Self::collect_owners_from_cache(&state.cache) - } else { - Vec::new() - } - } else { - let mut all_owners = Vec::new(); - for state in workspaces.values() { - all_owners.extend(Self::collect_owners_from_cache(&state.cache)); - } - all_owners - }; - - Ok(ListOwnersResponse { owners }) - } - - pub async fn list_tags(&self, workspace_uri: Option) -> LspResult { - let workspaces = self.workspaces.read().await; - - let tags = if let Some(uri) = workspace_uri { - if let Some(state) = workspaces.get(&uri) { - Self::collect_tags_from_cache(&state.cache) - } else { - Vec::new() - } - } else { - let mut all_tags = Vec::new(); - for state in workspaces.values() { - all_tags.extend(Self::collect_tags_from_cache(&state.cache)); - } - all_tags - }; - - Ok(ListTagsResponse { tags }) - } - - fn collect_files_from_cache(cache: &CodeownersCache) -> Vec { - cache - .files - .iter() - .map(|entry| FileOwnershipInfo { - path: entry.path.clone(), - owners: entry.owners.clone(), - tags: entry.tags.clone(), - is_unowned: entry.owners.is_empty() - || entry - .owners - .iter() - .any(|o| matches!(o.owner_type, OwnerType::Unowned)), - }) - .collect() - } - - fn collect_owners_from_cache(cache: &CodeownersCache) -> Vec { - cache - .owners_map - .iter() - .map(|(owner, files)| OwnerInfo { - owner: owner.clone(), - files: files.clone(), - }) - .collect() - } - - fn collect_tags_from_cache(cache: &CodeownersCache) -> Vec { - cache - .tags_map - .iter() - .map(|(tag, files)| TagInfo { - tag: tag.clone(), - files: files.clone(), - }) - .collect() - } -} - /// Convert a URL to a file path -fn uri_to_path(uri: &Url) -> Result { +pub fn uri_to_path(uri: &Url) -> Result { uri.to_file_path() .map_err(|_| Error::new("Invalid file URI")) } /// Check if a URI points to a CODEOWNERS file -fn is_codeowners_file(uri: &Url) -> bool { +pub fn is_codeowners_file(uri: &Url) -> bool { let path = uri.path(); path.contains("CODEOWNERS") || path.contains("codeowners") } diff --git a/codeinput/src/lsp/types.rs b/codeinput/src/lsp/types.rs new file mode 100644 index 0000000..9f1d2f6 --- /dev/null +++ b/codeinput/src/lsp/types.rs @@ -0,0 +1,40 @@ +use std::path::PathBuf; +use serde::{Deserialize, Serialize}; +use crate::core::types::{Owner, Tag}; + +/// Information about a file's ownership +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct FileOwnershipInfo { + pub path: PathBuf, + pub owners: Vec, + pub tags: Vec, + pub is_unowned: bool, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ListFilesResponse { + pub files: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct OwnerInfo { + pub owner: Owner, + pub files: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ListOwnersResponse { + pub owners: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct TagInfo { + pub tag: Tag, + pub files: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct ListTagsResponse { + pub tags: Vec, +} + From 4d9babd8fb4564e3ab5271f39b9dfab32dd3508d Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 18:37:16 +0800 Subject: [PATCH 12/21] feat(lsp): add getFileOwnership command and refactor inlay hints --- codeinput/src/lsp/commands.rs | 8 ++ codeinput/src/lsp/handlers.rs | 176 +++++++++++----------------------- 2 files changed, 64 insertions(+), 120 deletions(-) diff --git a/codeinput/src/lsp/commands.rs b/codeinput/src/lsp/commands.rs index 2c35a89..ab541d1 100644 --- a/codeinput/src/lsp/commands.rs +++ b/codeinput/src/lsp/commands.rs @@ -7,6 +7,13 @@ use super::server::LspServer; use super::types::*; impl LspServer { + pub async fn get_file_ownership_command(&self, uri_str: String) -> LspResult> { + let Ok(uri) = Url::parse(&uri_str) else { + return Err(tower_lsp::jsonrpc::Error::invalid_params("Invalid URI")); + }; + Ok(self.get_file_ownership(&uri).await) + } + pub async fn list_files(&self, workspace_uri: Option) -> LspResult { let workspaces = self.workspaces.read().await; @@ -107,3 +114,4 @@ impl LspServer { } } + diff --git a/codeinput/src/lsp/handlers.rs b/codeinput/src/lsp/handlers.rs index 4b6d55f..731c44c 100644 --- a/codeinput/src/lsp/handlers.rs +++ b/codeinput/src/lsp/handlers.rs @@ -51,6 +51,7 @@ impl LanguageServer for LspServer { "codeinput.listFiles".to_string(), "codeinput.listOwners".to_string(), "codeinput.listTags".to_string(), + "codeinput.getFileOwnership".to_string(), ], work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None, @@ -287,145 +288,73 @@ impl LanguageServer for LspServer { async fn inlay_hint(&self, params: InlayHintParams) -> LspResult>> { let file_uri = params.text_document.uri; - self.client - .log_message( - MessageType::INFO, - format!("inlay_hint called for: {}", file_uri), - ) - .await; - - // Only show inlay hints in CODEOWNERS files let path = uri_to_path(&file_uri); - if let Ok(path) = path { - let file_name = path - .file_name() - .map(|n| n.to_string_lossy()) - .unwrap_or_default(); - self.client - .log_message(MessageType::INFO, format!("file_name: {}", file_name)) - .await; - if file_name.to_lowercase() != "codeowners" { - self.client - .log_message(MessageType::INFO, "Not a CODEOWNERS file, skipping") - .await; - return Ok(None); - } - } else { - self.client - .log_message(MessageType::WARNING, "Failed to convert URI to path") - .await; + let file_path = match path { + Ok(p) => p, + Err(_) => return Ok(None), + }; + + if file_path.file_name().and_then(|n| n.to_str()).unwrap_or_default().to_lowercase() != "codeowners" { return Ok(None); } let workspaces = self.workspaces.read().await; - self.client - .log_message( - MessageType::INFO, - format!("Workspace count: {}", workspaces.len()), - ) - .await; - // Find the workspace that contains this file - for (root_uri, state) in workspaces.iter() { - self.client - .log_message( - MessageType::INFO, - format!("Checking workspace: {}", root_uri), - ) - .await; - let mut hints = vec![]; + for (_root_uri, state) in workspaces.iter() { + let file_entries: Vec<_> = state.cache.entries.iter() + .filter(|e| e.source_file == file_path) + .collect(); - let file_path = match uri_to_path(&file_uri) { - Ok(p) => p, + if file_entries.is_empty() { + continue; + } + + // Read the CODEOWNERS file content asynchronously to get line lengths + let content = match tokio::fs::read_to_string(&file_path).await { + Ok(c) => c, Err(_) => continue, }; - // Read the CODEOWNERS file content - if let Ok(content) = std::fs::read_to_string(&file_path) { - self.client - .log_message( - MessageType::INFO, - format!("Read CODEOWNERS file, {} lines", content.lines().count()), - ) - .await; - for (line_num, line) in content.lines().enumerate() { - let trimmed = line.trim(); + let lines: Vec<&str> = content.lines().collect(); + let mut hints = vec![]; - // Skip empty lines and comments - if trimmed.is_empty() || trimmed.starts_with('#') { - continue; - } + for entry in file_entries { + let line_idx = if entry.line_number > 0 { entry.line_number - 1 } else { 0 }; + let line_length = lines.get(line_idx).map(|l| l.len() as u32).unwrap_or(0); - // Parse pattern from line - let parts: Vec<&str> = trimmed.split_whitespace().collect(); - if !parts.is_empty() { - let pattern = parts[0]; - - // Count files matching this pattern using the cache - let match_count = state - .cache - .entries - .iter() - .filter(|entry| { - let rel_path = entry.source_file.to_string_lossy(); - // Simple pattern matching - if pattern == "*" { - return true; - } - if pattern.ends_with('/') { - let dir_pattern = &pattern[..pattern.len() - 1]; - rel_path.starts_with(dir_pattern) - } else if pattern.starts_with('*') { - let suffix = &pattern[1..]; - rel_path.ends_with(suffix) - } else if pattern.ends_with("/*") { - let prefix = &pattern[..pattern.len() - 2]; - rel_path.starts_with(prefix) - } else { - rel_path.contains(pattern.trim_start_matches('/')) - } - }) - .count(); - - if match_count > 0 { - let line_length = line.len() as u32; - hints.push(InlayHint { - position: Position::new(line_num as u32, line_length), - label: InlayHintLabel::String(format!( - " {} file{}", - match_count, - if match_count == 1 { "" } else { "s" } - )), - kind: Some(InlayHintKind::TYPE), - text_edits: None, - tooltip: Some(InlayHintTooltip::String(format!( - "This pattern matches {} file(s) in the repository", - match_count - ))), - padding_left: Some(true), - padding_right: Some(false), - data: None, - }); - } + let matcher = crate::core::types::codeowners_entry_to_matcher(entry); + + let mut match_count = 0; + for file_entry in &state.cache.files { + if matcher.override_matcher.matched(&file_entry.path, false).is_whitelist() { + match_count += 1; } } - self.client - .log_message( - MessageType::INFO, - format!("Generated {} inlay hints", hints.len()), - ) - .await; + hints.push(InlayHint { + position: Position::new(line_idx as u32, line_length), + label: InlayHintLabel::String(format!( + " {} file{}", + match_count, + if match_count == 1 { "" } else { "s" } + )), + kind: Some(InlayHintKind::TYPE), + text_edits: None, + tooltip: Some(InlayHintTooltip::String(format!( + "This pattern matches {} file(s) in the repository", + match_count + ))), + padding_left: Some(true), + padding_right: Some(false), + data: None, + }); + } + + if !hints.is_empty() { return Ok(Some(hints)); } } - self.client - .log_message( - MessageType::WARNING, - "No workspace found for CODEOWNERS file", - ) - .await; Ok(None) } @@ -459,6 +388,13 @@ impl LanguageServer for LspServer { } match params.command.as_str() { + "codeinput.getFileOwnership" => { + let uri_val = params.arguments.first().and_then(|v| v.as_str()).ok_or_else(|| { + tower_lsp::jsonrpc::Error::invalid_params("Expected a single URI string argument") + })?; + let result = self.get_file_ownership_command(uri_val.to_string()).await?; + to_value(result).map(Some) + } "codeinput.listFiles" => { let result = self.list_files(None).await?; to_value(result).map(Some) From c25166ce2395ca2e9aa969b6220356bc92fd6aa6 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Fri, 6 Mar 2026 19:16:24 +0800 Subject: [PATCH 13/21] refactor(vscode): simplify extension by removing unused features and streamlining code Remove addOwner command, simplify binary path resolution, use LSP command for ownership info instead of hover parsing, and streamline status bar display. --- extensions/vscode/package.json | 9 ----- extensions/vscode/src/client.ts | 63 +++++------------------------ extensions/vscode/src/extension.ts | 64 ++++++------------------------ extensions/vscode/src/statusbar.ts | 40 ++----------------- 4 files changed, 25 insertions(+), 151 deletions(-) diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index e728742..e7770d5 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -37,11 +37,6 @@ "title": "Show CODEOWNERS Tags", "category": "CodeInput" }, - { - "command": "codeinput.addOwner", - "title": "Add CODEOWNERS Entry", - "category": "CodeInput" - }, { "command": "codeinput.refreshCache", "title": "Refresh CODEOWNERS Cache", @@ -101,10 +96,6 @@ { "command": "codeinput.showTags", "when": "false" - }, - { - "command": "codeinput.addOwner", - "when": "false" } ] } diff --git a/extensions/vscode/src/client.ts b/extensions/vscode/src/client.ts index 8aa5287..69bf333 100644 --- a/extensions/vscode/src/client.ts +++ b/extensions/vscode/src/client.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode'; import { + ExecuteCommandRequest, LanguageClient, LanguageClientOptions, ServerOptions, @@ -9,7 +10,7 @@ import { export interface FileOwnershipInfo { path: string; owners: Array<{ identifier: string; owner_type: string }>; - tags: Array<{ 0: string }>; + tags: string[]; is_unowned: boolean; } @@ -97,68 +98,22 @@ export class CodeInputClient { return undefined; } - // Use the hover request to get ownership info try { - const hover = await this.client.sendRequest('textDocument/hover', { - textDocument: { uri: uri.toString() }, - position: { line: 0, character: 0 } - }) as any; + const info = await this.client.sendRequest(ExecuteCommandRequest.type, { + command: 'codeinput.getFileOwnership', + arguments: [uri.toString()] + }) as FileOwnershipInfo | null | undefined; - if (hover && hover.contents) { - // Parse hover contents to extract ownership info - return this.parseHoverContents(hover.contents, uri); + if (info) { + return info; } } catch (error) { - console.error('Error getting file ownership:', error); + console.error('[CodeInput Client] Error:', error); } return undefined; } - private parseHoverContents(contents: any, uri: vscode.Uri): FileOwnershipInfo | undefined { - // The LSP server returns hover contents with owners and tags - // This is a simplified parser - in production you'd want more robust parsing - const info: FileOwnershipInfo = { - path: uri.fsPath, - owners: [], - tags: [], - is_unowned: false - }; - - if (Array.isArray(contents)) { - for (const item of contents) { - if (typeof item === 'string') { - if (item.includes('Owners:')) { - const ownersMatch = item.match(/\*\*Owners:\*\* (.+)/); - if (ownersMatch) { - const ownersStr = ownersMatch[1]; - if (ownersStr !== '(none)') { - info.owners = ownersStr.split(', ').map(o => ({ - identifier: o.replace(/`/g, ''), - owner_type: 'Unknown' - })); - } - } - } - if (item.includes('Tags:')) { - const tagsMatch = item.match(/\*\*Tags:\*\* (.+)/); - if (tagsMatch) { - const tagsStr = tagsMatch[1]; - info.tags = tagsStr.split(', ').map(t => ({ - 0: t.replace(/`#/g, '').replace(/`/g, '') - })); - } - } - if (item.includes('Warning')) { - info.is_unowned = true; - } - } - } - } - - return info; - } - public isRunning(): boolean { return this.client?.isRunning() === true; } diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 902dd94..2c64616 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -12,7 +12,6 @@ async function checkBinary(binaryPath: string): Promise { const proc = spawn(binaryPath, ['lsp', '--help']); proc.on('error', () => resolve(false)); proc.on('exit', (code) => resolve(code === 0)); - // Timeout after 2 seconds setTimeout(() => { proc.kill(); resolve(false); @@ -23,31 +22,19 @@ async function checkBinary(binaryPath: string): Promise { export async function activate(context: vscode.ExtensionContext) { console.log('CodeInput extension is now active'); - // Check if custom binary path is set const config = vscode.workspace.getConfiguration('codeinput'); - const userBinaryPath = config.get('binaryPath', 'ci-lsp'); + const binaryPath = config.get('binaryPath', 'ci-lsp'); let finalBinaryPath: string | undefined; let binarySource = 'unknown'; - // If user set a custom path, use it - if (userBinaryPath !== 'ci-lsp') { - console.log(`[CodeInput] Checking user-specified binary: ${userBinaryPath}`); - const exists = await checkBinary(userBinaryPath); - if (exists) { - finalBinaryPath = userBinaryPath; - binarySource = 'user-config'; - console.log(`[CodeInput] Using user-specified binary: ${finalBinaryPath}`); - } else { - console.error(`[CodeInput] User-specified binary not found: ${userBinaryPath}`); - vscode.window.showErrorMessage( - `Custom binary not found: ${userBinaryPath}. Please check the path or install codeinput-lsp.` - ); - return; - } + const exists = await checkBinary(binaryPath); + if (exists) { + finalBinaryPath = binaryPath; + binarySource = 'config'; + console.log(`[CodeInput] Using binary from config: ${finalBinaryPath}`); } else { - // Try to download ci-lsp first - console.log('[CodeInput] Attempting to download ci-lsp binary...'); + console.log(`[CodeInput] Binary not found at ${binaryPath}, attempting to download...`); const downloader = new BinaryDownloader(context); const downloadedPath = await downloader.ensureBinary(); @@ -56,24 +43,11 @@ export async function activate(context: vscode.ExtensionContext) { binarySource = 'downloaded'; console.log(`[CodeInput] Using downloaded binary: ${finalBinaryPath}`); } else { - console.log('[CodeInput] Download failed, checking for existing ci binary with LSP support...'); - // Download failed, check if `ci` with LSP exists - const ciExists = await checkBinary('ci'); - if (ciExists) { - binarySource = 'fallback-ci'; - finalBinaryPath = 'ci'; - console.log('[CodeInput] Using fallback ci binary with LSP support'); - vscode.window.showInformationMessage( - 'Using existing `ci` binary with LSP support. Consider downloading `ci-lsp` for better performance.' - ); - } else { - // Neither works - console.error('[CodeInput] No usable binary found (tried downloading ci-lsp and using ci)'); - vscode.window.showErrorMessage( - 'codeinput-lsp not found. Please install it: curl -L https://github.com/code-input/cli/releases/latest/download/ci-lsp-linux-x64 -o ~/bin/ci-lsp && chmod +x ~/bin/ci-lsp' - ); - return; - } + console.error('[CodeInput] No usable binary found'); + vscode.window.showErrorMessage( + 'codeinput binary not found. Install it or set codeinput.binaryPath in settings.' + ); + return; } } @@ -152,20 +126,6 @@ export async function activate(context: vscode.ExtensionContext) { }) ); - context.subscriptions.push( - vscode.commands.registerCommand('codeinput.addOwner', async (uri: string) => { - const owner = await vscode.window.showInputBox({ - prompt: 'Enter owner (e.g., @username or @org/team)', - placeHolder: '@username' - }); - - if (owner) { - vscode.window.showInformationMessage(`Would add owner ${owner} to ${uri}`); - // TODO: Implement adding owner to CODEOWNERS file - } - }) - ); - // Handle configuration changes context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(e => { diff --git a/extensions/vscode/src/statusbar.ts b/extensions/vscode/src/statusbar.ts index 40808d7..e3c872a 100644 --- a/extensions/vscode/src/statusbar.ts +++ b/extensions/vscode/src/statusbar.ts @@ -12,7 +12,6 @@ export class StatusBarManager implements vscode.Disposable { vscode.StatusBarAlignment.Right, 100 ); - this.statusBarItem.command = 'codeinput.showInfo'; // Update when active editor changes this.disposables.push( @@ -55,7 +54,6 @@ export class StatusBarManager implements vscode.Disposable { const fileUri = editor.document.uri; - // Only show for file:// URIs if (fileUri.scheme !== 'file') { this.statusBarItem.hide(); return; @@ -66,23 +64,16 @@ export class StatusBarManager implements vscode.Disposable { if (info) { if (info.is_unowned || info.owners.length === 0) { - this.statusBarItem.text = '$(warning) Unowned'; - this.statusBarItem.tooltip = 'This file has no CODEOWNERS assignment\nClick to see details'; + this.statusBarItem.text = '$(alert)'; + this.statusBarItem.tooltip = 'No CODEOWNERS'; this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); } else { - const ownerNames = info.owners.map(o => o.identifier).join(', '); - const ownerInitials = info.owners - .map(o => this.getInitials(o.identifier)) - .join(''); - - this.statusBarItem.text = `$(lock) ${ownerInitials}`; - this.statusBarItem.tooltip = `Owners: ${ownerNames}\nClick to see details`; + this.statusBarItem.text = '$(lock)'; + this.statusBarItem.tooltip = 'Has CODEOWNERS'; this.statusBarItem.backgroundColor = undefined; } - this.statusBarItem.show(); } else { - // No CODEOWNERS info available (file not in cache) this.statusBarItem.hide(); } } catch (error) { @@ -91,29 +82,6 @@ export class StatusBarManager implements vscode.Disposable { } } - private getInitials(identifier: string): string { - // Extract initials from owner identifier - // @org/team -> T, @username -> U, email@domain.com -> E - - if (identifier.startsWith('@')) { - // Handle @org/team format - const parts = identifier.split('/'); - if (parts.length > 1) { - return parts[parts.length - 1].charAt(0).toUpperCase(); - } - // Handle @username format - return identifier.charAt(1).toUpperCase(); - } - - if (identifier.includes('@')) { - // Email format - return identifier.charAt(0).toUpperCase(); - } - - // Fallback - return identifier.charAt(0).toUpperCase(); - } - public dispose(): void { this.statusBarItem.dispose(); this.disposables.forEach(d => d.dispose()); From 03783f2fa33971bb28ca56fa0c77855a00c357aa Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 13:37:49 +0800 Subject: [PATCH 14/21] refactor(lsp): remove unowned file warning CodeLens and apply formatting --- codeinput/src/lsp/handlers.rs | 63 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/codeinput/src/lsp/handlers.rs b/codeinput/src/lsp/handlers.rs index 731c44c..9be0de3 100644 --- a/codeinput/src/lsp/handlers.rs +++ b/codeinput/src/lsp/handlers.rs @@ -1,11 +1,11 @@ use serde::Serialize; use serde_json::Value; +use tower_lsp::LanguageServer; use tower_lsp::jsonrpc::Result as LspResult; use tower_lsp::lsp_types::*; -use tower_lsp::LanguageServer; use url::Url; -use super::server::{is_codeowners_file, uri_to_path, LspServer}; +use super::server::{LspServer, is_codeowners_file, uri_to_path}; #[tower_lsp::async_trait] impl LanguageServer for LspServer { @@ -260,25 +260,6 @@ impl LanguageServer for LspServer { } } - // Add unowned warning CodeLens - if info.is_unowned { - // Safely serialize arguments - if let Some(uri_val) = serde_json::to_value(file_uri.to_string()).ok() { - lenses.push(CodeLens { - range: Range { - start: Position::new(0, 0), - end: Position::new(0, 0), - }, - command: Some(Command { - title: "$(warning) Unowned file".to_string(), - command: "codeinput.addOwner".to_string(), - arguments: Some(vec![uri_val]), - }), - data: None, - }); - } - } - return Ok(Some(lenses)); } @@ -294,14 +275,23 @@ impl LanguageServer for LspServer { Err(_) => return Ok(None), }; - if file_path.file_name().and_then(|n| n.to_str()).unwrap_or_default().to_lowercase() != "codeowners" { + if file_path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or_default() + .to_lowercase() + != "codeowners" + { return Ok(None); } let workspaces = self.workspaces.read().await; for (_root_uri, state) in workspaces.iter() { - let file_entries: Vec<_> = state.cache.entries.iter() + let file_entries: Vec<_> = state + .cache + .entries + .iter() .filter(|e| e.source_file == file_path) .collect(); @@ -319,14 +309,22 @@ impl LanguageServer for LspServer { let mut hints = vec![]; for entry in file_entries { - let line_idx = if entry.line_number > 0 { entry.line_number - 1 } else { 0 }; + let line_idx = if entry.line_number > 0 { + entry.line_number - 1 + } else { + 0 + }; let line_length = lines.get(line_idx).map(|l| l.len() as u32).unwrap_or(0); let matcher = crate::core::types::codeowners_entry_to_matcher(entry); - + let mut match_count = 0; for file_entry in &state.cache.files { - if matcher.override_matcher.matched(&file_entry.path, false).is_whitelist() { + if matcher + .override_matcher + .matched(&file_entry.path, false) + .is_whitelist() + { match_count += 1; } } @@ -389,9 +387,15 @@ impl LanguageServer for LspServer { match params.command.as_str() { "codeinput.getFileOwnership" => { - let uri_val = params.arguments.first().and_then(|v| v.as_str()).ok_or_else(|| { - tower_lsp::jsonrpc::Error::invalid_params("Expected a single URI string argument") - })?; + let uri_val = params + .arguments + .first() + .and_then(|v| v.as_str()) + .ok_or_else(|| { + tower_lsp::jsonrpc::Error::invalid_params( + "Expected a single URI string argument", + ) + })?; let result = self.get_file_ownership_command(uri_val.to_string()).await?; to_value(result).map(Some) } @@ -411,4 +415,3 @@ impl LanguageServer for LspServer { } } } - From e476d37a440aebbb02927e83e6cb5ccb97706efe Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 13:43:57 +0800 Subject: [PATCH 15/21] refactor(vscode): always show status bar item with ownership state --- extensions/vscode/src/statusbar.ts | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/extensions/vscode/src/statusbar.ts b/extensions/vscode/src/statusbar.ts index e3c872a..758ece4 100644 --- a/extensions/vscode/src/statusbar.ts +++ b/extensions/vscode/src/statusbar.ts @@ -62,23 +62,22 @@ export class StatusBarManager implements vscode.Disposable { try { const info = await this.client.getFileOwnership(fileUri); - if (info) { - if (info.is_unowned || info.owners.length === 0) { - this.statusBarItem.text = '$(alert)'; - this.statusBarItem.tooltip = 'No CODEOWNERS'; - this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); - } else { - this.statusBarItem.text = '$(lock)'; - this.statusBarItem.tooltip = 'Has CODEOWNERS'; - this.statusBarItem.backgroundColor = undefined; - } - this.statusBarItem.show(); + if (info && !info.is_unowned && info.owners.length > 0) { + this.statusBarItem.text = '$(lock)'; + this.statusBarItem.tooltip = 'Has CODEOWNERS'; + this.statusBarItem.backgroundColor = undefined; } else { - this.statusBarItem.hide(); + this.statusBarItem.text = '$(alert)'; + this.statusBarItem.tooltip = 'No CODEOWNERS'; + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); } + this.statusBarItem.show(); } catch (error) { console.error('Error updating status bar:', error); - this.statusBarItem.hide(); + this.statusBarItem.text = '$(alert)'; + this.statusBarItem.tooltip = 'No CODEOWNERS'; + this.statusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground'); + this.statusBarItem.show(); } } From f2399f7cb66fe5ad2ccaac382399c5fb9d03ec87 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 14:57:26 +0800 Subject: [PATCH 16/21] chore(vscode): prepare v0.1.0 release with docs and metadata --- extensions/vscode/.gitignore | 4 ++ extensions/vscode/.vscodeignore | 2 + extensions/vscode/.yarnrc.yml | 1 + extensions/vscode/CHANGELOG.md | 13 ++++++ extensions/vscode/LICENSE | 21 ++++++++++ extensions/vscode/README.md | 65 +++++++++++++++++++++++++++++ extensions/vscode/icon.png | Bin 0 -> 1634 bytes extensions/vscode/package.json | 33 +++++---------- extensions/vscode/src/extension.ts | 18 -------- 9 files changed, 116 insertions(+), 41 deletions(-) create mode 100644 extensions/vscode/.yarnrc.yml create mode 100644 extensions/vscode/CHANGELOG.md create mode 100644 extensions/vscode/LICENSE create mode 100644 extensions/vscode/README.md create mode 100644 extensions/vscode/icon.png diff --git a/extensions/vscode/.gitignore b/extensions/vscode/.gitignore index d61721c..d67180e 100644 --- a/extensions/vscode/.gitignore +++ b/extensions/vscode/.gitignore @@ -22,6 +22,7 @@ Thumbs.db # IDE .idea/ +.vscode/ *.swp *.swo @@ -31,3 +32,6 @@ coverage/ # Temporary files *.tmp *.temp + +# Yarn cache +.yarn/ diff --git a/extensions/vscode/.vscodeignore b/extensions/vscode/.vscodeignore index 1681d2e..d35f90a 100644 --- a/extensions/vscode/.vscodeignore +++ b/extensions/vscode/.vscodeignore @@ -15,3 +15,5 @@ vsc-extension-quickstart.md **/*.map **/*.ts *.vsix +codeinput-*.vsix +favicon.svg diff --git a/extensions/vscode/.yarnrc.yml b/extensions/vscode/.yarnrc.yml new file mode 100644 index 0000000..3186f3f --- /dev/null +++ b/extensions/vscode/.yarnrc.yml @@ -0,0 +1 @@ +nodeLinker: node-modules diff --git a/extensions/vscode/CHANGELOG.md b/extensions/vscode/CHANGELOG.md new file mode 100644 index 0000000..d83a612 --- /dev/null +++ b/extensions/vscode/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [0.1.0] - 2026-03-07 + +### Added +- Initial release +- LSP-based CODEOWNERS integration +- Status bar ownership indicator +- File ownership info command +- Automatic binary download +- Tag support for CODEOWNERS diff --git a/extensions/vscode/LICENSE b/extensions/vscode/LICENSE new file mode 100644 index 0000000..3781661 --- /dev/null +++ b/extensions/vscode/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Abid Omar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/extensions/vscode/README.md b/extensions/vscode/README.md new file mode 100644 index 0000000..b0bc7f4 --- /dev/null +++ b/extensions/vscode/README.md @@ -0,0 +1,65 @@ +# CodeInput - CODEOWNERS Integration for VS Code + +A Language Server Protocol (LSP) based extension that provides CODEOWNERS integration for Visual Studio Code. Automatically displays ownership information and tags for files in your workspace. + +## Features + +- **Status Bar Integration**: Shows ownership status at a glance with lock/alert icons +- **File Ownership Info**: View owners and tags for any file via command palette +- **Multi-format Support**: Works with GitHub, GitLab, and Bitbucket CODEOWNERS file locations +- **Tag Support**: Extended CODEOWNERS syntax with tag support (e.g., `*.rs @team #backend #critical`) +- **Automatic Binary Management**: Downloads the required LSP server binary automatically + +## Requirements + +The extension requires the `ci-lsp` binary. It will attempt to download it automatically, or you can specify a custom path in settings. + +## Installation + +1. Install the extension from the VS Code Marketplace +2. Open a workspace containing a CODEOWNERS file +3. The extension will activate automatically + +## Configuration + +| Setting | Description | Default | +| --------------------------- | --------------------------------------- | ------------------- | +| `codeinput.binaryPath` | Path to the codeinput LSP server binary | `ci-lsp` | +| `codeinput.cacheFile` | Name of the cache file | `.codeowners.cache` | +| `codeinput.showInStatusBar` | Show CODEOWNERS info in status bar | `true` | +| `codeinput.showDiagnostics` | Show diagnostics for unowned files | `true` | +| `codeinput.lspTransport` | Transport method for LSP (stdio/tcp) | `stdio` | +| `codeinput.lspPort` | TCP port for LSP communication | `8123` | + +## Commands + +| Command | Description | +| -------------------------------------------------- | ------------------------------------------- | +| `CodeInput: Show CODEOWNERS Info for Current File` | Display owners and tags for the active file | +| `CodeInput: Refresh CODEOWNERS Cache` | Force refresh the ownership cache | + +## CODEOWNERS File Locations + +The extension monitors these locations for CODEOWNERS files: + +- `CODEOWNERS` (root) +- `.github/CODEOWNERS` +- `.gitlab/CODEOWNERS` +- `docs/CODEOWNERS` + +## Extended Syntax + +CodeInput supports an extended CODEOWNERS syntax with tags: + +``` +# Standard GitHub syntax +*.rs @rust-team + +# Extended syntax with tags +src/api/** @backend-team #api #critical +*.md @docs-team #documentation +``` + +## License + +MIT diff --git a/extensions/vscode/icon.png b/extensions/vscode/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..7cc06ce75800cd65941a1d88ac00315ba016ce3c GIT binary patch literal 1634 zcmZ{kdo&Y#7{`Be$)vGT5nXtr5@w8HR+M3jvY$9&#R~~^_$VW$OgR z11_9G|8GgA*Y8vWxRpG9oZj7xca+m;K4MEBD@gV~j zgOO*KDG_rSlc?O~xO*IIIyS&0F{0*|1AdrHq`D-s8q0u zuv8a)jN{T!F2`IxcJF(-YR#YXj`?VQe#3SqoN%4sCPUg6=`VPrKzIPz?mK$Q%ph6R%-(!N ze*DbmZb;gaPnsg@@5pmnF9(bR^`Gsl9N2o`#w#TcNl^E`Y00|Zs3IMm)ThK^4%zHr z-SYI%4dHXYT0Ltjo8(}i3&YF~FkK-bnOf-#afseaN+?BnhudypWoO9B**+fH01Ve; zNZiXX*AFDghMfwe!b;VL4R?eVuPjdBOCmQ-{(#{1UN)9$SAUMHf*d|zXYv|$<^F7g zvf`9hvyOfV#6eHdCB_})APq&Tf6=TBmCS3scsbTI2Cj)3k-HsE-T*34`t51oTVQJZ z#-{FAg1inz!D3D`DfszVh8Md$Z2Zqqi5q70jDTt5f^3eEwR*M)kz?$;`L274b5}4< zbTf1})EVL*s!q}^CPLIq?aR=;u$_|D=c3Z8+S{C`mwT^8vZ{Of>@~P?r5pdL>DiS8 z8t({dJhr&)k5sjP*wk04SEU)`npOO7BpgIQN6KK^WQnZIiuG37KAQ^oM%j08< zJ}4GTf|UAQzU_0t?^f&(MS*AI;rX1-+*>5D6fi}{YQ<~?ndPhP3O94=r{8a}FMUvq z2k^{{8FS`cqin-({fQH%m-6?>;Jcm*>a8P^2K?{h%GHaL2rm=FEf5Q3#aUR1M3fWh*FNF+farO{>o RaIXU5B3K>8aSwZ*{}(-6#*Y91 literal 0 HcmV?d00001 diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index e7770d5..3bf9eb1 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -2,9 +2,18 @@ "name": "codeinput", "displayName": "CodeInput - CODEOWNERS Integration", "description": "LSP-based CODEOWNERS integration for VS Code", - "version": "0.0.1", + "version": "0.1.0", "publisher": "codeinput", "license": "MIT", + "icon": "icon.png", + "repository": { + "type": "git", + "url": "https://github.com/code-input/cli.git" + }, + "bugs": { + "url": "https://github.com/code-input/cli/issues" + }, + "homepage": "https://github.com/code-input/cli#readme", "engines": { "vscode": "^1.74.0" }, @@ -27,16 +36,6 @@ "main": "./out/extension.js", "contributes": { "commands": [ - { - "command": "codeinput.showOwners", - "title": "Show CODEOWNERS Owners", - "category": "CodeInput" - }, - { - "command": "codeinput.showTags", - "title": "Show CODEOWNERS Tags", - "category": "CodeInput" - }, { "command": "codeinput.refreshCache", "title": "Refresh CODEOWNERS Cache", @@ -86,18 +85,6 @@ "description": "TCP port for LSP communication (when using tcp transport)" } } - }, - "menus": { - "commandPalette": [ - { - "command": "codeinput.showOwners", - "when": "false" - }, - { - "command": "codeinput.showTags", - "when": "false" - } - ] } }, "scripts": { diff --git a/extensions/vscode/src/extension.ts b/extensions/vscode/src/extension.ts index 2c64616..166c8a6 100644 --- a/extensions/vscode/src/extension.ts +++ b/extensions/vscode/src/extension.ts @@ -108,24 +108,6 @@ export async function activate(context: vscode.ExtensionContext) { }) ); - context.subscriptions.push( - vscode.commands.registerCommand('codeinput.showOwners', (uri: string, owners: any[]) => { - if (owners && owners.length > 0) { - const ownerList = owners.map(o => o.identifier).join(', '); - vscode.window.showInformationMessage(`Owners: ${ownerList}`); - } - }) - ); - - context.subscriptions.push( - vscode.commands.registerCommand('codeinput.showTags', (uri: string, tags: any[]) => { - if (tags && tags.length > 0) { - const tagList = tags.map(t => `#${t}`).join(', '); - vscode.window.showInformationMessage(`Tags: ${tagList}`); - } - }) - ); - // Handle configuration changes context.subscriptions.push( vscode.workspace.onDidChangeConfiguration(e => { From 97933f3dd561d323624fdbf9eb5db5557450a238 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 16:24:20 +0800 Subject: [PATCH 17/21] chore: release version 0.1.0 --- CHANGELOG.md | 27 +++++++++++++++++++++++++-- README.md | 12 ++++++------ ci/Cargo.toml | 4 ++-- codeinput/Cargo.toml | 2 +- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 120e748..fc98f17 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,28 @@ All notable changes to this project will be documented in this file. -## [0.0.5] - 2025-03-02 +## [0.1.0] - 2026-03-07 ### Added + +- **VS Code Extension**: Companion extension for Visual Studio Code with LSP integration +- **Neovim Plugin**: Full Neovim support with telescope integration for browsing files by ownership +- **Vim Plugin**: Vim plugin for CODEOWNERS LSP integration +- **LSP Enhancements**: + - Inlay hints support for CODEOWNERS patterns + - Custom commands: `listFiles`, `listOwners`, `listTags`, `getFileOwnership` + - TCP transport support (`ci lsp --port `) + +### Changed + +- Refactored LSP server into modular structure for better maintainability +- Simplified VS Code extension by removing unused features +- Improved telescope file pickers with proper entry makers + +## [0.0.5] - 2026-03-02 + +### Added + - **LSP Server**: Language Server Protocol implementation for IDE integration - `textDocument/hover`: Shows owners and tags when hovering over files - `textDocument/codeLens`: Displays ownership annotations above files @@ -14,20 +33,24 @@ All notable changes to this project will be documented in this file. - **VS Code Extension**: Companion extension for Visual Studio Code (in `vscode-extension/`) ### Changed + - Upgraded `utoipa` to 5.4.0 with schema fixes - LSP feature is now opt-in via `--features lsp` cargo flag ### Fixed + - Safe serialization of CodeLens arguments - Output redirected to stderr for LSP compatibility -## [0.0.4] - 2024-12-XX +## [0.0.4] - 2025-12-XX ### Added + - `infer-owners` command for intelligent owner inference - ARM64 runners for release builds (Linux, Windows, macOS) ### Changed + - Dependency updates and formatting improvements ## [0.0.3] - Previous Release diff --git a/README.md b/README.md index 26f6dc6..6a48d06 100644 --- a/README.md +++ b/README.md @@ -59,13 +59,13 @@ ### Pre-built Binaries -**Latest Release: `0.0.4`** +**Latest Release: `0.1.0`** -- **Linux x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-linux-x86_64) -- **Linux ARM64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-linux-aarch64) -- **Windows x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-windows-x86_64.exe) -- **macOS Intel**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-macos-x86_64) -- **macOS Apple Silicon**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.0.4/ci-macos-aarch64) +- **Linux x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-linux-x86_64) +- **Linux ARM64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-linux-aarch64) +- **Windows x86_64**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-windows-x86_64.exe) +- **macOS Intel**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-macos-x86_64) +- **macOS Apple Silicon**: [Download](https://github.com/CodeInputCorp/cli/releases/download/v0.1.0/ci-macos-aarch64) #### Installation Instructions diff --git a/ci/Cargo.toml b/ci/Cargo.toml index 0e37b2e..a8346b2 100644 --- a/ci/Cargo.toml +++ b/ci/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ci" -version = "0.0.5" +version = "0.1.0" authors = ["Abid Omar "] edition = "2021" repository = "https://github.com/code-input/cli" @@ -24,7 +24,7 @@ syslog = ["codeinput/syslog"] lsp = ["codeinput/tower-lsp", "codeinput/tokio", "tokio"] [dependencies] -codeinput = { version = "0.0.5", path = "../codeinput" } +codeinput = { version = "0.1.0", path = "../codeinput" } human-panic = { workspace = true } better-panic = { workspace = true } log = { workspace = true } diff --git a/codeinput/Cargo.toml b/codeinput/Cargo.toml index ed7f8a8..e021398 100644 --- a/codeinput/Cargo.toml +++ b/codeinput/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "codeinput" -version = "0.0.5" +version = "0.1.0" authors = ["Abid Omar "] edition = "2021" repository = "https://github.com/code-input/cli" From 6a2f176c49371e7aa3646a6c1bc87e78405d4a52 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 17:28:54 +0800 Subject: [PATCH 18/21] chore: fix release action --- .github/workflows/release.yml | 96 ++++++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 18 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d319644..f90cb36 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -116,25 +116,85 @@ jobs: with: path: artifacts - - name: Create Release and Upload Assets + - name: Remove Same Release + uses: omarabid-forks/action-rollback@stable + continue-on-error: true + with: + tag: ${{ steps.vars.outputs.package_version }} env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - TAG: ${{ steps.vars.outputs.package_version }} - PACKAGE_NAME: ${{ steps.vars.outputs.package_name }} - run: | - # Delete existing release if exists - gh release delete "$TAG" --yes || true - - # Create release - gh release create "$TAG" \ - --title "Version $TAG" \ - --notes "$PACKAGE_NAME - $TAG" \ - artifacts/ci-linux-x86_64/ci \ - artifacts/ci-linux-aarch64/ci \ - artifacts/ci-windows-x86_64.exe/ci.exe \ - artifacts/ci-windows-aarch64.exe/ci.exe \ - artifacts/ci-macos-x86_64/ci \ - artifacts/ci-macos-aarch64/ci + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Create Release + id: create-release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.vars.outputs.package_version }} + release_name: ${{ steps.vars.outputs.package_name }} ${{ steps.vars.outputs.package_version }} + body: ${{ steps.vars.outputs.package_name }} - ${{ steps.vars.outputs.package_version }} + draft: false + prerelease: false + + - name: Upload Linux x86_64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-linux-x86_64/ci + asset_name: ci-linux-x86_64 + asset_content_type: application/octet-stream + + - name: Upload Linux aarch64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-linux-aarch64/ci + asset_name: ci-linux-aarch64 + asset_content_type: application/octet-stream + + - name: Upload Windows x86_64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-windows-x86_64.exe/ci.exe + asset_name: ci-windows-x86_64.exe + asset_content_type: application/octet-stream + + - name: Upload Windows aarch64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-windows-aarch64.exe/ci.exe + asset_name: ci-windows-aarch64.exe + asset_content_type: application/octet-stream + + - name: Upload macOS x86_64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-macos-x86_64/ci + asset_name: ci-macos-x86_64 + asset_content_type: application/octet-stream + + - name: Upload macOS aarch64 binary + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: artifacts/ci-macos-aarch64/ci + asset_name: ci-macos-aarch64 + asset_content_type: application/octet-stream - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1 From 1f23b8e01b6a7911e634b2e7eb4ee25634b54f5f Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Sat, 7 Mar 2026 19:17:12 +0800 Subject: [PATCH 19/21] fix: release action --- .github/workflows/release-lsp.yml | 83 ++++++++++++++----------------- 1 file changed, 37 insertions(+), 46 deletions(-) diff --git a/.github/workflows/release-lsp.yml b/.github/workflows/release-lsp.yml index e087de1..e55ce2b 100644 --- a/.github/workflows/release-lsp.yml +++ b/.github/workflows/release-lsp.yml @@ -1,14 +1,31 @@ name: Release LSP on: - push: - tags: - - '*' + workflow_run: + workflows: ["Release"] + types: + - completed jobs: + get-tag: + name: Get Release Tag + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion == 'success' }} + outputs: + tag: ${{ steps.get-tag.outputs.tag }} + steps: + - name: Get tag from latest release + id: get-tag + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + TAG=$(gh api repos/${{ github.repository }}/releases/latest --jq '.tag_name') + echo "tag=$TAG" >> $GITHUB_OUTPUT + release: name: Release LSP - ${{ matrix.os }} (${{ matrix.arch }}) runs-on: ${{ matrix.runner }} + needs: get-tag strategy: matrix: include: @@ -52,13 +69,8 @@ jobs: steps: - name: Checkout Source uses: actions/checkout@v4 - - - name: Set variables - id: vars - shell: bash - run: | - echo "package_name=$(sed -En 's/name[[:space:]]*=[[:space:]]*"([^"]+)"/\1/p' Cargo.toml | head -1)" >> $GITHUB_OUTPUT - echo "package_version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + with: + ref: ${{ needs.get-tag.outputs.tag }} - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable @@ -97,51 +109,30 @@ jobs: name: ${{ matrix.asset_name }} path: target/${{ matrix.target }}/release/${{ matrix.binary_name }} - create-release: - name: Create LSP Release + upload-lsp-binaries: + name: Upload LSP Binaries runs-on: ubuntu-latest - needs: release + needs: [get-tag, release] steps: - - name: Checkout Source - uses: actions/checkout@v4 - - - name: Set variables - id: vars + - name: Get upload URL + id: get-upload-url + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - echo "package_name=$(sed -En 's/name[[:space:]]*=[[:space:]]*"([^"]+)"/\1/p' Cargo.toml | head -1)" >> $GITHUB_OUTPUT - echo "package_version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + UPLOAD_URL=$(gh release view ${{ needs.get-tag.outputs.tag }} --json uploadUrl --jq '.uploadUrl') + echo "upload_url=$UPLOAD_URL" >> $GITHUB_OUTPUT - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - - name: Remove Same Release - uses: omarabid-forks/action-rollback@stable - continue-on-error: true - with: - tag: ${{ steps.vars.outputs.package_version }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Create Release - id: create-release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.vars.outputs.package_version }} - release_name: LSP Server ${{ steps.vars.outputs.package_version }} - body: ${{ steps.vars.outputs.package_name }} LSP Server - ${{ steps.vars.outputs.package_version }} - draft: false - prerelease: false - - name: Upload Linux x64 binary uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-linux-x64/ci asset_name: ci-lsp-linux-x64 asset_content_type: application/octet-stream @@ -151,7 +142,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-linux-arm64/ci asset_name: ci-lsp-linux-arm64 asset_content_type: application/octet-stream @@ -161,7 +152,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-windows-x64.exe/ci.exe asset_name: ci-lsp-windows-x64.exe asset_content_type: application/octet-stream @@ -171,7 +162,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-windows-arm64.exe/ci.exe asset_name: ci-lsp-windows-arm64.exe asset_content_type: application/octet-stream @@ -181,7 +172,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-darwin-x64/ci asset_name: ci-lsp-darwin-x64 asset_content_type: application/octet-stream @@ -191,7 +182,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - upload_url: ${{ steps.create-release.outputs.upload_url }} + upload_url: ${{ steps.get-upload-url.outputs.upload_url }} asset_path: artifacts/ci-lsp-darwin-arm64/ci asset_name: ci-lsp-darwin-arm64 asset_content_type: application/octet-stream From 2eae0c394890d0bb772ad8c59852c89d8af5dd27 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 10 Mar 2026 20:26:29 +0800 Subject: [PATCH 20/21] chore: fix release action --- .github/workflows/release-lsp.yml | 65 +++++-------------------------- 1 file changed, 9 insertions(+), 56 deletions(-) diff --git a/.github/workflows/release-lsp.yml b/.github/workflows/release-lsp.yml index e55ce2b..ec7d1c0 100644 --- a/.github/workflows/release-lsp.yml +++ b/.github/workflows/release-lsp.yml @@ -1,6 +1,7 @@ name: Release LSP on: + workflow_dispatch: workflow_run: workflows: ["Release"] types: @@ -113,79 +114,31 @@ jobs: name: Upload LSP Binaries runs-on: ubuntu-latest needs: [get-tag, release] + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - - name: Get upload URL - id: get-upload-url - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - UPLOAD_URL=$(gh release view ${{ needs.get-tag.outputs.tag }} --json uploadUrl --jq '.uploadUrl') - echo "upload_url=$UPLOAD_URL" >> $GITHUB_OUTPUT - - name: Download all artifacts uses: actions/download-artifact@v4 with: path: artifacts - name: Upload Linux x64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-linux-x64/ci - asset_name: ci-lsp-linux-x64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-x64/ci --repo ${{ github.repository }} - name: Upload Linux arm64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-linux-arm64/ci - asset_name: ci-lsp-linux-arm64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-arm64/ci --repo ${{ github.repository }} - name: Upload Windows x64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-windows-x64.exe/ci.exe - asset_name: ci-lsp-windows-x64.exe - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-x64.exe/ci.exe --repo ${{ github.repository }} - name: Upload Windows arm64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-windows-arm64.exe/ci.exe - asset_name: ci-lsp-windows-arm64.exe - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-arm64.exe/ci.exe --repo ${{ github.repository }} - name: Upload macOS x64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-darwin-x64/ci - asset_name: ci-lsp-darwin-x64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-x64/ci --repo ${{ github.repository }} - name: Upload macOS arm64 binary - uses: actions/upload-release-asset@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ steps.get-upload-url.outputs.upload_url }} - asset_path: artifacts/ci-lsp-darwin-arm64/ci - asset_name: ci-lsp-darwin-arm64 - asset_content_type: application/octet-stream + run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-arm64/ci --repo ${{ github.repository }} - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1 From 70d723c69ed892c375f71f55c78dabad8304c7b2 Mon Sep 17 00:00:00 2001 From: Abid Omar Date: Tue, 10 Mar 2026 20:41:59 +0800 Subject: [PATCH 21/21] chore: fix release action --- .github/workflows/release-lsp.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-lsp.yml b/.github/workflows/release-lsp.yml index ec7d1c0..d93cc42 100644 --- a/.github/workflows/release-lsp.yml +++ b/.github/workflows/release-lsp.yml @@ -123,22 +123,34 @@ jobs: path: artifacts - name: Upload Linux x64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-x64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-linux-x64/ci ci-lsp-linux-x64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-linux-x64 --repo ${{ github.repository }} - name: Upload Linux arm64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-linux-arm64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-linux-arm64/ci ci-lsp-linux-arm64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-linux-arm64 --repo ${{ github.repository }} - name: Upload Windows x64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-x64.exe/ci.exe --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-windows-x64.exe/ci.exe ci-lsp-windows-x64.exe + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-windows-x64.exe --repo ${{ github.repository }} - name: Upload Windows arm64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-windows-arm64.exe/ci.exe --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-windows-arm64.exe/ci.exe ci-lsp-windows-arm64.exe + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-windows-arm64.exe --repo ${{ github.repository }} - name: Upload macOS x64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-x64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-darwin-x64/ci ci-lsp-darwin-x64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-darwin-x64 --repo ${{ github.repository }} - name: Upload macOS arm64 binary - run: gh release upload ${{ needs.get-tag.outputs.tag }} artifacts/ci-lsp-darwin-arm64/ci --repo ${{ github.repository }} + run: | + cp artifacts/ci-lsp-darwin-arm64/ci ci-lsp-darwin-arm64 + gh release upload ${{ needs.get-tag.outputs.tag }} ci-lsp-darwin-arm64 --repo ${{ github.repository }} - name: Purge artifacts uses: omarabid-forks/purge-artifacts@v1