From 4d1f7b6f0d535d88bce23e2fba16d8b9b40b9fac Mon Sep 17 00:00:00 2001 From: Seto Elkahfi <1797197+setoelkahfi@users.noreply.github.com> Date: Mon, 3 Aug 2026 11:10:52 +0200 Subject: [PATCH 1/2] Add --version flag to xcrs and document cargo install xcrs previously had no --version flag; `xcrs --version` errored. Add `#[command(version)]` so it reports its crate version, matching `smb` and the version recorded in the MCP registry. Also document that `xcrs` is installed via `cargo install xcrs` from crates.io, not Homebrew, since `brew install smbcloud-cli` ships only the `smb` binary. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- crates/xcrs/src/main.rs | 1 + docs/mcp.md | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/crates/xcrs/src/main.rs b/crates/xcrs/src/main.rs index 71edb8d..9f3b8ee 100644 --- a/crates/xcrs/src/main.rs +++ b/crates/xcrs/src/main.rs @@ -5,6 +5,7 @@ use xcrs::{IosAppTest, XcodeCommandLineTools}; #[derive(Debug, Parser)] #[command(name = "xcrs")] +#[command(version)] #[command(about = "Cross-platform mobile and TV app automation")] struct Cli { /// Run as a standalone Model Context Protocol server over stdio. diff --git a/docs/mcp.md b/docs/mcp.md index bf5e106..f681831 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -259,6 +259,12 @@ smb --mcp --scope automation xcrs --mcp ``` +> **Installing `xcrs`:** the standalone binary is published to +> [crates.io](https://crates.io/crates/xcrs) — install it with +> `cargo install xcrs`. It is **not** distributed through Homebrew; `brew +> install smbcloud-cli` only provides the `smb` binary (use `smb --mcp --scope +> automation` for the same tools without a separate install). + Both commands expose the same target-aware tools with the same names. Tool names do not repeat the server brand because MCP clients already namespace them by server. From 41cb0e29fdb5685a52e3c2d927c624828a2b3db8 Mon Sep 17 00:00:00 2001 From: Seto Elkahfi <1797197+setoelkahfi@users.noreply.github.com> Date: Mon, 3 Aug 2026 11:48:13 +0200 Subject: [PATCH 2/2] Add npm, NuGet, and PyPI distribution for the xcrs binary Extend the xcrs binary to ship through the same package managers as the smb CLI (npm, NuGet, PyPI), wired into the tag-driven release orchestration. crates.io already covers xcrs via cargo-workspaces publish. xcrs builds fully standalone (reqwest+rustls, no smbcloud-* or openssl deps), so its workflows drop CLI_CLIENT_SECRET, GH_OAUTH_*, OpenSSL vendoring, and the manylinux perl-core step. The binary name equals the crate name, so the PyPI package is simply 'xcrs' with no stub. - Scaffold npm/xcrs (@smbcloud/xcrs + platform packages), pypi-xcrs (xcrs), and nuget/xcrs (SmbCloud.Xcrs). - Generalize the npm package generators to take a product identity, keeping smb output byte-identical. - Add release-xcrs-{npm,nuget,pypi}.yml and fan them out from release-crate.yml's dispatch-distributions job. - Extend sync/check-release-versions scripts for the new manifests. Release Notes: - The xcrs MCP CLI can now be installed via npm (@smbcloud/xcrs), pip (xcrs), and dotnet tool (SmbCloud.Xcrs), in addition to cargo install xcrs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/release-crate.yml | 42 + .github/workflows/release-xcrs-npm.yml | 197 +++ .github/workflows/release-xcrs-nuget.yml | 285 ++++ .github/workflows/release-xcrs-pypi.yml | 204 +++ npm/scripts/render-main-package.cjs | 139 +- npm/scripts/render-platform-package.cjs | 6 +- npm/xcrs/.gitignore | 133 ++ npm/xcrs/README.md | 87 ++ npm/xcrs/package-lock.json | 1790 ++++++++++++++++++++++ npm/xcrs/package.json | 55 + npm/xcrs/src/index.ts | 43 + npm/xcrs/tsconfig.json | 12 + nuget/.gitignore | 3 + nuget/xcrs/Program.cs | 109 ++ nuget/xcrs/README.md | 59 + nuget/xcrs/Xcrs.csproj | 26 + pypi-xcrs/README.md | 93 ++ pypi-xcrs/pyproject.toml | 38 + scripts/check-release-versions.mjs | 11 + scripts/sync-release-version.mjs | 47 + 20 files changed, 3333 insertions(+), 46 deletions(-) create mode 100644 .github/workflows/release-xcrs-npm.yml create mode 100644 .github/workflows/release-xcrs-nuget.yml create mode 100644 .github/workflows/release-xcrs-pypi.yml create mode 100644 npm/xcrs/.gitignore create mode 100644 npm/xcrs/README.md create mode 100644 npm/xcrs/package-lock.json create mode 100644 npm/xcrs/package.json create mode 100644 npm/xcrs/src/index.ts create mode 100644 npm/xcrs/tsconfig.json create mode 100644 nuget/xcrs/Program.cs create mode 100644 nuget/xcrs/README.md create mode 100644 nuget/xcrs/Xcrs.csproj create mode 100644 pypi-xcrs/README.md create mode 100644 pypi-xcrs/pyproject.toml diff --git a/.github/workflows/release-crate.yml b/.github/workflows/release-crate.yml index 441188f..4fe0593 100644 --- a/.github/workflows/release-crate.yml +++ b/.github/workflows/release-crate.yml @@ -217,6 +217,48 @@ jobs: } }) + - name: Trigger npm XCRS release + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-xcrs-npm.yml', + ref: '${{ needs.publish.outputs.tag }}', + inputs: { + tag: '${{ needs.publish.outputs.tag }}' + } + }) + + - name: Trigger NuGet XCRS release + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-xcrs-nuget.yml', + ref: '${{ needs.publish.outputs.tag }}', + inputs: { + tag: '${{ needs.publish.outputs.tag }}' + } + }) + + - name: Trigger PyPI XCRS release + uses: actions/github-script@v7 + with: + script: | + await github.rest.actions.createWorkflowDispatch({ + owner: context.repo.owner, + repo: context.repo.repo, + workflow_id: 'release-xcrs-pypi.yml', + ref: '${{ needs.publish.outputs.tag }}', + inputs: { + tag: '${{ needs.publish.outputs.tag }}' + } + }) + dispatch-sdk-pypi: name: Trigger SDK PyPI release needs: publish diff --git a/.github/workflows/release-xcrs-npm.yml b/.github/workflows/release-xcrs-npm.yml new file mode 100644 index 0000000..0869b47 --- /dev/null +++ b/.github/workflows/release-xcrs-npm.yml @@ -0,0 +1,197 @@ +name: NPM XCRS Release + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag (e.g. v0.3.39)" + required: true + +permissions: + id-token: write + contents: read + +jobs: + publish-npm-binaries: + name: Publish NPM packages + runs-on: ${{ matrix.build.OS }} + strategy: + fail-fast: false + matrix: + build: + - { + NAME: linux-x64-glibc, + OS: ubuntu-latest, + TARGET: x86_64-unknown-linux-gnu, + } + - { + NAME: linux-arm64-glibc, + OS: ubuntu-24.04-arm, + TARGET: aarch64-unknown-linux-gnu, + } + - { + NAME: win32-x64-msvc, + OS: windows-2022, + TARGET: x86_64-pc-windows-msvc, + } + - { + NAME: win32-arm64-msvc, + OS: windows-2022, + TARGET: aarch64-pc-windows-msvc, + } + - { + NAME: darwin-x64, + OS: macos-15-intel, + TARGET: x86_64-apple-darwin, + } + - { + NAME: darwin-arm64, + OS: macos-latest, + TARGET: aarch64-apple-darwin, + } + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Read Rust toolchain + shell: bash + run: | + rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)" + if [ -z "$rust_toolchain" ]; then + echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2 + exit 1 + fi + + echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV" + + - name: Install toolkit + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + + - name: Install Rust target + shell: bash + run: | + rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }} + rustup target list --installed + + - name: Build + shell: bash + run: | + cargo build --release --locked --target ${{ matrix.build.TARGET }} --package xcrs + + - name: Install node + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + registry-url: "https://registry.npmjs.org" + + - name: Publish to NPM + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + shell: bash + run: | + # We want to name our npm package @smbcloud/xcrs, and the command is xcrs. + # All optional platform dependencies follow the @smbcloud/xcrs-${os}-${arch} + # naming convention. + + # Move to the npm directory + cd npm + # set the binary name, this is from the rust Cargo.toml file + cargo_bin="xcrs" + node_pkg_prefix="xcrs" + # derive the OS and architecture from the build matrix name + # note: when split by a hyphen, first part is the OS and the second is the architecture + node_os=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f1) + export node_os + node_arch=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f2) + export node_arch + # set the version + export node_version="${{ env.RELEASE_VERSION }}" + # set the package name + # note: use 'windows' as OS name instead of 'win32' + if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then + export node_pkg="${node_pkg_prefix}-windows-${node_arch}" + else + export node_pkg="${node_pkg_prefix}-${node_os}-${node_arch}" + fi + # create the package directory + mkdir -p "${node_pkg}/bin" + # generate package metadata + node ./scripts/render-platform-package.cjs "${node_pkg}" "${node_version}" "${node_os}" "${node_arch}" "Platform binary for the xcrs CLI." + # copy the binary into the package + # note: windows binaries has '.exe' extension + if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then + cargo_bin="${cargo_bin}.exe" + fi + cp "../target/${{ matrix.build.TARGET }}/release/${cargo_bin}" "${node_pkg}/bin" + # publish the package + cd "${node_pkg}" + npm_package_name="@smbcloud/${node_pkg}" + if npm view "${npm_package_name}@${node_version}" version >/dev/null 2>&1; then + echo "${npm_package_name}@${node_version} already exists on npm, skipping publish" + exit 0 + fi + npm publish --access public + + publish-npm-base: + name: Publish the base NPM package + needs: publish-npm-binaries + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Install node + uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + registry-url: "https://registry.npmjs.org" + + - name: Publish the package + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + shell: bash + run: | + cd npm/xcrs + + node ../scripts/render-main-package.cjs "./package.json" "${{ env.RELEASE_VERSION }}" xcrs + + npm_package_name="@smbcloud/xcrs" + npm_package_version="${{ env.RELEASE_VERSION }}" + if npm view "${npm_package_name}@${npm_package_version}" version >/dev/null 2>&1; then + echo "${npm_package_name}@${npm_package_version} already exists on npm, skipping publish" + exit 0 + fi + + npm install + npm run build + npm publish --access public diff --git a/.github/workflows/release-xcrs-nuget.yml b/.github/workflows/release-xcrs-nuget.yml new file mode 100644 index 0000000..c4c409f --- /dev/null +++ b/.github/workflows/release-xcrs-nuget.yml @@ -0,0 +1,285 @@ +name: NuGet XCRS Release + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag (e.g. v0.3.39)" + required: true + +permissions: + contents: read + +env: + CARGO_TERM_COLOR: always + DOTNET_VERSION: 8.0.x + NUGET_PACKAGE_ID: SmbCloud.Xcrs + +jobs: + build-native-binaries: + name: Build native binary (${{ matrix.build.NAME }}) + runs-on: ${{ matrix.build.OS }} + strategy: + fail-fast: false + matrix: + build: + - { + NAME: linux-x64, + OS: ubuntu-latest, + TARGET: x86_64-unknown-linux-gnu, + } + - { + NAME: linux-arm64, + OS: ubuntu-24.04-arm, + TARGET: aarch64-unknown-linux-gnu, + } + - { + NAME: windows-x64, + OS: windows-2022, + TARGET: x86_64-pc-windows-msvc, + } + - { + NAME: windows-arm64, + OS: windows-2022, + TARGET: aarch64-pc-windows-msvc, + } + - { + NAME: darwin-x64, + OS: macos-15-intel, + TARGET: x86_64-apple-darwin, + } + - { + NAME: darwin-arm64, + OS: macos-latest, + TARGET: aarch64-apple-darwin, + } + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Read Rust toolchain + shell: bash + run: | + rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)" + if [ -z "$rust_toolchain" ]; then + echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2 + exit 1 + fi + + echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV" + + - name: Install toolkit + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + targets: ${{ matrix.build.TARGET }} + + - name: Setup Rust cache + uses: Swatinem/rust-cache@v2 + with: + key: nuget-xcrs-${{ matrix.build.TARGET }} + + - name: Build + shell: bash + run: cargo build --release --locked --target ${{ matrix.build.TARGET }} --package xcrs + + - name: Prepare artifact + shell: bash + run: | + executable_name="xcrs" + if [[ "${{ matrix.build.OS }}" == "windows-2022" ]]; then + executable_name="xcrs.exe" + fi + + mkdir -p "nuget-artifacts/native/${{ matrix.build.NAME }}" + cp "target/${{ matrix.build.TARGET }}/release/${executable_name}" "nuget-artifacts/native/${{ matrix.build.NAME }}/${executable_name}" + + - name: Upload native artifact + uses: actions/upload-artifact@v7 + with: + name: nuget-xcrs-native-${{ matrix.build.NAME }} + path: nuget-artifacts/native + + pack-nuget: + name: Pack NuGet .NET tool + runs-on: ubuntu-latest + needs: build-native-binaries + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Download native artifacts + uses: actions/download-artifact@v7 + with: + pattern: nuget-xcrs-native-* + path: nuget/xcrs/native + merge-multiple: true + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Pack .NET tool + shell: bash + run: | + dotnet pack nuget/xcrs/Xcrs.csproj \ + --configuration Release \ + --output nuget/dist \ + -p:PackageVersion=${RELEASE_VERSION} + + - name: Upload package artifact + uses: actions/upload-artifact@v7 + with: + name: nuget-xcrs-package + path: nuget/dist/*.nupkg + + smoke-test: + name: Smoke test (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + needs: pack-nuget + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-2022 + - macos-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Download package artifact + uses: actions/download-artifact@v7 + with: + name: nuget-xcrs-package + path: nuget/dist + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Install tool from local package + shell: pwsh + run: | + $packageSource = (Resolve-Path "nuget/dist").Path + @" + + + + + + + + "@ | Set-Content -Path "nuget/NuGet.Config" + + dotnet tool install ` + --tool-path ".tool" ` + --configfile "nuget/NuGet.Config" ` + --version "$env:RELEASE_VERSION" ` + "$env:NUGET_PACKAGE_ID" + + - name: Run xcrs --version + shell: pwsh + run: | + $toolPath = if ($IsWindows) { ".\.tool\xcrs.exe" } else { "./.tool/xcrs" } + & $toolPath --version + + publish-nuget: + name: Publish to NuGet + runs-on: ubuntu-latest + needs: smoke-test + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Download package artifact + uses: actions/download-artifact@v7 + with: + name: nuget-xcrs-package + path: nuget/dist + + - name: Setup .NET SDK + uses: actions/setup-dotnet@v4 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Check whether release already exists on NuGet + id: nuget-check + shell: bash + run: | + package_index_url="https://api.nuget.org/v3-flatcontainer/smbcloud.xcrs/index.json" + if curl -fsS "${package_index_url}" | grep -F "\"${RELEASE_VERSION}\"" >/dev/null; then + echo "${NUGET_PACKAGE_ID} ${RELEASE_VERSION} already exists on NuGet, skipping publish" + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Publish package + if: steps.nuget-check.outputs.exists != 'true' + env: + NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }} + shell: bash + run: | + dotnet nuget push nuget/dist/*.nupkg \ + --api-key "${NUGET_API_KEY}" \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate diff --git a/.github/workflows/release-xcrs-pypi.yml b/.github/workflows/release-xcrs-pypi.yml new file mode 100644 index 0000000..cf5b111 --- /dev/null +++ b/.github/workflows/release-xcrs-pypi.yml @@ -0,0 +1,204 @@ +name: PyPI XCRS Release + +# Windows arm64 wheels are intentionally not built here. GitHub's hosted +# Windows runners provide x64 Python, and maturin refuses to build an arm64 +# wheel when the interpreter reports win-amd64. + +on: + workflow_dispatch: + inputs: + tag: + description: "Release tag (e.g. v0.3.39)" + required: true + +permissions: + id-token: write + contents: read + +env: + CARGO_TERM_COLOR: always + +jobs: + build-wheels: + name: Build PyPI wheels + runs-on: ${{ matrix.build.OS }} + strategy: + fail-fast: false + matrix: + build: + - { + NAME: linux-x64-glibc, + OS: ubuntu-latest, + TARGET: x86_64-unknown-linux-gnu, + MANYLINUX: "2014", + } + - { + NAME: linux-arm64-glibc, + OS: ubuntu-24.04-arm, + TARGET: aarch64-unknown-linux-gnu, + MANYLINUX: "2014", + } + - { + NAME: win32-x64-msvc, + OS: windows-2022, + TARGET: x86_64-pc-windows-msvc, + } + + - { NAME: darwin-x64, OS: macos-latest, TARGET: x86_64-apple-darwin } + - { + NAME: darwin-arm64, + OS: macos-latest, + TARGET: aarch64-apple-darwin, + } + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Read Rust toolchain + shell: bash + run: | + rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)" + if [ -z "$rust_toolchain" ]; then + echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2 + exit 1 + fi + + echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV" + + - name: Install toolkit + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + + - name: Install Rust target + shell: bash + run: | + rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }} + rustup target list --installed + + - name: Build wheel + uses: PyO3/maturin-action@v1 + with: + target: ${{ matrix.build.TARGET }} + manylinux: ${{ matrix.build.MANYLINUX || 'off' }} + working-directory: pypi-xcrs + args: --release --locked --compatibility pypi --out dist + + - name: Upload wheel artifact + uses: actions/upload-artifact@v7 + with: + name: wheels-${{ matrix.build.NAME }} + path: pypi-xcrs/dist/* + + build-sdist: + name: Build source distribution + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Read Rust toolchain + shell: bash + run: | + rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)" + if [ -z "$rust_toolchain" ]; then + echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2 + exit 1 + fi + + echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV" + + - name: Install toolkit + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: ${{ env.RUST_TOOLCHAIN }} + + - name: Build sdist + uses: PyO3/maturin-action@v1 + with: + command: sdist + working-directory: pypi-xcrs + args: --out dist + + - name: Upload sdist artifact + uses: actions/upload-artifact@v7 + with: + name: sdist + path: pypi-xcrs/dist/* + + publish-pypi: + name: Publish to PyPI + runs-on: ubuntu-latest + needs: + - build-wheels + - build-sdist + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ github.event.inputs.tag || github.ref }} + + - name: Set the release version + shell: bash + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + release_version="${GITHUB_REF_NAME#v}" + else + release_version="${{ github.event.inputs.tag }}" + release_version="${release_version#v}" + fi + + echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV" + + - name: Download distribution artifacts + uses: actions/download-artifact@v7 + with: + pattern: "*" + path: dist + merge-multiple: true + + - name: Check whether release already exists on PyPI + id: pypi-check + shell: bash + run: | + if curl -fsS "https://pypi.org/pypi/xcrs/${RELEASE_VERSION}/json" >/dev/null 2>&1; then + echo "xcrs ${RELEASE_VERSION} already exists on PyPI, skipping publish" + echo "exists=true" >> "$GITHUB_OUTPUT" + else + echo "exists=false" >> "$GITHUB_OUTPUT" + fi + + - name: Publish distribution + if: steps.pypi-check.outputs.exists != 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + skip-existing: true diff --git a/npm/scripts/render-main-package.cjs b/npm/scripts/render-main-package.cjs index 81b3c27..b7c5a82 100644 --- a/npm/scripts/render-main-package.cjs +++ b/npm/scripts/render-main-package.cjs @@ -3,51 +3,110 @@ const fs = require("fs"); const path = require("path"); -const [outputPath, version] = process.argv.slice(2); +const [outputPath, version, product = "smb"] = process.argv.slice(2); if (!outputPath || !version) { - throw new Error("Usage: render-main-package.cjs "); + throw new Error("Usage: render-main-package.cjs [product]"); +} + +// The five platform binary packages the wrapper resolves at runtime. Kept in +// lockstep with the release build matrix and the `optionalDependencies` below. +const platformSuffixes = [ + "darwin-arm64", + "darwin-x64", + "linux-x64", + "windows-arm64", + "windows-x64", +]; + +const products = { + smb: { + name: "@smbcloud/cli", + // Ownership proof for the MCP Registry: must match `name` in ../../server.json. + mcpName: "io.github.smbcloudXYZ/smbcloud-cli", + binName: "smb", + platformPrefix: "cli", + description: "A CLI for accessing the smbCloud platform.", + keywords: [ + "smbcloud", + "cli", + "smb", + "pndk", + "smbcloud-cli", + "cloud", + "smbcloud", + "developer", + "tools", + "web3", + "web3js", + "web3.js", + "web3js", + "bitcoin", + "btc", + "ethereum", + "solana", + "eth", + "sol", + "blockchain", + "smart-contracts", + "dapps", + "dapp", + "dapp-tools", + "dapp-tool", + "dapp-toolkit", + "dapp-toolkit-cli", + ], + }, + xcrs: { + name: "@smbcloud/xcrs", + // Ownership proof for the MCP Registry: must match `name` in ../../server-xcrs.json. + mcpName: "io.github.smbcloudXYZ/xcrs", + binName: "xcrs", + platformPrefix: "xcrs", + description: "Cross-platform mobile and TV app automation over MCP.", + keywords: [ + "xcrs", + "mcp", + "model-context-protocol", + "mobile", + "ios", + "android", + "tv", + "apple-tv", + "android-tv", + "automation", + "app-testing", + "device", + "simulator", + "adb", + "cli", + ], + }, +}; + +const selected = products[product]; + +if (!selected) { + throw new Error( + `Unknown product "${product}". Expected one of: ${Object.keys(products).join(", ")}.` + ); +} + +const optionalDependencies = {}; +for (const suffix of platformSuffixes) { + optionalDependencies[`@smbcloud/${selected.platformPrefix}-${suffix}`] = version; } const packageJson = { - name: "@smbcloud/cli", + name: selected.name, version, - // Ownership proof for the MCP Registry: must match `name` in ../../server.json. - mcpName: "io.github.smbcloudXYZ/smbcloud-cli", - keywords: [ - "smbcloud", - "cli", - "smb", - "pndk", - "smbcloud-cli", - "cloud", - "smbcloud", - "developer", - "tools", - "web3", - "web3js", - "web3.js", - "web3js", - "bitcoin", - "btc", - "ethereum", - "solana", - "eth", - "sol", - "blockchain", - "smart-contracts", - "dapps", - "dapp", - "dapp-tools", - "dapp-tool", - "dapp-toolkit", - "dapp-toolkit-cli", - ], + mcpName: selected.mcpName, + keywords: selected.keywords, bin: { - smb: "lib/index.js", + [selected.binName]: "lib/index.js", }, files: ["lib", "README.md"], - description: "A CLI for accessing the smbCloud platform.", + description: selected.description, license: "Apache-2.0", repository: { type: "git", @@ -67,13 +126,7 @@ const packageJson = { eslint: "^8.31.0", typescript: "^5.0.0", }, - optionalDependencies: { - "@smbcloud/cli-darwin-arm64": version, - "@smbcloud/cli-darwin-x64": version, - "@smbcloud/cli-linux-x64": version, - "@smbcloud/cli-windows-arm64": version, - "@smbcloud/cli-windows-x64": version, - }, + optionalDependencies, }; fs.writeFileSync(path.resolve(outputPath), `${JSON.stringify(packageJson, null, 2)} diff --git a/npm/scripts/render-platform-package.cjs b/npm/scripts/render-platform-package.cjs index 91c2338..12b8b65 100644 --- a/npm/scripts/render-platform-package.cjs +++ b/npm/scripts/render-platform-package.cjs @@ -3,11 +3,11 @@ const fs = require("fs"); const path = require("path"); -const [packageName, version, operatingSystem, architecture] = process.argv.slice(2); +const [packageName, version, operatingSystem, architecture, description] = process.argv.slice(2); if (!packageName || !version || !operatingSystem || !architecture) { throw new Error( - "Usage: render-platform-package.cjs " + "Usage: render-platform-package.cjs [description]" ); } @@ -18,7 +18,7 @@ fs.mkdirSync(packageDirectory, { recursive: true }); const packageJson = { name: `@smbcloud/${packageName}`, version, - description: "Platform binary for the smbCloud CLI.", + description: description || "Platform binary for the smbCloud CLI.", license: "Apache-2.0", repository: { type: "git", diff --git a/npm/xcrs/.gitignore b/npm/xcrs/.gitignore new file mode 100644 index 0000000..fe6424a --- /dev/null +++ b/npm/xcrs/.gitignore @@ -0,0 +1,133 @@ +# Typescript build artifacts +lib + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* \ No newline at end of file diff --git a/npm/xcrs/README.md b/npm/xcrs/README.md new file mode 100644 index 0000000..5bc35bc --- /dev/null +++ b/npm/xcrs/README.md @@ -0,0 +1,87 @@ + +

+

+ smbCloud Logo +
xcrs +

+

+ Cross-platform mobile and TV app automation over MCP. +
+
+ Website + · + Documentation + · + Releases + · + Issues +

+

+ npm + NuGet + PyPI + Crates.io + License +

+

+ +## About + +**`xcrs`** drives mobile and TV apps — on iOS simulators, physical Apple +devices, and adb-connected Android phones, tablets, emulators, and TVs — through +the [Model Context Protocol](https://modelcontextprotocol.io/). It is the +standalone automation profile of the [smbCloud CLI](https://smbcloud.xyz/); the +same tools are also available via `smb --mcp --scope automation`. + +This package installs the native `xcrs` executable for your platform directly — +no runtime dependencies. + +## Install + +```sh +npm install -g @smbcloud/xcrs +``` + +## Quick start + +Run it as an MCP server over stdio and point your MCP client at it: + +```sh +xcrs --mcp +``` + +**Recommended flow:** `device_list` → `device_select` → `device_capabilities`, +then inspect with `screen_capture` / `ui_describe` and drive with the `input_*` +tools. + +## Other installation methods + +- Cargo: `cargo install xcrs` +- pip: `pip install xcrs` +- NuGet: `dotnet tool install --global SmbCloud.Xcrs` + +## Platform support + +| Platform | Architecture | +| ------------- | ------------ | +| macOS | arm64, x64 | +| Linux (glibc) | arm64, x64 | +| Windows | arm64, x64 | + +The full Apple automation surface (`ui_describe`, `ui_element_list`, simulator +control) requires macOS with Xcode command-line tools. Android automation over +`adb` works from any platform. + +## Source + +- Repository: +- Documentation: +- Issues: + +## License + +Apache-2.0 + +## Copyright + +© 2026 [Splitfire AB](https://5mb.app) ([smbCloud](https://smbcloud.xyz)). diff --git a/npm/xcrs/package-lock.json b/npm/xcrs/package-lock.json new file mode 100644 index 0000000..829a4f5 --- /dev/null +++ b/npm/xcrs/package-lock.json @@ -0,0 +1,1790 @@ +{ + "name": "@smbcloud/xcrs", + "version": "0.5.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@smbcloud/xcrs", + "version": "0.5.0", + "license": "Apache-2.0", + "bin": { + "xcrs": "lib/index.js" + }, + "devDependencies": { + "@types/node": "^18.15.11", + "@typescript-eslint/eslint-plugin": "^5.48.0", + "@typescript-eslint/parser": "^5.48.0", + "eslint": "^8.31.0", + "typescript": "^5.0.0" + }, + "optionalDependencies": { + "@smbcloud/xcrs-darwin-arm64": "0.5.0", + "@smbcloud/xcrs-darwin-x64": "0.5.0", + "@smbcloud/xcrs-linux-x64": "0.5.0", + "@smbcloud/xcrs-windows-arm64": "0.5.0", + "@smbcloud/xcrs-windows-x64": "0.5.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", + "integrity": "sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@smbcloud/xcrs-darwin-arm64": { + "optional": true + }, + "node_modules/@smbcloud/xcrs-darwin-x64": { + "optional": true + }, + "node_modules/@smbcloud/xcrs-linux-x64": { + "optional": true + }, + "node_modules/@smbcloud/xcrs-windows-arm64": { + "optional": true + }, + "node_modules/@smbcloud/xcrs-windows-x64": { + "optional": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "18.19.130", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", + "integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.3.tgz", + "integrity": "sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.4.tgz", + "integrity": "sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/npm/xcrs/package.json b/npm/xcrs/package.json new file mode 100644 index 0000000..e64fb20 --- /dev/null +++ b/npm/xcrs/package.json @@ -0,0 +1,55 @@ +{ + "name": "@smbcloud/xcrs", + "version": "0.5.0", + "keywords": [ + "xcrs", + "mcp", + "model-context-protocol", + "mobile", + "ios", + "android", + "tv", + "apple-tv", + "android-tv", + "automation", + "app-testing", + "device", + "simulator", + "adb", + "cli" + ], + "bin": { + "xcrs": "lib/index.js" + }, + "files": [ + "lib", + "README.md" + ], + "description": "Cross-platform mobile and TV app automation over MCP.", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "git+https://github.com/smbcloudXYZ/smbcloud-cli.git" + }, + "scripts": { + "typecheck": "tsc --noEmit", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "build": "tsc", + "dev": "npm run build && node lib/index.js" + }, + "devDependencies": { + "@types/node": "^18.15.11", + "@typescript-eslint/eslint-plugin": "^5.48.0", + "@typescript-eslint/parser": "^5.48.0", + "eslint": "^8.31.0", + "typescript": "^5.0.0" + }, + "optionalDependencies": { + "@smbcloud/xcrs-darwin-arm64": "0.5.0", + "@smbcloud/xcrs-darwin-x64": "0.5.0", + "@smbcloud/xcrs-linux-x64": "0.5.0", + "@smbcloud/xcrs-windows-arm64": "0.5.0", + "@smbcloud/xcrs-windows-x64": "0.5.0" + } +} diff --git a/npm/xcrs/src/index.ts b/npm/xcrs/src/index.ts new file mode 100644 index 0000000..fcf04d9 --- /dev/null +++ b/npm/xcrs/src/index.ts @@ -0,0 +1,43 @@ +#!/usr/bin/env node + +import { spawnSync } from "child_process"; + +/** + * Returns the executable path which is located inside `node_modules` + * The naming convention is xcrs-${os}-${arch} + * If the platform is `win32` or `cygwin`, executable will include a `.exe` extension. + * @see https://nodejs.org/api/os.html#osarch + * @see https://nodejs.org/api/os.html#osplatform + * @example "x/xx/node_modules/xcrs-darwin-arm64" + */ +function getExePath() { + const arch = process.arch; + let os = process.platform as string; + let extension = ""; + if (["win32", "cygwin"].includes(process.platform)) { + os = "windows"; + extension = ".exe"; + } + + try { + // The binary lives in `node_modules`, so `require.resolve` gives us the installed path. + return require.resolve( + `@smbcloud/xcrs-${os}-${arch}/bin/xcrs${extension}`, + ); + } catch (e) { + throw new Error( + `Couldn't find application binary inside node_modules for ${os}-${arch}`, + ); + } +} + +/** + * Runs the native CLI with the current process arguments. + */ +function run() { + const args = process.argv.slice(2); + const processResult = spawnSync(getExePath(), args, { stdio: "inherit" }); + process.exit(processResult.status ?? 0); +} + +run(); diff --git a/npm/xcrs/tsconfig.json b/npm/xcrs/tsconfig.json new file mode 100644 index 0000000..8e6c790 --- /dev/null +++ b/npm/xcrs/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "es2016", + "module": "commonjs", + "esModuleInterop": true, + "baseUrl": "./", + "outDir": "lib", + "forceConsistentCasingInFileNames": true, + "strict": true, + "skipLibCheck": true + } +} diff --git a/nuget/.gitignore b/nuget/.gitignore index 4000aa6..91eadc6 100644 --- a/nuget/.gitignore +++ b/nuget/.gitignore @@ -2,3 +2,6 @@ dist/ smbcloud-cli/bin/ smbcloud-cli/obj/ smbcloud-cli/native/ +xcrs/bin/ +xcrs/obj/ +xcrs/native/ diff --git a/nuget/xcrs/Program.cs b/nuget/xcrs/Program.cs new file mode 100644 index 0000000..4cb8ddb --- /dev/null +++ b/nuget/xcrs/Program.cs @@ -0,0 +1,109 @@ +using System.ComponentModel; +using System.Diagnostics; +using System.Runtime.InteropServices; + +internal static class Program +{ + private const string CommandName = "xcrs"; + + public static async Task Main(string[] arguments) + { + try + { + string executablePath = ResolveExecutablePath(); + EnsureExecutablePermissions(executablePath); + return await RunAsync(executablePath, arguments); + } + catch (Exception exception) when ( + exception is FileNotFoundException or + PlatformNotSupportedException or + Win32Exception) + { + Console.Error.WriteLine($"{CommandName}: {exception.Message}"); + return 1; + } + } + + private static string ResolveExecutablePath() + { + string runtimeIdentifier = GetRuntimeIdentifier(); + string executableName = OperatingSystem.IsWindows() ? $"{CommandName}.exe" : CommandName; + string executablePath = Path.GetFullPath( + Path.Combine(AppContext.BaseDirectory, "native", runtimeIdentifier, executableName)); + + if (!File.Exists(executablePath)) + { + throw new FileNotFoundException( + $"The native {CommandName} executable for '{runtimeIdentifier}' is not bundled in this package.", + executablePath); + } + + return executablePath; + } + + private static string GetRuntimeIdentifier() + { + string operatingSystem = OperatingSystem.IsWindows() + ? "windows" + : OperatingSystem.IsMacOS() + ? "darwin" + : OperatingSystem.IsLinux() + ? "linux" + : throw new PlatformNotSupportedException( + $"{CommandName} does not support this operating system through the .NET tool package."); + + string architecture = RuntimeInformation.ProcessArchitecture switch + { + Architecture.X64 => "x64", + Architecture.Arm64 => "arm64", + _ => throw new PlatformNotSupportedException( + $"{CommandName} does not support the '{RuntimeInformation.ProcessArchitecture}' architecture through the .NET tool package."), + }; + + return $"{operatingSystem}-{architecture}"; + } + + private static void EnsureExecutablePermissions(string executablePath) + { + if (OperatingSystem.IsWindows()) + { + return; + } + + UnixFileMode currentMode = File.GetUnixFileMode(executablePath); + UnixFileMode requiredMode = UnixFileMode.UserRead | + UnixFileMode.UserWrite | + UnixFileMode.UserExecute | + UnixFileMode.GroupRead | + UnixFileMode.GroupExecute | + UnixFileMode.OtherRead | + UnixFileMode.OtherExecute; + + if ((currentMode & requiredMode) == requiredMode) + { + return; + } + + File.SetUnixFileMode(executablePath, currentMode | requiredMode); + } + + private static async Task RunAsync(string executablePath, IReadOnlyList arguments) + { + ProcessStartInfo startInfo = new(executablePath) + { + UseShellExecute = false, + WorkingDirectory = Environment.CurrentDirectory, + }; + + foreach (string argument in arguments) + { + startInfo.ArgumentList.Add(argument); + } + + using Process process = Process.Start(startInfo) + ?? throw new Win32Exception($"Failed to start '{CommandName}'."); + + await process.WaitForExitAsync(); + return process.ExitCode; + } +} diff --git a/nuget/xcrs/README.md b/nuget/xcrs/README.md new file mode 100644 index 0000000..95b5e7c --- /dev/null +++ b/nuget/xcrs/README.md @@ -0,0 +1,59 @@ +# xcrs for .NET + + + +`xcrs` drives mobile and TV apps — on iOS simulators, physical Apple devices, and +adb-connected Android phones, tablets, emulators, and TVs — through the +[Model Context Protocol](https://modelcontextprotocol.io/). It is the standalone +automation profile of the [smbCloud CLI](https://smbcloud.xyz/). + +## Install + +```sh +dotnet tool install --global SmbCloud.Xcrs +``` + +## Update + +```sh +dotnet tool update --global SmbCloud.Xcrs +``` + +## Quick start + +Run it as an MCP server over stdio and point your MCP client at it: + +```sh +xcrs --mcp +``` + +## Platform support + +This .NET tool bundles native `xcrs` binaries for: + +- macOS `arm64`, `x64` +- Linux `arm64`, `x64` (glibc) +- Windows `arm64`, `x64` + +The full Apple automation surface requires macOS with Xcode command-line tools. +Android automation over `adb` works from any platform. + +## Other installation methods + +- Cargo: `cargo install xcrs` +- npm: `npm install -g @smbcloud/xcrs` +- pip: `pip install xcrs` + +## Source + +- Repository: +- Documentation: +- Issues: + +## License + +Apache-2.0 + +## Copyright + +© 2026 [Splitfire AB](https://5mb.app) ([smbCloud](https://smbcloud.xyz)). diff --git a/nuget/xcrs/Xcrs.csproj b/nuget/xcrs/Xcrs.csproj new file mode 100644 index 0000000..1032377 --- /dev/null +++ b/nuget/xcrs/Xcrs.csproj @@ -0,0 +1,26 @@ + + + Exe + net8.0 + enable + enable + true + xcrs + SmbCloud.Xcrs + 0.5.0 + $(PackageVersion) + Seto Elkahfi + Cross-platform mobile and TV app automation over MCP. + README.md + Apache-2.0 + https://smbcloud.xyz/ + https://github.com/smbcloudXYZ/smbcloud-cli + mcp;mobile;ios;android;tv;automation;developer-tools;dotnet-tool + true + + + + + + + diff --git a/pypi-xcrs/README.md b/pypi-xcrs/README.md new file mode 100644 index 0000000..0129c8e --- /dev/null +++ b/pypi-xcrs/README.md @@ -0,0 +1,93 @@ + +

+

+ smbCloud Logo +
xcrs +

+

+ Cross-platform mobile and TV app automation over MCP. +
+
+ Website + · + Documentation + · + Releases + · + Issues +

+

+ PyPI + npm + NuGet + Crates.io + License +

+

+ +## About + +**`xcrs`** drives mobile and TV apps — on iOS simulators, physical Apple +devices, and adb-connected Android phones, tablets, emulators, and TVs — through +the [Model Context Protocol](https://modelcontextprotocol.io/). It is the +standalone automation profile of the [smbCloud CLI](https://smbcloud.xyz/); the +same tools are also available via `smb --mcp --scope automation`. + +This package installs the native `xcrs` executable for your platform directly — +no Node.js, no Docker, no runtime dependencies. + +## Install + +```sh +pip install xcrs +``` + +Or run it without installing: + +```sh +uvx xcrs --mcp +``` + +## Quick start + +Run it as an MCP server over stdio and point your MCP client at it: + +```sh +xcrs --mcp +``` + +**Recommended flow:** `device_list` → `device_select` → `device_capabilities`, +then inspect with `screen_capture` / `ui_describe` and drive with the `input_*` +tools. + +## Other installation methods + +- Cargo: `cargo install xcrs` +- npm: `npm install -g @smbcloud/xcrs` +- NuGet: `dotnet tool install --global SmbCloud.Xcrs` + +## Platform support + +| Platform | Architecture | +| ------------- | ------------ | +| macOS | arm64, x64 | +| Linux (glibc) | arm64, x64 | +| Windows | x64 | + +The full Apple automation surface (`ui_describe`, `ui_element_list`, simulator +control) requires macOS with Xcode command-line tools. Android automation over +`adb` works from any platform. + +## Source + +- Repository: +- Documentation: +- Issues: + +## License + +Apache-2.0 + +## Copyright + +© 2026 [Splitfire AB](https://5mb.app) ([smbCloud](https://smbcloud.xyz)). diff --git a/pypi-xcrs/pyproject.toml b/pypi-xcrs/pyproject.toml new file mode 100644 index 0000000..888e2c9 --- /dev/null +++ b/pypi-xcrs/pyproject.toml @@ -0,0 +1,38 @@ +[build-system] +requires = ["maturin>=1.7,<2.0"] +build-backend = "maturin" + +[project] +name = "xcrs" +description = "Cross-platform mobile and TV app automation over MCP." +readme = "README.md" +requires-python = ">=3.8" +dynamic = ["version"] +license = { text = "Apache-2.0" } +authors = [{ name = "Seto Elkahfi", email = "seto@smbcloud.xyz" }] +keywords = ["mcp", "mobile", "ios", "android", "tv", "automation", "adb", "cli"] +classifiers = [ + "Development Status :: 4 - Beta", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Operating System :: MacOS", + "Operating System :: Microsoft :: Windows", + "Operating System :: POSIX :: Linux", + "Programming Language :: Python :: 3", + "Programming Language :: Rust", + "Topic :: Software Development :: Testing", + "Topic :: Software Development :: Build Tools", + "Topic :: Utilities", +] + +[project.urls] +Homepage = "https://smbcloud.xyz/" +Documentation = "https://smbcloud.xyz/posts" +Repository = "https://github.com/smbcloudXYZ/smbcloud-cli" +Issues = "https://github.com/smbcloudXYZ/smbcloud-cli/issues" + +[tool.maturin] +manifest-path = "../crates/xcrs/Cargo.toml" +bindings = "bin" +strip = true diff --git a/scripts/check-release-versions.mjs b/scripts/check-release-versions.mjs index 188173f..0f59ee9 100644 --- a/scripts/check-release-versions.mjs +++ b/scripts/check-release-versions.mjs @@ -74,6 +74,13 @@ const npmLock = JSON.parse(read("npm/smbcloud-cli/package-lock.json")); check("npm/smbcloud-cli/package-lock.json", npmLock.version); check("npm/smbcloud-cli/package-lock.json packages root", npmLock.packages?.[""]?.version); +const npmXcrsPackage = JSON.parse(read("npm/xcrs/package.json")); +check("npm/xcrs/package.json", npmXcrsPackage.version); + +const npmXcrsLock = JSON.parse(read("npm/xcrs/package-lock.json")); +check("npm/xcrs/package-lock.json", npmXcrsLock.version); +check("npm/xcrs/package-lock.json packages root", npmXcrsLock.packages?.[""]?.version); + for (const path of ["server.json", "server-xcrs.json"]) { const server = JSON.parse(read(path)); check(path, server.version); @@ -86,6 +93,10 @@ check( "nuget/smbcloud-cli/SmbCloud.Cli.csproj", read("nuget/smbcloud-cli/SmbCloud.Cli.csproj").match(/([^<]+)<\/PackageVersion>/)?.[1], ); +check( + "nuget/xcrs/Xcrs.csproj", + read("nuget/xcrs/Xcrs.csproj").match(/([^<]+)<\/PackageVersion>/)?.[1], +); check( "sdk/gems/email/Gemfile.lock", read("sdk/gems/email/Gemfile.lock").match(/smbcloud-email \(([^)]+)\)/)?.[1], diff --git a/scripts/sync-release-version.mjs b/scripts/sync-release-version.mjs index 9f25f8f..5a4ea42 100644 --- a/scripts/sync-release-version.mjs +++ b/scripts/sync-release-version.mjs @@ -6,6 +6,9 @@ const cliCargoTomlPath = resolve(repoRoot, "crates/cli/Cargo.toml"); const npmCliPackageJsonPath = resolve(repoRoot, "npm/smbcloud-cli/package.json"); const npmCliPackageLockPath = resolve(repoRoot, "npm/smbcloud-cli/package-lock.json"); const nugetCliProjectPath = resolve(repoRoot, "nuget/smbcloud-cli/SmbCloud.Cli.csproj"); +const npmXcrsPackageJsonPath = resolve(repoRoot, "npm/xcrs/package.json"); +const npmXcrsPackageLockPath = resolve(repoRoot, "npm/xcrs/package-lock.json"); +const nugetXcrsProjectPath = resolve(repoRoot, "nuget/xcrs/Xcrs.csproj"); const sdkNpmPackageJsonPath = resolve(repoRoot, "sdk/npm/smbcloud-auth/package.json"); const authGemVersionPath = resolve(repoRoot, "sdk/gems/auth/lib/auth/version.rb"); const authGemCargoTomlPath = resolve(repoRoot, "sdk/gems/auth/ext/auth/Cargo.toml"); @@ -104,6 +107,50 @@ if ( updatedPaths.push(nugetCliProjectPath); } +if ( + updateFile(npmXcrsPackageJsonPath, (content) => { + const parsed = JSON.parse(content); + parsed.version = releaseVersion; + + for (const packageName of Object.keys(parsed.optionalDependencies ?? {})) { + parsed.optionalDependencies[packageName] = releaseVersion; + } + + return `${JSON.stringify(parsed, null, 2)}\n`; + }) +) { + updatedPaths.push(npmXcrsPackageJsonPath); +} + +if ( + updateFile(npmXcrsPackageLockPath, (content) => { + const parsed = JSON.parse(content); + parsed.version = releaseVersion; + parsed.packages[""].version = releaseVersion; + + for (const packageName of Object.keys(parsed.packages[""].optionalDependencies ?? {})) { + parsed.packages[""].optionalDependencies[packageName] = releaseVersion; + } + + return `${JSON.stringify(parsed, null, 2)}\n`; + }) +) { + updatedPaths.push(npmXcrsPackageLockPath); +} + +if ( + updateFile(nugetXcrsProjectPath, (content) => + replaceOrThrow( + content, + /[^<]+<\/PackageVersion>/, + `${releaseVersion}`, + `${nugetXcrsProjectPath} package version`, + ), + ) +) { + updatedPaths.push(nugetXcrsProjectPath); +} + if ( updateFile(sdkNpmPackageJsonPath, (content) => { const parsed = JSON.parse(content);