From d54d87a563d25ca4d6bdb79db518cd66d423a872 Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Mon, 18 May 2026 20:14:28 +0800 Subject: [PATCH 01/11] clean up release ppl --- .github/workflows/cli-release.yml | 69 +----------- cli/AGENTS.md | 2 +- cli/README.md | 33 ++---- cli/package.json | 3 +- cli/scripts/install-cli.ps1 | 149 ------------------------- cli/scripts/install-cli.sh | 104 ++++++++--------- cli/scripts/install-local.sh | 9 +- cli/scripts/release-bump-guard.sh | 54 --------- cli/scripts/release-cosign-sign.sh | 33 ------ cli/scripts/release-npm-publish.sh | 48 -------- cli/scripts/release-pack-tarballs.sh | 47 ++++++++ cli/scripts/release-upload-tarballs.sh | 99 ---------------- cli/scripts/release.sh | 38 ------- 13 files changed, 122 insertions(+), 566 deletions(-) delete mode 100644 cli/scripts/install-cli.ps1 delete mode 100755 cli/scripts/release-bump-guard.sh delete mode 100755 cli/scripts/release-cosign-sign.sh delete mode 100755 cli/scripts/release-npm-publish.sh create mode 100755 cli/scripts/release-pack-tarballs.sh delete mode 100755 cli/scripts/release-upload-tarballs.sh delete mode 100755 cli/scripts/release.sh diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 314a9819f6a3ef..7477a48c9f1da9 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -1,31 +1,18 @@ name: CLI Release on: - release: - types: [published] workflow_dispatch: - inputs: - dify_release_tag: - description: "dify release tag to attach cli artifacts to (e.g. 1.14.0). Bare semver — dify tags are NOT v-prefixed." - type: string - required: true concurrency: - group: cli-release-${{ github.event.release.tag_name || inputs.dify_release_tag }} + group: cli-release-${{ github.ref }} cancel-in-progress: true jobs: release: runs-on: depot-ubuntu-24.04 - if: >- - github.repository == 'langgenius/dify' && - (github.event_name == 'workflow_dispatch' || - (vars.CLI_AUTO_RELEASE == 'true' && !github.event.release.prerelease)) - env: - DIFY_TAG: ${{ github.event.release.tag_name || inputs.dify_release_tag }} + if: github.repository == 'langgenius/dify' permissions: - contents: write - id-token: write + contents: read defaults: run: shell: bash @@ -41,12 +28,6 @@ jobs: - name: Setup web environment uses: ./.github/actions/setup-web - - name: Setup Node registry auth - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 - with: - node-version-file: .nvmrc - registry-url: 'https://registry.npmjs.org' - - name: Read cli/package.json id: manifest run: | @@ -64,19 +45,6 @@ jobs: - name: Validate manifest run: scripts/release-validate-manifest.sh - - name: Bump guard (auto-path only) - if: github.event_name == 'release' - run: scripts/release-bump-guard.sh - env: - NEW_VERSION: ${{ steps.manifest.outputs.version }} - NEW_MIN_DIFY: ${{ steps.manifest.outputs.minDify }} - NEW_MAX_DIFY: ${{ steps.manifest.outputs.maxDify }} - - - name: Verify target dify release exists - run: gh release view "$DIFY_TAG" --repo langgenius/dify > /dev/null - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Build cli run: | DIFYCTL_VERSION="${{ steps.manifest.outputs.version }}" \ @@ -88,44 +56,19 @@ jobs: pnpm build - name: Pack tarballs - run: pnpm pack:tarballs - - - name: Publish to npm (idempotent) - run: scripts/release-npm-publish.sh - env: - CHANNEL: ${{ steps.manifest.outputs.channel }} - NEW_VERSION: ${{ steps.manifest.outputs.version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + run: CLI_VERSION=${{ steps.manifest.outputs.version }} pnpm pack:tarballs - name: Generate sha256 checksum file run: scripts/release-write-checksums.sh env: CLI_VERSION: ${{ steps.manifest.outputs.version }} - - name: Install cosign - uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 - - - name: Keyless-sign tarballs + checksum file (Sigstore) - run: scripts/release-cosign-sign.sh - env: - CLI_VERSION: ${{ steps.manifest.outputs.version }} - COSIGN_EXPERIMENTAL: '1' - - - name: Snapshot tarballs + checksum + signatures as workflow artifact - if: always() + - name: Upload tarballs + checksum as workflow artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: - name: difyctl-${{ steps.manifest.outputs.version }}-${{ env.DIFY_TAG }} + name: difyctl-${{ steps.manifest.outputs.version }} path: | cli/dist/difyctl-v*.tar.xz cli/dist/difyctl-v*-checksums.txt - cli/dist/difyctl-v*.sig - cli/dist/difyctl-v*.pem retention-days: 90 if-no-files-found: error - - - name: Upload tarballs + checksum + signatures to dify GH release (idempotent) - run: scripts/release-upload-tarballs.sh - env: - CLI_VERSION: ${{ steps.manifest.outputs.version }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/cli/AGENTS.md b/cli/AGENTS.md index ec929c689f7255..e55f2fa304fd5f 100644 --- a/cli/AGENTS.md +++ b/cli/AGENTS.md @@ -64,7 +64,7 @@ pnpm build # production bundle + oclif manif pnpm manifest # regenerate oclif.manifest.json only ``` -`make` covers `build` / `test` / `release` / `ci` as no-arg targets. Dev runs use `pnpm dev` directly. +Release tarballs are produced by `pnpm pack:tarballs` (called from `.github/workflows/cli-release.yml`). ## Tests diff --git a/cli/README.md b/cli/README.md index c2cfb9a06dd87b..6cf80747b0e10b 100644 --- a/cli/README.md +++ b/cli/README.md @@ -4,32 +4,23 @@ CLI client for [Dify] platform. Browser device-flow signin, list/inspect apps, r ## Install -### npm +Pre-release builds are published only as **GitHub Actions workflow artifacts** (no npm, no GitHub Release assets). The installer fetches the latest successful `cli-release.yml` run on `main`, verifies sha256, and extracts the tarball into `$HOME/.local`. ```sh -npm install -g @langgenius/difyctl +# GH_TOKEN with `actions:read` scope is required — workflow artifact downloads +# need auth even on public repos. +export GH_TOKEN= +curl -fsSL https://raw.githubusercontent.com/langgenius/dify/main/cli/scripts/install-cli.sh | sh ``` -### Tarball +| Env | Default | Purpose | +| ---------------- | ----------------- | --------------------------------------------------- | +| `GH_TOKEN` | — | GitHub PAT (or `GITHUB_TOKEN`) with `actions:read`. | +| `DIFYCTL_PREFIX` | `$HOME/.local` | Install root. Binary symlinked to `/bin`. | +| `DIFYCTL_REPO` | `langgenius/dify` | Source repo. | +| `DIFYCTL_BRANCH` | `main` | Branch to pick the latest successful run from. | -```sh -# macOS arm64 -curl -fsSL https://github.com/langgenius/dify/releases/latest/download/difyctl-darwin-arm64.tar.xz | tar xJ -C /usr/local -ln -sf /usr/local/difyctl/bin/difyctl /usr/local/bin/difyctl - -# Linux x64 -curl -fsSL https://github.com/langgenius/dify/releases/latest/download/difyctl-linux-x64.tar.xz | tar xJ -C /opt -ln -sf /opt/difyctl/bin/difyctl /usr/local/bin/difyctl -``` - -Other targets: `darwin-x64`, `linux-arm64`, `win32-x64`. - -### Container - -```sh -docker run --rm -it -v "$HOME/.config/difyctl:/root/.config/difyctl" \ - ghcr.io/langgenius/difyctl:latest version -``` +Targets: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`. Windows is not supported at this stage. ## Quickstart diff --git a/cli/package.json b/cli/package.json index 0a0a0c44b486c4..06a73073eb6957 100644 --- a/cli/package.json +++ b/cli/package.json @@ -40,7 +40,8 @@ "clean": "rm -rf dist node_modules/.cache", "version:info": "tsx scripts/print-buildinfo.ts", "docker:build-dev": "scripts/docker-build-dev.sh", - "sync-models": "scripts/sync-models.sh" + "sync-models": "scripts/sync-models.sh", + "pack:tarballs": "scripts/release-pack-tarballs.sh" }, "dependencies": { "@napi-rs/keyring": "catalog:", diff --git a/cli/scripts/install-cli.ps1 b/cli/scripts/install-cli.ps1 deleted file mode 100644 index da4a895edbc2de..00000000000000 --- a/cli/scripts/install-cli.ps1 +++ /dev/null @@ -1,149 +0,0 @@ -#Requires -Version 5.1 -<# -.SYNOPSIS - One-line difyctl installer for Windows. Verifies sha256 before extract. -.PARAMETER Version - Dify release tag. Defaults to the latest release. -.PARAMETER Prefix - Install root. Defaults to $env:LOCALAPPDATA\difyctl. -.PARAMETER Repo - Release source repo. Defaults to langgenius/dify. -#> -[CmdletBinding()] -param( - [string]$Version = $env:DIFYCTL_VERSION, - [string]$Prefix = $env:DIFYCTL_PREFIX, - [string]$Repo = $env:DIFYCTL_REPO -) - -$ErrorActionPreference = 'Stop' - -if ([string]::IsNullOrEmpty($Version)) { $Version = 'latest' } -if ([string]::IsNullOrEmpty($Prefix)) { $Prefix = Join-Path $env:LOCALAPPDATA 'difyctl' } -if ([string]::IsNullOrEmpty($Repo)) { $Repo = 'langgenius/dify' } - -function Fail($msg) { Write-Error "install-cli: $msg"; exit 1 } -function Need($cmd) { - if (-not (Get-Command $cmd -ErrorAction SilentlyContinue)) { Fail "$cmd is required" } -} -Need tar - -switch ($env:PROCESSOR_ARCHITECTURE) { - 'AMD64' { $arch = 'x64' } - 'ARM64' { $arch = 'arm64' } - default { Fail "unsupported arch: $env:PROCESSOR_ARCHITECTURE" } -} -$target = "win32-$arch" - -if ($Version -eq 'latest') { - $api = "https://api.github.com/repos/$Repo/releases/latest" -} else { - $api = "https://api.github.com/repos/$Repo/releases/tags/$Version" -} - -try { - $release = Invoke-RestMethod -Uri $api -UseBasicParsing -} catch { - Fail "could not fetch release metadata from $api $($_.Exception.Message)" -} - -$tag = $release.tag_name -if ([string]::IsNullOrEmpty($tag)) { Fail "release has no tag_name" } - -$assetRegex = "^difyctl-v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?-$target\.tar\.xz$" -$matches = @($release.assets | Where-Object { $_.name -match $assetRegex }) - -if ($matches.Count -eq 0) { Fail "no difyctl asset for $target on $tag" } -if ($matches.Count -gt 1) { - $names = ($matches | ForEach-Object { $_.name }) -join ', ' - Fail "expected exactly 1 difyctl asset for $target on $tag, found $($matches.Count): $names" -} -$asset = $matches[0].name - -$suffix = "-$target.tar.xz" -$cliV = $asset.Substring('difyctl-'.Length, $asset.Length - 'difyctl-'.Length - $suffix.Length) -$checksums = "difyctl-$cliV-checksums.txt" - -$checksumAsset = $release.assets | Where-Object { $_.name -eq $checksums } | Select-Object -First 1 -if ($null -eq $checksumAsset) { - Fail "checksum file $checksums missing on $tag; refusing to install unverified binary" -} - -$url = "https://github.com/$Repo/releases/download/$tag/$asset" -$sumsUrl = "https://github.com/$Repo/releases/download/$tag/$checksums" - -$tmp = Join-Path ([System.IO.Path]::GetTempPath()) ("difyctl-install-" + [guid]::NewGuid().ToString('N')) -New-Item -ItemType Directory -Path $tmp -Force | Out-Null -$tarPath = Join-Path $tmp $asset -$sumPath = Join-Path $tmp $checksums - -try { - Write-Host "downloading $asset" - Invoke-WebRequest -Uri $url -OutFile $tarPath -UseBasicParsing - Invoke-WebRequest -Uri $sumsUrl -OutFile $sumPath -UseBasicParsing - - $expected = (Get-Content $sumPath | Where-Object { $_ -match " $([Regex]::Escape($asset))$" } | Select-Object -First 1) - if ([string]::IsNullOrEmpty($expected)) { Fail "no checksum entry for $asset in $checksums" } - $expectedHash = ($expected -split '\s+')[0].ToLower() - $actualHash = (Get-FileHash -Algorithm SHA256 -Path $tarPath).Hash.ToLower() - if ($expectedHash -ne $actualHash) { - Fail "checksum mismatch for $asset (expected $expectedHash, got $actualHash)" - } - - if (Get-Command cosign -ErrorAction SilentlyContinue) { - $sigUrl = "$url.sig" - $pemUrl = "$url.pem" - $sigPath = Join-Path $tmp "$asset.sig" - $pemPath = Join-Path $tmp "$asset.pem" - try { - Invoke-WebRequest -Uri $sigUrl -OutFile $sigPath -UseBasicParsing - Invoke-WebRequest -Uri $pemUrl -OutFile $pemPath -UseBasicParsing - } catch { - Fail "tarball signature/cert missing on $tag; refusing to install (cosign present): $($_.Exception.Message)" - } - $env:COSIGN_EXPERIMENTAL = '1' - & cosign verify-blob ` - --certificate $pemPath ` - --signature $sigPath ` - --certificate-identity-regexp '^https://github.com/langgenius/dify/' ` - --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' ` - $tarPath - if ($LASTEXITCODE -ne 0) { Fail "cosign verification failed for $asset" } - Write-Host "cosign: verified $asset" - } else { - Write-Host "note: cosign not installed; skipping signature verification (sha256 still enforced)" - } - - $shareDir = Join-Path $Prefix 'share' - $binDir = Join-Path $Prefix 'bin' - New-Item -ItemType Directory -Path $shareDir -Force | Out-Null - New-Item -ItemType Directory -Path $binDir -Force | Out-Null - - Write-Host "extracting to $shareDir" - & tar.exe -xJf $tarPath -C $shareDir --strip-components=1 - if ($LASTEXITCODE -ne 0) { Fail "tar.exe failed with exit $LASTEXITCODE" } - - $sourceBin = Join-Path $shareDir 'bin\difyctl.cmd' - if (-not (Test-Path $sourceBin)) { $sourceBin = Join-Path $shareDir 'bin\difyctl.exe' } - if (-not (Test-Path $sourceBin)) { Fail "expected binary at bin\difyctl.{cmd,exe} after extract" } - - $shimSrc = Get-Item $sourceBin - Copy-Item -Path $sourceBin -Destination (Join-Path $binDir $shimSrc.Name) -Force -} -finally { - if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp } -} - -Write-Host "" -Write-Host "difyctl $cliV installed: $binDir" - -$userPath = [System.Environment]::GetEnvironmentVariable('Path', 'User') -if ($null -eq $userPath) { $userPath = '' } -if (-not ($userPath -split ';' | Where-Object { $_ -ieq $binDir })) { - $newPath = if ($userPath) { "$userPath;$binDir" } else { $binDir } - [System.Environment]::SetEnvironmentVariable('Path', $newPath, 'User') - Write-Host "added $binDir to user PATH (open a new terminal to pick it up)" -} -else { - Write-Host "verify: run 'difyctl version' in a new terminal" -} diff --git a/cli/scripts/install-cli.sh b/cli/scripts/install-cli.sh index c6eab92d52d0e5..04639b4a58d584 100755 --- a/cli/scripts/install-cli.sh +++ b/cli/scripts/install-cli.sh @@ -1,18 +1,22 @@ #!/bin/sh -# install-cli.sh — one-line difyctl installer for Linux and macOS. +# install-cli.sh — one-line difyctl installer from latest GitHub Actions build. # # usage: # curl -fsSL https://raw.githubusercontent.com/langgenius/dify/main/cli/scripts/install-cli.sh | sh # -# env: DIFYCTL_VERSION (default latest), DIFYCTL_PREFIX (default $HOME/.local), -# DIFYCTL_REPO (default langgenius/dify). -# requires: curl, tar (xz), uname, jq, sha256sum or shasum. +# env: DIFYCTL_PREFIX (default $HOME/.local), DIFYCTL_REPO (default langgenius/dify), +# DIFYCTL_BRANCH (default main), +# GH_TOKEN (required — GitHub workflow artifact zip downloads need auth even on public repos; +# minimum scope: actions:read). +# requires: curl, tar (xz), uname, jq, unzip, sha256sum or shasum. set -eu REPO="${DIFYCTL_REPO:-langgenius/dify}" -VERSION="${DIFYCTL_VERSION:-latest}" +BRANCH="${DIFYCTL_BRANCH:-main}" PREFIX="${DIFYCTL_PREFIX:-${HOME}/.local}" +WORKFLOW_FILE="cli-release.yml" +TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}" err() { printf '%s\n' "install-cli: $*" >&2; } die() { err "$*"; exit 1; } @@ -22,6 +26,11 @@ need curl need tar need uname need jq +need unzip + +[ -n "$TOKEN" ] || die "GH_TOKEN (or GITHUB_TOKEN) is required — workflow artifact downloads need auth" + +gh_curl() { curl -fsSL -H "Authorization: Bearer ${TOKEN}" -H "Accept: application/vnd.github.v3+json" "$@"; } if command -v sha256sum >/dev/null 2>&1; then HASH="sha256sum" @@ -45,79 +54,64 @@ esac target="${os}-${arch}" -if [ "$VERSION" = "latest" ]; then - api="https://api.github.com/repos/${REPO}/releases/latest" -else - api="https://api.github.com/repos/${REPO}/releases/tags/${VERSION}" -fi +# 1. Find the latest successful workflow run +api_url="https://api.github.com/repos/${REPO}/actions/workflows/${WORKFLOW_FILE}/runs?branch=${BRANCH}&status=success&per_page=1" +run_id=$(gh_curl "$api_url" | jq -r '.workflow_runs[0].id') -release=$(curl -fsSL "$api") || die "could not fetch release metadata from ${api}" -tag=$(printf '%s' "$release" | jq -r '.tag_name') -[ -n "$tag" ] && [ "$tag" != "null" ] || die "release has no tag_name" - -matches=$(printf '%s' "$release" \ - | jq -r --arg t "$target" '.assets[].name | select(test("^difyctl-v[0-9]+\\.[0-9]+\\.[0-9]+(-[0-9A-Za-z.-]+)?-\($t)\\.tar\\.xz$"))') -count=$(printf '%s' "$matches" | grep -c . || true) -case "$count" in - 0) die "no difyctl asset for ${target} on ${tag}" ;; - 1) asset="$matches" ;; - *) die "expected exactly 1 difyctl asset for ${target} on ${tag}, found ${count}: ${matches}" ;; -esac - -no_target="${asset%-${target}.tar.xz}" -cli_v="${no_target#difyctl-}" -checksums="difyctl-${cli_v}-checksums.txt" +if [ -z "$run_id" ] || [ "$run_id" = "null" ]; then + die "could not find a successful workflow run for ${WORKFLOW_FILE} on branch ${BRANCH}" +fi -printf '%s' "$release" | jq -e --arg c "$checksums" '.assets[] | select(.name == $c)' >/dev/null \ - || die "checksum file ${checksums} missing on ${tag}; refusing to install unverified binary" +# 2. Find the artifact from that run +artifacts_url="https://api.github.com/repos/${REPO}/actions/runs/${run_id}/artifacts" +artifact_info=$(gh_curl "$artifacts_url" | jq '.artifacts[0]') +artifact_id=$(printf '%s' "$artifact_info" | jq -r '.id') +artifact_name=$(printf '%s' "$artifact_info" | jq -r '.name') -url="https://github.com/${REPO}/releases/download/${tag}/${asset}" -sums_url="https://github.com/${REPO}/releases/download/${tag}/${checksums}" +if [ -z "$artifact_id" ] || [ "$artifact_id" = "null" ]; then + die "could not find any artifacts for workflow run ${run_id}" +fi +# 3. Download and unzip the artifact tmp=$(mktemp -d 2>/dev/null || mktemp -d -t difyctl-install) trap 'rm -rf "$tmp"' EXIT INT TERM -printf 'downloading %s\n from %s\n' "$asset" "$url" -curl -fsSL --retry 3 "$url" -o "${tmp}/${asset}" -curl -fsSL --retry 3 "$sums_url" -o "${tmp}/${checksums}" +download_url="https://api.github.com/repos/${REPO}/actions/artifacts/${artifact_id}/zip" +printf 'downloading artifact %s (run %s)...\n' "$artifact_name" "$run_id" +gh_curl -L "$download_url" -o "${tmp}/artifact.zip" + +unzip -q "${tmp}/artifact.zip" -d "${tmp}/artifact" + +# 4. Find the tarball + checksum file by target +asset_path=$(ls "${tmp}/artifact"/difyctl-v*-"${target}".tar.xz 2>/dev/null | head -1) +[ -n "$asset_path" ] || die "no tarball matching target ${target} in artifact" +asset=$(basename "$asset_path") +cli_version=${asset#difyctl-v} +cli_version=${cli_version%-${target}.tar.xz} +checksums="difyctl-v${cli_version}-checksums.txt" + +[ -f "${tmp}/artifact/${checksums}" ] || die "checksum file ${checksums} not found in artifact" +# 5. Verify checksum ( - cd "$tmp" + cd "${tmp}/artifact" grep " ${asset}\$" "$checksums" | $HASH -c - ) || die "checksum mismatch for ${asset}" -if command -v cosign >/dev/null 2>&1; then - sig_url="${url}.sig" - pem_url="${url}.pem" - curl -fsSL --retry 3 "$sig_url" -o "${tmp}/${asset}.sig" \ - || die "tarball signature missing on ${tag}; refusing to install (cosign present)" - curl -fsSL --retry 3 "$pem_url" -o "${tmp}/${asset}.pem" \ - || die "tarball cert missing on ${tag}; refusing to install (cosign present)" - COSIGN_EXPERIMENTAL=1 cosign verify-blob \ - --certificate "${tmp}/${asset}.pem" \ - --signature "${tmp}/${asset}.sig" \ - --certificate-identity-regexp '^https://github.com/langgenius/dify/' \ - --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \ - "${tmp}/${asset}" \ - || die "cosign verification failed for ${asset}" - printf 'cosign: verified %s\n' "$asset" -else - printf 'note: cosign not installed; skipping signature verification (sha256 still enforced)\n' >&2 -fi - +# 6. Extract and install share_dir="${PREFIX}/share/difyctl" bin_dir="${PREFIX}/bin" mkdir -p "$share_dir" "$bin_dir" printf 'extracting to %s\n' "$share_dir" -tar -xJf "${tmp}/${asset}" -C "$share_dir" --strip-components=1 +tar -xJf "${tmp}/artifact/${asset}" -C "$share_dir" --strip-components=1 target_bin="${share_dir}/bin/difyctl" [ -x "$target_bin" ] || die "expected binary at ${target_bin} after extract" ln -sf "$target_bin" "${bin_dir}/difyctl" -printf '\ndifyctl %s installed: %s/difyctl\n' "$cli_v" "$bin_dir" +printf '\ndifyctl v%s installed: %s/difyctl\n' "$cli_version" "$bin_dir" case ":${PATH}:" in *":${bin_dir}:"*) diff --git a/cli/scripts/install-local.sh b/cli/scripts/install-local.sh index 125d23e8766a47..3a1b76f78d9a48 100755 --- a/cli/scripts/install-local.sh +++ b/cli/scripts/install-local.sh @@ -19,12 +19,13 @@ case "$(uname -m)" in *) echo "unsupported arch: $(uname -m)" >&2; exit 1 ;; esac -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -DIST_DIR="${SCRIPT_DIR}/../dist" -TARBALL="$(ls "${DIST_DIR}"/difyctl-*-${os}-${arch}.tar.xz 2>/dev/null | head -1)" +# Accept an optional directory path as the first argument. +# Default to the cli/dist directory if not provided. +ARTIFACT_DIR="${1:-$(cd "$(dirname "$0")/../dist" && pwd)}" +TARBALL="$(ls "${ARTIFACT_DIR}"/difyctl-*-${os}-${arch}.tar.xz 2>/dev/null | head -1)" if [ -z "$TARBALL" ]; then - echo "no tarball found for ${os}-${arch} in ${DIST_DIR}" >&2 + echo "no tarball found for ${os}-${arch} in ${ARTIFACT_DIR}" >&2 echo "run: pnpm pack:tarballs" >&2 exit 1 fi diff --git a/cli/scripts/release-bump-guard.sh b/cli/scripts/release-bump-guard.sh deleted file mode 100755 index 293b23e594a039..00000000000000 --- a/cli/scripts/release-bump-guard.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env bash -# scripts/release-bump-guard.sh — auto-path only. Refuse if version+compat -# both unchanged vs. the channel-matching npm dist-tag. -# -# Required env: NEW_VERSION, NEW_MIN_DIFY, NEW_MAX_DIFY. - -set -euo pipefail - -_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=lib/common.sh -source "${_dir}/lib/common.sh" - -require node -require jq -require npm - -cd "$(cli::root)" - -: "${NEW_VERSION:?NEW_VERSION is required}" -: "${NEW_MIN_DIFY:?NEW_MIN_DIFY is required}" -: "${NEW_MAX_DIFY:?NEW_MAX_DIFY is required}" - -channel=$(node -p "require('./package.json').difyctl.channel") -case "$channel" in - stable) dist_tag=latest ;; - rc) dist_tag=next ;; - *) die "unsupported channel for publish: ${channel}" ;; -esac - -dist_tags_json=$(npm view @langgenius/difyctl dist-tags --json 2>/dev/null || echo '{}') -prev_version=$(echo "$dist_tags_json" | jq -r --arg t "$dist_tag" '.[$t] // ""') - -if [[ -z "$prev_version" ]]; then - log::info "no prior release on dist-tag '${dist_tag}'; skipping bump guard" - exit 0 -fi - -if [[ "$prev_version" == "$NEW_VERSION" ]]; then - echo "::warning title=cli version not bumped::package.json version ${NEW_VERSION} is already published on dist-tag '${dist_tag}'. If this is a deliberate re-run (dify release re-cut, retry after failure), ignore. If you intended to ship new cli bytes, bump cli/package.json#version and re-run." - log::info "same version as npm dist-tag '${dist_tag}' (${prev_version}); skipping bump guard" - exit 0 -fi - -prev_meta=$(npm view "@langgenius/difyctl@${prev_version}" --json) -prev_min=$(echo "$prev_meta" | jq -r '.difyctl.compat.minDify') -prev_max=$(echo "$prev_meta" | jq -r '.difyctl.compat.maxDify') - -[[ "$NEW_VERSION" != "$prev_version" ]] \ - || die "version unchanged from npm dist-tag '${dist_tag}' (${prev_version}); bump cli/package.json" - -[[ "$NEW_MIN_DIFY" != "$prev_min" || "$NEW_MAX_DIFY" != "$prev_max" ]] \ - || die "compat unchanged from npm @${prev_version} on dist-tag '${dist_tag}' (${prev_min}..${prev_max}); bump in cli/package.json" - -log::info "bump guard passed: ${prev_version} → ${NEW_VERSION}, compat ${prev_min}..${prev_max} → ${NEW_MIN_DIFY}..${NEW_MAX_DIFY}" diff --git a/cli/scripts/release-cosign-sign.sh b/cli/scripts/release-cosign-sign.sh deleted file mode 100755 index 5060c605c6c605..00000000000000 --- a/cli/scripts/release-cosign-sign.sh +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env bash -# scripts/release-cosign-sign.sh — keyless cosign sign of tarballs + checksum -# manifest using GitHub Actions OIDC (Sigstore Fulcio cert + Rekor log entry). -# -# Required env: CLI_VERSION. Workflow must export id-token: write and set -# COSIGN_EXPERIMENTAL=1 (cli-release.yml does both). - -set -euo pipefail - -_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=lib/common.sh -source "${_dir}/lib/common.sh" - -require cosign - -: "${CLI_VERSION:?CLI_VERSION is required}" - -cd "$(cli::root)/dist" - -shopt -s nullglob -targets=(difyctl-v"${CLI_VERSION}"-*.tar.xz "difyctl-v${CLI_VERSION}-checksums.txt") -shopt -u nullglob - -[[ ${#targets[@]} -gt 0 ]] || die "no files to sign in dist/ for CLI_VERSION=${CLI_VERSION}" - -for f in "${targets[@]}"; do - [[ -f "$f" ]] || continue - cosign sign-blob --yes \ - --output-signature "${f}.sig" \ - --output-certificate "${f}.pem" \ - "$f" - log::info "signed ${f} → ${f}.sig + ${f}.pem" -done diff --git a/cli/scripts/release-npm-publish.sh b/cli/scripts/release-npm-publish.sh deleted file mode 100755 index 4c5cf44edf4f5a..00000000000000 --- a/cli/scripts/release-npm-publish.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env bash -# scripts/release-npm-publish.sh — channel-aware npm publish with -# EPUBLISHCONFLICT no-op trap. -# -# Required env: CHANNEL (stable | rc), NEW_VERSION. - -set -euo pipefail - -_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=lib/common.sh -source "${_dir}/lib/common.sh" - -require npm -require node - -cd "$(cli::root)" - -: "${CHANNEL:?CHANNEL is required}" -: "${NEW_VERSION:?NEW_VERSION is required}" - -case "$CHANNEL" in - stable) dist_tag=latest ;; - rc) dist_tag=next ;; - *) die "unsupported channel for publish: ${CHANNEL}" ;; -esac - -pkg_version=$(node -p "require('./package.json').version") -[[ "$pkg_version" == "$NEW_VERSION" ]] \ - || die "package.json version (${pkg_version}) != NEW_VERSION (${NEW_VERSION})" - -set +e -output=$(npm publish --access public --provenance --tag "$dist_tag" 2>&1) -status=$? -set -e - -if [[ $status -eq 0 ]]; then - log::info "PUBLISHED @langgenius/difyctl@${NEW_VERSION} --tag ${dist_tag}" - printf '%s\n' "$output" - exit 0 -fi - -if printf '%s' "$output" | grep -qE 'EPUBLISHCONFLICT|cannot publish over the previously published versions'; then - log::warn "NO-OP: @langgenius/difyctl@${NEW_VERSION} already on registry (idempotent re-run)" - exit 0 -fi - -printf '%s\n' "$output" >&2 -die "npm publish failed (exit ${status}); see output above" diff --git a/cli/scripts/release-pack-tarballs.sh b/cli/scripts/release-pack-tarballs.sh new file mode 100755 index 00000000000000..ca5feedefadd1f --- /dev/null +++ b/cli/scripts/release-pack-tarballs.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +# scripts/release-pack-tarballs.sh — build distributable tarballs. +# +# Required env: CLI_VERSION. Output: +# dist/difyctl-v--.tar.xz + +set -euo pipefail + +_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib/common.sh +source "${_dir}/lib/common.sh" + +require pnpm +require tar + +: "${CLI_VERSION:?CLI_VERSION is required}" + +cd "$(cli::root)" + +BUILD_DIR="dist/release-staging" +rm -rf "$BUILD_DIR" +mkdir -p "$BUILD_DIR/difyctl/bin" + +log::info "staging files for v${CLI_VERSION}..." + +# Copy built code, manifests, and the binary entrypoint +cp -r dist/ "$BUILD_DIR/difyctl/dist" +cp bin/run.js "$BUILD_DIR/difyctl/bin/difyctl" +chmod +x "$BUILD_DIR/difyctl/bin/difyctl" +cp package.json README.md pnpm-lock.yaml "$BUILD_DIR/difyctl/" + +# Install production dependencies into the staging folder +( + cd "$BUILD_DIR/difyctl" + pnpm install --prod --frozen-lockfile +) + +# Create tarballs for each target platform +# The contents are the same for all, but naming them per-platform simplifies +# the installer and allows for platform-specific native deps later. +for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do + log::info "packing ${target}..." + tar -C "$BUILD_DIR" -cJf "dist/difyctl-v${CLI_VERSION}-${target}.tar.xz" difyctl +done + +log::info "tarballs created in dist/" +ls -lh dist/difyctl-v${CLI_VERSION}-*.tar.xz >&2 diff --git a/cli/scripts/release-upload-tarballs.sh b/cli/scripts/release-upload-tarballs.sh deleted file mode 100755 index ac95176f8de0e2..00000000000000 --- a/cli/scripts/release-upload-tarballs.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bash -# scripts/release-upload-tarballs.sh — idempotent gh release upload of -# tarballs + checksum file (sha256-strict; skip on match, fail on mismatch) -# and cosign .sig/.pem signatures (overwrite-allowed; bytes vary per run). -# -# Required env: DIFY_TAG, CLI_VERSION, GH_TOKEN. - -set -euo pipefail - -_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=lib/common.sh -source "${_dir}/lib/common.sh" - -require gh -require jq - -: "${DIFY_TAG:?DIFY_TAG is required}" -: "${CLI_VERSION:?CLI_VERSION is required}" - -cd "$(cli::root)" - -REPO_FLAG=(--repo langgenius/dify) - -if command -v sha256sum >/dev/null 2>&1; then - hash_cmd() { sha256sum "$1" | awk '{print $1}'; } -elif command -v shasum >/dev/null 2>&1; then - hash_cmd() { shasum -a 256 "$1" | awk '{print $1}'; } -else - die "no sha256 hasher found (need sha256sum or shasum)" -fi - -remote_json=$(gh release view "$DIFY_TAG" "${REPO_FLAG[@]}" --json assets -q '.assets') - -upload_one() { - local file="$1" - local mode="${2:-strict}" # strict | clobber - local name - name=$(basename "$file") - local local_sha - local_sha=$(hash_cmd "$file") - local remote_entry - remote_entry=$(printf '%s' "$remote_json" | jq -c --arg n "$name" '.[] | select(.name == $n)') - - if [[ -z "$remote_entry" ]]; then - log::info "uploading ${name}" - gh release upload "$DIFY_TAG" "$file" "${REPO_FLAG[@]}" - return - fi - - if [[ "$mode" == "clobber" ]]; then - log::info "overwriting ${name} (clobber mode — cosign sig/cert)" - gh release upload "$DIFY_TAG" "$file" "${REPO_FLAG[@]}" --clobber - return - fi - - local remote_digest remote_sha="" - remote_digest=$(printf '%s' "$remote_entry" | jq -r '.digest // ""') - if [[ "$remote_digest" == sha256:* ]]; then - remote_sha="${remote_digest#sha256:}" - else - local tmp download_url - tmp=$(mktemp) - download_url=$(printf '%s' "$remote_entry" | jq -r '.url') - gh api -H 'Accept: application/octet-stream' "$download_url" > "$tmp" - remote_sha=$(hash_cmd "$tmp") - rm -f "$tmp" - fi - - if [[ "$local_sha" == "$remote_sha" ]]; then - log::info "skip ${name} (sha256 matches)" - return - fi - - die "asset ${name} already on ${DIFY_TAG} with different sha256 (local=${local_sha}, remote=${remote_sha}); refusing to overwrite" -} - -shopt -s nullglob -tars=(dist/difyctl-v"${CLI_VERSION}"-*.tar.xz) -checksum_file="dist/difyctl-v${CLI_VERSION}-checksums.txt" -sigs=(dist/difyctl-v"${CLI_VERSION}"-*.sig dist/difyctl-v"${CLI_VERSION}"-checksums.txt.sig) -pems=(dist/difyctl-v"${CLI_VERSION}"-*.pem dist/difyctl-v"${CLI_VERSION}"-checksums.txt.pem) -shopt -u nullglob - -[[ ${#tars[@]} -gt 0 ]] || die "no tarballs in dist/ matching difyctl-v${CLI_VERSION}-*.tar.xz" -[[ -f "$checksum_file" ]] || die "checksum file missing: ${checksum_file}" - -for f in "${tars[@]}" "$checksum_file"; do - upload_one "$f" strict -done - -# Cosign signatures + certs are keyless and re-generated per run with fresh -# timestamps; their bytes change each run but verify the same blob. Allow -# overwrite via --clobber so re-runs converge cleanly. -for f in "${sigs[@]}" "${pems[@]}"; do - [[ -f "$f" ]] || continue - upload_one "$f" clobber -done - -log::info "uploaded ${#tars[@]} tarballs + checksums.txt + signatures to dify release ${DIFY_TAG}" diff --git a/cli/scripts/release.sh b/cli/scripts/release.sh deleted file mode 100755 index cb6666d8ddaba2..00000000000000 --- a/cli/scripts/release.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash -# scripts/release.sh — local-developer release build. -# -# Reads cli/package.json, validates, exports DIFYCTL_* env, runs pnpm build + -# oclif pack tarballs. cli-release.yml does NOT call this; the workflow inlines -# the same env contract. - -set -euo pipefail - -_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=lib/common.sh -source "${_dir}/lib/common.sh" - -require pnpm 'install with `corepack enable && corepack prepare pnpm@latest --activate`' -require node - -cd "$(cli::root)" - -scripts/release-validate-manifest.sh - -PKG_VERSION=$(node -p "require('./package.json').version") -CHANNEL=$(node -p "require('./package.json').difyctl.channel") -MIN_DIFY=$(node -p "require('./package.json').difyctl.compat.minDify") -MAX_DIFY=$(node -p "require('./package.json').difyctl.compat.maxDify") - -export DIFYCTL_VERSION="${PKG_VERSION}" -export DIFYCTL_CHANNEL="${CHANNEL}" -export DIFYCTL_MIN_DIFY="${MIN_DIFY}" -export DIFYCTL_MAX_DIFY="${MAX_DIFY}" -export DIFYCTL_COMMIT="$(git rev-parse HEAD)" -export DIFYCTL_BUILD_DATE="$(git log -1 --format=%cI HEAD)" - -log::info "release ${DIFYCTL_VERSION} (channel=${DIFYCTL_CHANNEL}, compat=${MIN_DIFY}..${MAX_DIFY})" -pnpm build -pnpm pack:tarballs - -log::info "artifacts in dist/" -ls -lh dist/ 2>/dev/null | tail -n +2 >&2 || true From 8b9962e9c56a26bb2af210d8f7be61135f7d08e6 Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 10:28:59 +0800 Subject: [PATCH 02/11] add pr trigger to test --- .github/workflows/cli-release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 7477a48c9f1da9..981cc25c751003 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -2,6 +2,12 @@ name: CLI Release on: workflow_dispatch: + # TEMP: remove before merging — lets the PR exercise the release pipeline. + pull_request: + branches: [feat/cli] + paths: + - 'cli/**' + - '.github/workflows/cli-release.yml' concurrency: group: cli-release-${{ github.ref }} From 3b693686497c64dee703751fba8ff60c6e4c781f Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 10:43:55 +0800 Subject: [PATCH 03/11] remove pr trigger --- .github/workflows/cli-release.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 981cc25c751003..7477a48c9f1da9 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -2,12 +2,6 @@ name: CLI Release on: workflow_dispatch: - # TEMP: remove before merging — lets the PR exercise the release pipeline. - pull_request: - branches: [feat/cli] - paths: - - 'cli/**' - - '.github/workflows/cli-release.yml' concurrency: group: cli-release-${{ github.ref }} From 5dd7953f2390c78fcaa2921b46665ecdedb6582b Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 11:06:18 +0800 Subject: [PATCH 04/11] fix tarball script --- .github/workflows/cli-release.yml | 78 ++++++++++++++++++++++++---- cli/scripts/release-pack-tarballs.sh | 73 +++++++++++++++++--------- 2 files changed, 115 insertions(+), 36 deletions(-) diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 7477a48c9f1da9..a48f0e7cff2dcf 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -8,9 +8,22 @@ concurrency: cancel-in-progress: true jobs: - release: - runs-on: depot-ubuntu-24.04 + pack: + name: pack (${{ matrix.target }}) if: github.repository == 'langgenius/dify' + strategy: + fail-fast: false + matrix: + include: + - target: linux-x64 + runs-on: depot-ubuntu-24.04 + - target: linux-arm64 + runs-on: ubuntu-24.04-arm + - target: darwin-x64 + runs-on: macos-13 + - target: darwin-arm64 + runs-on: macos-14 + runs-on: ${{ matrix.runs-on }} permissions: contents: read defaults: @@ -46,24 +59,67 @@ jobs: run: scripts/release-validate-manifest.sh - name: Build cli + env: + DIFYCTL_VERSION: ${{ steps.manifest.outputs.version }} + DIFYCTL_CHANNEL: ${{ steps.manifest.outputs.channel }} + DIFYCTL_MIN_DIFY: ${{ steps.manifest.outputs.minDify }} + DIFYCTL_MAX_DIFY: ${{ steps.manifest.outputs.maxDify }} run: | - DIFYCTL_VERSION="${{ steps.manifest.outputs.version }}" \ - DIFYCTL_CHANNEL="${{ steps.manifest.outputs.channel }}" \ - DIFYCTL_MIN_DIFY="${{ steps.manifest.outputs.minDify }}" \ - DIFYCTL_MAX_DIFY="${{ steps.manifest.outputs.maxDify }}" \ DIFYCTL_COMMIT="$(git rev-parse HEAD)" \ DIFYCTL_BUILD_DATE="$(git log -1 --format=%cI HEAD)" \ - pnpm build + pnpm build + + - name: Pack tarball (${{ matrix.target }}) + env: + CLI_VERSION: ${{ steps.manifest.outputs.version }} + PACK_TARGET: ${{ matrix.target }} + run: pnpm pack:tarballs - - name: Pack tarballs - run: CLI_VERSION=${{ steps.manifest.outputs.version }} pnpm pack:tarballs + - name: Upload per-target tarball + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: difyctl-${{ steps.manifest.outputs.version }}-${{ matrix.target }} + path: cli/dist/difyctl-v*-${{ matrix.target }}.tar.xz + retention-days: 7 + if-no-files-found: error + + bundle: + name: bundle release artifact + needs: pack + if: github.repository == 'langgenius/dify' + runs-on: depot-ubuntu-24.04 + permissions: + contents: read + defaults: + run: + shell: bash + working-directory: ./cli + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + persist-credentials: false + + - name: Read manifest version + id: manifest + run: | + version=$(node -p "require('./package.json').version") + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Download per-target tarballs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: cli/dist + pattern: difyctl-${{ steps.manifest.outputs.version }}-* + merge-multiple: true - name: Generate sha256 checksum file - run: scripts/release-write-checksums.sh env: CLI_VERSION: ${{ steps.manifest.outputs.version }} + run: scripts/release-write-checksums.sh - - name: Upload tarballs + checksum as workflow artifact + - name: Upload combined release artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: difyctl-${{ steps.manifest.outputs.version }} diff --git a/cli/scripts/release-pack-tarballs.sh b/cli/scripts/release-pack-tarballs.sh index ca5feedefadd1f..7ce67ea6ff269f 100755 --- a/cli/scripts/release-pack-tarballs.sh +++ b/cli/scripts/release-pack-tarballs.sh @@ -1,8 +1,15 @@ #!/usr/bin/env bash -# scripts/release-pack-tarballs.sh — build distributable tarballs. +# scripts/release-pack-tarballs.sh — build a distributable tarball for the +# current host target. # -# Required env: CLI_VERSION. Output: -# dist/difyctl-v--.tar.xz +# Uses `pnpm deploy` to resolve workspace `catalog:` / `workspace:` refs from +# the monorepo lockfile and produce a self-contained directory. The deploy +# installs native optionalDependencies (e.g. @napi-rs/keyring) for the host +# OS/arch, so each target must be packed on its native runner. +# +# Required env: CLI_VERSION. +# Optional env: PACK_TARGET (override detected target, e.g. linux-x64). +# Output: dist/difyctl-v-.tar.xz set -euo pipefail @@ -15,33 +22,49 @@ require tar : "${CLI_VERSION:?CLI_VERSION is required}" -cd "$(cli::root)" +detect_target() { + local os arch + case "$(uname -s)" in + Linux) os=linux ;; + Darwin) os=darwin ;; + *) die "unsupported OS: $(uname -s)" ;; + esac + case "$(uname -m)" in + x86_64|amd64) arch=x64 ;; + arm64|aarch64) arch=arm64 ;; + *) die "unsupported arch: $(uname -m)" ;; + esac + printf '%s' "${os}-${arch}" +} -BUILD_DIR="dist/release-staging" -rm -rf "$BUILD_DIR" -mkdir -p "$BUILD_DIR/difyctl/bin" +target="${PACK_TARGET:-$(detect_target)}" -log::info "staging files for v${CLI_VERSION}..." +cli_root="$(cli::root)" +workspace_root="$(cd "${cli_root}/.." && pwd)" -# Copy built code, manifests, and the binary entrypoint -cp -r dist/ "$BUILD_DIR/difyctl/dist" -cp bin/run.js "$BUILD_DIR/difyctl/bin/difyctl" -chmod +x "$BUILD_DIR/difyctl/bin/difyctl" -cp package.json README.md pnpm-lock.yaml "$BUILD_DIR/difyctl/" +BUILD_DIR="${cli_root}/dist/release-staging" +STAGE="${BUILD_DIR}/difyctl" -# Install production dependencies into the staging folder +rm -rf "$BUILD_DIR" +mkdir -p "$BUILD_DIR" + +log::info "deploying difyctl@v${CLI_VERSION} (${target}) via pnpm deploy..." ( - cd "$BUILD_DIR/difyctl" - pnpm install --prod --frozen-lockfile + cd "$workspace_root" + # --legacy: cli has no workspace:* prod deps; injection isn't needed. Avoids + # requiring `inject-workspace-packages=true` on the whole monorepo (pnpm v10+). + pnpm --filter @langgenius/difyctl deploy --prod --legacy "$STAGE" ) -# Create tarballs for each target platform -# The contents are the same for all, but naming them per-platform simplifies -# the installer and allows for platform-specific native deps later. -for target in linux-x64 linux-arm64 darwin-x64 darwin-arm64; do - log::info "packing ${target}..." - tar -C "$BUILD_DIR" -cJf "dist/difyctl-v${CLI_VERSION}-${target}.tar.xz" difyctl -done +# install-cli.sh expects bin/difyctl. Keep bin/run.js too so `node bin/run.js` +# from the extracted tree still works and the package.json bin field stays valid. +cp "$STAGE/bin/run.js" "$STAGE/bin/difyctl" +chmod +x "$STAGE/bin/difyctl" + +mkdir -p "${cli_root}/dist" +tarball="${cli_root}/dist/difyctl-v${CLI_VERSION}-${target}.tar.xz" +log::info "packing ${target} -> $(basename "$tarball")..." +tar -C "$BUILD_DIR" -cJf "$tarball" difyctl -log::info "tarballs created in dist/" -ls -lh dist/difyctl-v${CLI_VERSION}-*.tar.xz >&2 +log::info "tarball created: $tarball" +ls -lh "$tarball" >&2 From d361534288a836f7ce98aee98f6bbee915d7979b Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 12:17:37 +0800 Subject: [PATCH 05/11] use bun to build executable --- .github/workflows/cli-release.yml | 82 +++++++------------------- cli/.gitignore | 1 - cli/AGENTS.md | 15 ++--- cli/ARD.md | 27 +++++---- cli/README.md | 16 ++--- cli/package.json | 2 +- cli/scripts/cross-arch.npmrc | 13 ++++ cli/scripts/install-cli.sh | 48 +++++++-------- cli/scripts/release-build.sh | 62 +++++++++++++++++++ cli/scripts/release-pack-tarballs.sh | 70 ---------------------- cli/scripts/release-write-checksums.sh | 15 ++--- cli/src/commands/AGENTS.md | 17 +++--- 12 files changed, 163 insertions(+), 205 deletions(-) create mode 100644 cli/scripts/cross-arch.npmrc create mode 100755 cli/scripts/release-build.sh delete mode 100755 cli/scripts/release-pack-tarballs.sh diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index a48f0e7cff2dcf..481fee56898761 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -8,22 +8,10 @@ concurrency: cancel-in-progress: true jobs: - pack: - name: pack (${{ matrix.target }}) + release: + name: build standalone binaries (all targets) + runs-on: depot-ubuntu-24.04 if: github.repository == 'langgenius/dify' - strategy: - fail-fast: false - matrix: - include: - - target: linux-x64 - runs-on: depot-ubuntu-24.04 - - target: linux-arm64 - runs-on: ubuntu-24.04-arm - - target: darwin-x64 - runs-on: macos-13 - - target: darwin-arm64 - runs-on: macos-14 - runs-on: ${{ matrix.runs-on }} permissions: contents: read defaults: @@ -41,6 +29,11 @@ jobs: - name: Setup web environment uses: ./.github/actions/setup-web + - name: Setup Bun + uses: oven-sh/setup-bun@4bc047ad259df6fc24a6c9b0f9a0cb08cf17fbe5 # v2.0.2 + with: + bun-version: latest + - name: Read cli/package.json id: manifest run: | @@ -58,7 +51,13 @@ jobs: - name: Validate manifest run: scripts/release-validate-manifest.sh - - name: Build cli + - name: Install cross-arch native prebuilds + # Re-installs node_modules with every @napi-rs/keyring platform variant + # so `bun build --compile` can embed the right .node into each target. + working-directory: ./ + run: NPM_CONFIG_USERCONFIG="$PWD/cli/scripts/cross-arch.npmrc" pnpm install --frozen-lockfile + + - name: Build cli (dist/) env: DIFYCTL_VERSION: ${{ steps.manifest.outputs.version }} DIFYCTL_CHANNEL: ${{ steps.manifest.outputs.channel }} @@ -69,62 +68,21 @@ jobs: DIFYCTL_BUILD_DATE="$(git log -1 --format=%cI HEAD)" \ pnpm build - - name: Pack tarball (${{ matrix.target }}) + - name: Compile standalone binaries (all targets) env: CLI_VERSION: ${{ steps.manifest.outputs.version }} - PACK_TARGET: ${{ matrix.target }} - run: pnpm pack:tarballs - - - name: Upload per-target tarball - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: difyctl-${{ steps.manifest.outputs.version }}-${{ matrix.target }} - path: cli/dist/difyctl-v*-${{ matrix.target }}.tar.xz - retention-days: 7 - if-no-files-found: error - - bundle: - name: bundle release artifact - needs: pack - if: github.repository == 'langgenius/dify' - runs-on: depot-ubuntu-24.04 - permissions: - contents: read - defaults: - run: - shell: bash - working-directory: ./cli - - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - persist-credentials: false - - - name: Read manifest version - id: manifest - run: | - version=$(node -p "require('./package.json').version") - echo "version=$version" >> "$GITHUB_OUTPUT" - - - name: Download per-target tarballs - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - with: - path: cli/dist - pattern: difyctl-${{ steps.manifest.outputs.version }}-* - merge-multiple: true + run: pnpm build:bin - name: Generate sha256 checksum file env: CLI_VERSION: ${{ steps.manifest.outputs.version }} run: scripts/release-write-checksums.sh - - name: Upload combined release artifact + - name: Upload release artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: difyctl-${{ steps.manifest.outputs.version }} path: | - cli/dist/difyctl-v*.tar.xz - cli/dist/difyctl-v*-checksums.txt - retention-days: 90 + cli/dist/bin/difyctl-v* + retention-days: 21 if-no-files-found: error diff --git a/cli/.gitignore b/cli/.gitignore index 69bb88b501d1da..9747e29156e047 100644 --- a/cli/.gitignore +++ b/cli/.gitignore @@ -1,7 +1,6 @@ dist/ coverage/ node_modules/ -oclif.manifest.json *.tsbuildinfo .vitest-cache/ docs/specs/ diff --git a/cli/AGENTS.md b/cli/AGENTS.md index e55f2fa304fd5f..0d579af2c75efb 100644 --- a/cli/AGENTS.md +++ b/cli/AGENTS.md @@ -1,6 +1,6 @@ # AGENTS.md — difyctl (TypeScript CLI) -TypeScript port of difyctl. Stack: oclif 4.x, Node 22+, ESM, ky for HTTP, vitest, eslint via @antfu/eslint-config. +TypeScript port of difyctl. Stack: custom CLI framework (`src/framework/`), Node 22+, ESM, ky for HTTP, vitest, eslint via @antfu/eslint-config. > Architecture patterns, scaffolding recipe, printer chain, strategy pattern, testing conventions, anti-patterns: see **[`ARD.md`]**. @@ -24,8 +24,8 @@ TypeScript port of difyctl. Stack: oclif 4.x, Node 22+, ESM, ky for HTTP, vitest | Layer | Path | Role | | --------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -| commands | `src/commands/` | oclif command shells. Only place oclif imports run. | -| domain | `src/run/`, `src/get/`, etc. | Plain TS modules. Take typed deps via options. Testable without oclif. | +| commands | `src/commands/` | Command class shells (extend `DifyCommand`). Only place framework imports run. | +| domain | `src/run/`, `src/get/`, etc. | Plain TS modules. Take typed deps via options. Testable without the framework. | | api | `src/api/` | One typed client per resource. Each takes `KyInstance`. | | http | `src/http/` | `createClient` + middleware (auth, retry, logging, error mapping). Only place ky runs. | | io | `src/io/` | Streams + spinner. Fence between data-out and progress UI. | @@ -45,7 +45,7 @@ Scaffold recipe + checklist: see `ARD.md §New command scaffold`. Full folder co Layer rules: - Commands thin shells. Use `this.authedCtx(opts)` for bearer context; delegate to domain function. -- Domain receives deps via options; never imports oclif. +- Domain receives deps via options; never imports `src/framework/`. - Only `src/http/client.ts` and `src/api/*` import ky at runtime; elsewhere use `import type { KyInstance }`. - `process.*` lives in `src/io/`, `src/config/dir.ts`, `src/util/browser.ts`. Nowhere else. - No circular imports. `types/` pure leaf. @@ -60,11 +60,12 @@ pnpm test:coverage # with coverage pnpm type-check # tsc, no emit pnpm lint # eslint pnpm lint:fix # eslint --fix -pnpm build # production bundle + oclif manifest -pnpm manifest # regenerate oclif.manifest.json only +pnpm build # production bundle (vp pack) +pnpm tree:gen # regenerate src/commands/tree.ts (registry) +pnpm tree:check # verify tree.ts is up-to-date with the fs ``` -Release tarballs are produced by `pnpm pack:tarballs` (called from `.github/workflows/cli-release.yml`). +Release binaries (5 platform targets, Bun-compiled) are produced by `pnpm build:bin` (called from `.github/workflows/cli-release.yml`). ## Tests diff --git a/cli/ARD.md b/cli/ARD.md index a85c3d6ece7357..b8813fe920deb2 100644 --- a/cli/ARD.md +++ b/cli/ARD.md @@ -40,10 +40,10 @@ Examples: `get/app/`, `auth/devices/revoke/`, `describe/app/`. **2. Mandatory files** -| File | Responsibility | -| ---------- | ---------------------------------------------------------------------------------------- | -| `index.ts` | oclif `Command` subclass. Flag/arg declaration + `run()` wiring only. No business logic. | -| `run.ts` | Pure async function. Typed options + deps. Returns string. No `@oclif/core` imports. | +| File | Responsibility | +| ---------- | --------------------------------------------------------------------------------------- | +| `index.ts` | `DifyCommand` subclass. Flag/arg declaration + `run()` wiring only. No business logic. | +| `run.ts` | Pure async function. Typed options + deps. Returns string. No `src/framework/` imports. | **3. Optional files — add as needed** @@ -61,10 +61,10 @@ Examples: `get/app/`, `auth/devices/revoke/`, `describe/app/`. - [ ] Authed command calls `this.authedCtx()`; non-authed skips - [ ] No try/catch in `run()` — `DifyCommand.catch()` handles `BaseError` - [ ] `run.ts` returns string; no direct stdout write -- [ ] `run.ts` no `@oclif/core` imports +- [ ] `run.ts` no `src/framework/` imports - [ ] HTTP client via factory dep, not direct - [ ] `run.test.ts` written before impl (test-first) -- [ ] `pnpm manifest` run after adding command (updates `oclif.manifest.json`) +- [ ] `pnpm tree:gen` run after adding command (updates `src/commands/tree.ts`) - [ ] README command table updated by hand --- @@ -236,7 +236,7 @@ Never instantiate clients in `index.ts`. **Test-first.** Write failing test, run to confirm fail, then implement. -Tests live in `run.test.ts` alongside command. Test `run.ts` direct — never oclif `Command` class. +Tests live in `run.test.ts` alongside command. Test `run.ts` direct — never the `DifyCommand` class. ```typescript const io = bufferStreams() @@ -290,13 +290,14 @@ expect(JSON.parse(out).workspaces).toHaveLength(2) | `pnpm type-check` | `tsc --noEmit` — catches type errors without build | | `pnpm lint` | ESLint check | | `pnpm lint:fix` | ESLint auto-fix (perfectionist sort, chaining) | -| `pnpm build` | Production bundle + `oclif manifest` | -| `pnpm manifest` | Regenerate `oclif.manifest.json` only | -| `pnpm pack:tarballs` | Build distributable tarballs (release only) | +| `pnpm build` | Production bundle (`vp pack`) | +| `pnpm tree:gen` | Regenerate `src/commands/tree.ts` (registry) | +| `pnpm tree:check` | Verify `tree.ts` matches the filesystem | +| `pnpm build:bin` | Cross-compile standalone binaries via Bun (CI) | -**`pnpm manifest` rule:** run after adding, removing, renaming any command, flag, or arg. Manifest = runtime command registry — stale manifest causes silent flag failures at runtime. +**`pnpm tree:gen` rule:** run after adding, removing, renaming any command. The generated `tree.ts` is the runtime command registry — stale tree causes commands to be invisible at runtime. (Runs implicitly via `prebuild`/`predev`/`pretest`.) -**README hand-maintained.** `oclif readme` incompatible with this monorepo setup. When adding command, update command table in `README.md` manually. +**README hand-maintained.** When adding a command, update the command table in `README.md` manually. --- @@ -336,7 +337,7 @@ Repo runs `@antfu/eslint-config` + perfectionist + unicorn. | `enabled: !isHuman` in `runWithSpinner` | Set `outputFormat` on `IOStreams`; spinner auto-detects | | Long positional arg lists | Options struct | | `Record` dispatch map | Named singletons + picker function | -| `@oclif/core` import in `run.ts` | Keep oclif in `index.ts` only | +| `src/framework/` import in `run.ts` | Keep framework imports in `index.ts` only | | `buildAuthedContext(this, opts)` in command body | `this.authedCtx(opts)` | | `console.log` in `src/` | Return string from `run.ts`; write in `index.ts` | | New dependency without approval | Check first | diff --git a/cli/README.md b/cli/README.md index 6cf80747b0e10b..3c1b98c33219b4 100644 --- a/cli/README.md +++ b/cli/README.md @@ -4,7 +4,7 @@ CLI client for [Dify] platform. Browser device-flow signin, list/inspect apps, r ## Install -Pre-release builds are published only as **GitHub Actions workflow artifacts** (no npm, no GitHub Release assets). The installer fetches the latest successful `cli-release.yml` run on `main`, verifies sha256, and extracts the tarball into `$HOME/.local`. +Builds are standalone binaries (Bun-compiled) published as **GitHub Actions workflow artifacts** — no npm, no GitHub Release assets. The installer fetches the latest successful `cli-release.yml` run on `main`, verifies sha256, and copies the binary into `$HOME/.local/bin/difyctl`. ```sh # GH_TOKEN with `actions:read` scope is required — workflow artifact downloads @@ -13,14 +13,14 @@ export GH_TOKEN= curl -fsSL https://raw.githubusercontent.com/langgenius/dify/main/cli/scripts/install-cli.sh | sh ``` -| Env | Default | Purpose | -| ---------------- | ----------------- | --------------------------------------------------- | -| `GH_TOKEN` | — | GitHub PAT (or `GITHUB_TOKEN`) with `actions:read`. | -| `DIFYCTL_PREFIX` | `$HOME/.local` | Install root. Binary symlinked to `/bin`. | -| `DIFYCTL_REPO` | `langgenius/dify` | Source repo. | -| `DIFYCTL_BRANCH` | `main` | Branch to pick the latest successful run from. | +| Env | Default | Purpose | +| ---------------- | ----------------- | ----------------------------------------------------- | +| `GH_TOKEN` | — | GitHub PAT (or `GITHUB_TOKEN`) with `actions:read`. | +| `DIFYCTL_PREFIX` | `$HOME/.local` | Install root. Binary lands at `/bin/difyctl`. | +| `DIFYCTL_REPO` | `langgenius/dify` | Source repo. | +| `DIFYCTL_BRANCH` | `main` | Branch to pick the latest successful run from. | -Targets: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`. Windows is not supported at this stage. +Supported targets: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`, `windows-x64.exe`. The shell installer covers Linux + macOS; Windows users can download the `.exe` directly from the same artifact. ## Quickstart diff --git a/cli/package.json b/cli/package.json index 3362ceb9c194da..43c925d37a66e5 100644 --- a/cli/package.json +++ b/cli/package.json @@ -46,7 +46,7 @@ "version:info": "tsx scripts/print-buildinfo.ts", "docker:build-dev": "scripts/docker-build-dev.sh", "sync-models": "scripts/sync-models.sh", - "pack:tarballs": "scripts/release-pack-tarballs.sh" + "build:bin": "scripts/release-build.sh" }, "dependencies": { "@napi-rs/keyring": "catalog:", diff --git a/cli/scripts/cross-arch.npmrc b/cli/scripts/cross-arch.npmrc new file mode 100644 index 00000000000000..246bb479db7b25 --- /dev/null +++ b/cli/scripts/cross-arch.npmrc @@ -0,0 +1,13 @@ +# Cross-arch keyring prebuilds for difyctl release builds. +# +# Pre-populates node_modules with @napi-rs/keyring native bindings for every +# release target so `bun build --compile` can embed them. Use via: +# +# NPM_CONFIG_USERCONFIG=cli/scripts/cross-arch.npmrc pnpm install --force +# +# Do not set as a workspace default — it would bloat dev installs. +supported-architectures-os[]=linux +supported-architectures-os[]=darwin +supported-architectures-os[]=win32 +supported-architectures-cpu[]=x64 +supported-architectures-cpu[]=arm64 diff --git a/cli/scripts/install-cli.sh b/cli/scripts/install-cli.sh index 04639b4a58d584..955dcd5a9e92be 100755 --- a/cli/scripts/install-cli.sh +++ b/cli/scripts/install-cli.sh @@ -1,14 +1,14 @@ #!/bin/sh -# install-cli.sh — one-line difyctl installer from latest GitHub Actions build. +# install-cli.sh — one-line difyctl installer from the latest GitHub Actions build. # # usage: -# curl -fsSL https://raw.githubusercontent.com/langgenius/dify/main/cli/scripts/install-cli.sh | sh +# GH_TOKEN= curl -fsSL https://raw.githubusercontent.com/langgenius/dify/main/cli/scripts/install-cli.sh | sh # # env: DIFYCTL_PREFIX (default $HOME/.local), DIFYCTL_REPO (default langgenius/dify), # DIFYCTL_BRANCH (default main), -# GH_TOKEN (required — GitHub workflow artifact zip downloads need auth even on public repos; -# minimum scope: actions:read). -# requires: curl, tar (xz), uname, jq, unzip, sha256sum or shasum. +# GH_TOKEN/GITHUB_TOKEN (required — workflow artifact zip downloads need +# auth even on public repos; minimum scope: actions:read). +# requires: curl, uname, jq, unzip, sha256sum or shasum. set -eu @@ -23,7 +23,6 @@ die() { err "$*"; exit 1; } need() { command -v "$1" >/dev/null 2>&1 || die "$1 is required"; } need curl -need tar need uname need jq need unzip @@ -43,7 +42,7 @@ fi case "$(uname -s)" in Linux*) os=linux ;; Darwin*) os=darwin ;; - *) die "unsupported OS: $(uname -s)" ;; + *) die "unsupported OS: $(uname -s) (use the Windows .exe directly)" ;; esac case "$(uname -m)" in @@ -54,7 +53,7 @@ esac target="${os}-${arch}" -# 1. Find the latest successful workflow run +# 1. Find the latest successful workflow run on the branch api_url="https://api.github.com/repos/${REPO}/actions/workflows/${WORKFLOW_FILE}/runs?branch=${BRANCH}&status=success&per_page=1" run_id=$(gh_curl "$api_url" | jq -r '.workflow_runs[0].id') @@ -72,22 +71,21 @@ if [ -z "$artifact_id" ] || [ "$artifact_id" = "null" ]; then die "could not find any artifacts for workflow run ${run_id}" fi -# 3. Download and unzip the artifact +# 3. Download and unzip the artifact (one zip with all platform binaries + checksums) tmp=$(mktemp -d 2>/dev/null || mktemp -d -t difyctl-install) trap 'rm -rf "$tmp"' EXIT INT TERM download_url="https://api.github.com/repos/${REPO}/actions/artifacts/${artifact_id}/zip" printf 'downloading artifact %s (run %s)...\n' "$artifact_name" "$run_id" gh_curl -L "$download_url" -o "${tmp}/artifact.zip" - unzip -q "${tmp}/artifact.zip" -d "${tmp}/artifact" -# 4. Find the tarball + checksum file by target -asset_path=$(ls "${tmp}/artifact"/difyctl-v*-"${target}".tar.xz 2>/dev/null | head -1) -[ -n "$asset_path" ] || die "no tarball matching target ${target} in artifact" +# 4. Locate the binary for this host + the checksum manifest +asset_path=$(ls "${tmp}/artifact"/difyctl-v*-"${target}" 2>/dev/null | head -1) +[ -n "$asset_path" ] || die "no binary matching target ${target} in artifact" asset=$(basename "$asset_path") cli_version=${asset#difyctl-v} -cli_version=${cli_version%-${target}.tar.xz} +cli_version=${cli_version%-${target}} checksums="difyctl-v${cli_version}-checksums.txt" [ -f "${tmp}/artifact/${checksums}" ] || die "checksum file ${checksums} not found in artifact" @@ -98,26 +96,20 @@ checksums="difyctl-v${cli_version}-checksums.txt" grep " ${asset}\$" "$checksums" | $HASH -c - ) || die "checksum mismatch for ${asset}" -# 6. Extract and install -share_dir="${PREFIX}/share/difyctl" +# 6. Install: copy binary to /bin/difyctl and chmod +x bin_dir="${PREFIX}/bin" -mkdir -p "$share_dir" "$bin_dir" - -printf 'extracting to %s\n' "$share_dir" -tar -xJf "${tmp}/artifact/${asset}" -C "$share_dir" --strip-components=1 - -target_bin="${share_dir}/bin/difyctl" -[ -x "$target_bin" ] || die "expected binary at ${target_bin} after extract" - -ln -sf "$target_bin" "${bin_dir}/difyctl" +mkdir -p "$bin_dir" +target_bin="${bin_dir}/difyctl" +cp "${tmp}/artifact/${asset}" "$target_bin" +chmod +x "$target_bin" -printf '\ndifyctl v%s installed: %s/difyctl\n' "$cli_version" "$bin_dir" +printf '\ndifyctl v%s installed: %s\n' "$cli_version" "$target_bin" case ":${PATH}:" in *":${bin_dir}:"*) - "${bin_dir}/difyctl" version >/dev/null 2>&1 \ + "$target_bin" version >/dev/null 2>&1 \ && printf 'verify: run "difyctl version"\n' \ - || err "binary present but failed to execute; check ${bin_dir}/difyctl" + || err "binary present but failed to execute; check ${target_bin}" ;; *) printf '\n%s is not on your PATH. Add this to your shell profile:\n' "$bin_dir" diff --git a/cli/scripts/release-build.sh b/cli/scripts/release-build.sh new file mode 100755 index 00000000000000..3218cb9fd60b95 --- /dev/null +++ b/cli/scripts/release-build.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +# scripts/release-build.sh — cross-compile difyctl to standalone binaries +# for every release target via `bun build --compile`. +# +# Prereqs: +# - dist/ produced by `pnpm build` (Bun bundles bin/run.js which imports +# from ../dist/). +# - All @napi-rs/keyring native variants present in node_modules. Use +# `NPM_CONFIG_USERCONFIG=cli/scripts/cross-arch.npmrc pnpm install --force` +# to populate them. +# +# Required env: CLI_VERSION. +# Output: dist/bin/difyctl-v-[.exe] + +set -euo pipefail + +_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=lib/common.sh +source "${_dir}/lib/common.sh" + +require bun + +: "${CLI_VERSION:?CLI_VERSION is required}" + +cli_root="$(cli::root)" +entry="${cli_root}/bin/run.js" +out_dir="${cli_root}/dist/bin" + +[[ -f "$entry" ]] || die "entry not found: $entry (run \`pnpm build\` first?)" +[[ -d "${cli_root}/dist/commands" ]] || die "${cli_root}/dist not built — run \`pnpm build\` first" + +rm -rf "$out_dir" +mkdir -p "$out_dir" + +# Bun --target -> release asset suffix (asset name omits the bun- prefix +# and uses Node-style platform names; .exe is appended for Windows). +targets=( + "bun-linux-x64:linux-x64" + "bun-linux-arm64:linux-arm64" + "bun-darwin-x64:darwin-x64" + "bun-darwin-arm64:darwin-arm64" + "bun-windows-x64:windows-x64" +) + +for spec in "${targets[@]}"; do + bun_target="${spec%%:*}" + asset_target="${spec##*:}" + suffix="" + case "$bun_target" in + bun-windows-*) suffix=".exe" ;; + esac + + out="${out_dir}/difyctl-v${CLI_VERSION}-${asset_target}${suffix}" + log::info "compiling ${asset_target} -> $(basename "$out")..." + bun build "$entry" \ + --target="$bun_target" \ + --compile \ + --outfile="$out" >/dev/null +done + +log::info "built $(find "$out_dir" -type f | wc -l | tr -d ' ') binaries:" +ls -lh "$out_dir" >&2 diff --git a/cli/scripts/release-pack-tarballs.sh b/cli/scripts/release-pack-tarballs.sh deleted file mode 100755 index 7ce67ea6ff269f..00000000000000 --- a/cli/scripts/release-pack-tarballs.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env bash -# scripts/release-pack-tarballs.sh — build a distributable tarball for the -# current host target. -# -# Uses `pnpm deploy` to resolve workspace `catalog:` / `workspace:` refs from -# the monorepo lockfile and produce a self-contained directory. The deploy -# installs native optionalDependencies (e.g. @napi-rs/keyring) for the host -# OS/arch, so each target must be packed on its native runner. -# -# Required env: CLI_VERSION. -# Optional env: PACK_TARGET (override detected target, e.g. linux-x64). -# Output: dist/difyctl-v-.tar.xz - -set -euo pipefail - -_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=lib/common.sh -source "${_dir}/lib/common.sh" - -require pnpm -require tar - -: "${CLI_VERSION:?CLI_VERSION is required}" - -detect_target() { - local os arch - case "$(uname -s)" in - Linux) os=linux ;; - Darwin) os=darwin ;; - *) die "unsupported OS: $(uname -s)" ;; - esac - case "$(uname -m)" in - x86_64|amd64) arch=x64 ;; - arm64|aarch64) arch=arm64 ;; - *) die "unsupported arch: $(uname -m)" ;; - esac - printf '%s' "${os}-${arch}" -} - -target="${PACK_TARGET:-$(detect_target)}" - -cli_root="$(cli::root)" -workspace_root="$(cd "${cli_root}/.." && pwd)" - -BUILD_DIR="${cli_root}/dist/release-staging" -STAGE="${BUILD_DIR}/difyctl" - -rm -rf "$BUILD_DIR" -mkdir -p "$BUILD_DIR" - -log::info "deploying difyctl@v${CLI_VERSION} (${target}) via pnpm deploy..." -( - cd "$workspace_root" - # --legacy: cli has no workspace:* prod deps; injection isn't needed. Avoids - # requiring `inject-workspace-packages=true` on the whole monorepo (pnpm v10+). - pnpm --filter @langgenius/difyctl deploy --prod --legacy "$STAGE" -) - -# install-cli.sh expects bin/difyctl. Keep bin/run.js too so `node bin/run.js` -# from the extracted tree still works and the package.json bin field stays valid. -cp "$STAGE/bin/run.js" "$STAGE/bin/difyctl" -chmod +x "$STAGE/bin/difyctl" - -mkdir -p "${cli_root}/dist" -tarball="${cli_root}/dist/difyctl-v${CLI_VERSION}-${target}.tar.xz" -log::info "packing ${target} -> $(basename "$tarball")..." -tar -C "$BUILD_DIR" -cJf "$tarball" difyctl - -log::info "tarball created: $tarball" -ls -lh "$tarball" >&2 diff --git a/cli/scripts/release-write-checksums.sh b/cli/scripts/release-write-checksums.sh index 2729d9a0b425ef..b106091324a9bc 100755 --- a/cli/scripts/release-write-checksums.sh +++ b/cli/scripts/release-write-checksums.sh @@ -1,8 +1,8 @@ #!/usr/bin/env bash -# scripts/release-write-checksums.sh — write sha256 manifest for tarballs. +# scripts/release-write-checksums.sh — write sha256 manifest for release binaries. # # Required env: CLI_VERSION (e.g. 0.1.0-rc.1). Output: -# cli/dist/difyctl-v-checksums.txt +# cli/dist/bin/difyctl-v-checksums.txt set -euo pipefail @@ -12,7 +12,7 @@ source "${_dir}/lib/common.sh" : "${CLI_VERSION:?CLI_VERSION is required}" -cd "$(cli::root)/dist" +cd "$(cli::root)/dist/bin" manifest="difyctl-v${CLI_VERSION}-checksums.txt" > "$manifest" @@ -26,12 +26,13 @@ else fi found=0 -for tar in difyctl-v"${CLI_VERSION}"-*.tar.xz; do - [[ -f "$tar" ]] || continue - $hash_cmd "$tar" >> "$manifest" +for bin in difyctl-v"${CLI_VERSION}"-*; do + [[ -f "$bin" ]] || continue + [[ "$bin" == "$manifest" ]] && continue + $hash_cmd "$bin" >> "$manifest" found=$((found + 1)) done -[[ "$found" -gt 0 ]] || die "no tarballs matching difyctl-v${CLI_VERSION}-*.tar.xz in dist/" +[[ "$found" -gt 0 ]] || die "no binaries matching difyctl-v${CLI_VERSION}-* in dist/bin/" log::info "wrote ${manifest} (${found} entries)" diff --git a/cli/src/commands/AGENTS.md b/cli/src/commands/AGENTS.md index 2b864032556864..0a4a1ec3fa5450 100644 --- a/cli/src/commands/AGENTS.md +++ b/cli/src/commands/AGENTS.md @@ -4,7 +4,7 @@ Per-command agent-optimized usage and structure guide. ## Command folder convention -Every command is a folder. `index.ts` is the only oclif entrypoint. All related +Every command is a folder. `index.ts` is the command class file. All related code — business logic, helpers, tests, and optional agent guide — colocates inside the folder. Subcommands are subfolders. @@ -12,8 +12,8 @@ the folder. Subcommands are subfolders. src/commands/ / / - index.ts ← oclif command entrypoint (the ONLY file oclif discovers) - run.ts ← business logic (not a command, invisible to oclif) + index.ts ← command class (extends DifyCommand; the ONLY file the registry discovers) + run.ts ← business logic (not a command, invisible to the registry) handlers.ts ← helpers guide.ts ← agent guide string (optional) *.test.ts ← tests @@ -23,16 +23,17 @@ src/commands/ .ts ``` -oclif discovers commands only via `**/index.+(js|cjs|mjs)`. All other files in -command folders are invisible to oclif — add freely without glob exclusions. -Folders prefixed with `_` (e.g. `_shared/`, `_strategies/`) are also excluded -from oclif discovery and from coverage checks. +The registry generator (`pnpm tree:gen` → `src/commands/tree.ts`) discovers +commands only via `**/index.+(js|cjs|mjs|ts)`. All other files in command +folders are invisible to the registry — add freely without glob exclusions. +Folders prefixed with `_` (e.g. `_shared/`, `_strategies/`) are excluded from +registry discovery and from coverage checks. ## Adding a new command 1. Create `src/commands///index.ts` extending `DifyCommand`. 1. Add business logic in sibling files (e.g. `run.ts`, `handlers.ts`). -1. Run `pnpm build` to regenerate the oclif manifest. +1. Run `pnpm tree:gen` to regenerate the command tree (also runs implicitly via `prebuild`/`predev`/`pretest`). 1. Run `pnpm test` to verify coverage. ## Adding an agent guide From 9a6f7bb48f2f211d16918f943f986f9305755abf Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 12:31:57 +0800 Subject: [PATCH 06/11] remove vite from release --- .github/workflows/cli-release.yml | 11 +++-------- cli/scripts/release-build.sh | 30 ++++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 481fee56898761..60b722c6430d1f 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -57,21 +57,16 @@ jobs: working-directory: ./ run: NPM_CONFIG_USERCONFIG="$PWD/cli/scripts/cross-arch.npmrc" pnpm install --frozen-lockfile - - name: Build cli (dist/) + - name: Compile standalone binaries (all targets) env: - DIFYCTL_VERSION: ${{ steps.manifest.outputs.version }} + CLI_VERSION: ${{ steps.manifest.outputs.version }} DIFYCTL_CHANNEL: ${{ steps.manifest.outputs.channel }} DIFYCTL_MIN_DIFY: ${{ steps.manifest.outputs.minDify }} DIFYCTL_MAX_DIFY: ${{ steps.manifest.outputs.maxDify }} run: | DIFYCTL_COMMIT="$(git rev-parse HEAD)" \ DIFYCTL_BUILD_DATE="$(git log -1 --format=%cI HEAD)" \ - pnpm build - - - name: Compile standalone binaries (all targets) - env: - CLI_VERSION: ${{ steps.manifest.outputs.version }} - run: pnpm build:bin + pnpm build:bin - name: Generate sha256 checksum file env: diff --git a/cli/scripts/release-build.sh b/cli/scripts/release-build.sh index 3218cb9fd60b95..3014a901e3cc97 100755 --- a/cli/scripts/release-build.sh +++ b/cli/scripts/release-build.sh @@ -2,14 +2,16 @@ # scripts/release-build.sh — cross-compile difyctl to standalone binaries # for every release target via `bun build --compile`. # +# Bun consumes bin/run.ts (which imports from src/) directly — no `pnpm build` +# / dist/ step needed. +# # Prereqs: -# - dist/ produced by `pnpm build` (Bun bundles bin/run.js which imports -# from ../dist/). # - All @napi-rs/keyring native variants present in node_modules. Use # `NPM_CONFIG_USERCONFIG=cli/scripts/cross-arch.npmrc pnpm install --force` # to populate them. # -# Required env: CLI_VERSION. +# Required env: CLI_VERSION, DIFYCTL_CHANNEL, DIFYCTL_MIN_DIFY, DIFYCTL_MAX_DIFY, +# DIFYCTL_COMMIT, DIFYCTL_BUILD_DATE. # Output: dist/bin/difyctl-v-[.exe] set -euo pipefail @@ -21,17 +23,32 @@ source "${_dir}/lib/common.sh" require bun : "${CLI_VERSION:?CLI_VERSION is required}" +: "${DIFYCTL_CHANNEL:?DIFYCTL_CHANNEL is required}" +: "${DIFYCTL_MIN_DIFY:?DIFYCTL_MIN_DIFY is required}" +: "${DIFYCTL_MAX_DIFY:?DIFYCTL_MAX_DIFY is required}" +: "${DIFYCTL_COMMIT:?DIFYCTL_COMMIT is required}" +: "${DIFYCTL_BUILD_DATE:?DIFYCTL_BUILD_DATE is required}" cli_root="$(cli::root)" -entry="${cli_root}/bin/run.js" +entry="${cli_root}/bin/run.ts" out_dir="${cli_root}/dist/bin" -[[ -f "$entry" ]] || die "entry not found: $entry (run \`pnpm build\` first?)" -[[ -d "${cli_root}/dist/commands" ]] || die "${cli_root}/dist not built — run \`pnpm build\` first" +[[ -f "$entry" ]] || die "entry not found: $entry" rm -rf "$out_dir" mkdir -p "$out_dir" +# Build-info globals (referenced as bare identifiers in src/version/info.ts). +# Each value must be a JS expression — wrap strings as JSON-quoted strings. +defines=( + "--define" "__DIFYCTL_VERSION__=\"${CLI_VERSION}\"" + "--define" "__DIFYCTL_CHANNEL__=\"${DIFYCTL_CHANNEL}\"" + "--define" "__DIFYCTL_MIN_DIFY__=\"${DIFYCTL_MIN_DIFY}\"" + "--define" "__DIFYCTL_MAX_DIFY__=\"${DIFYCTL_MAX_DIFY}\"" + "--define" "__DIFYCTL_COMMIT__=\"${DIFYCTL_COMMIT}\"" + "--define" "__DIFYCTL_BUILD_DATE__=\"${DIFYCTL_BUILD_DATE}\"" +) + # Bun --target -> release asset suffix (asset name omits the bun- prefix # and uses Node-style platform names; .exe is appended for Windows). targets=( @@ -55,6 +72,7 @@ for spec in "${targets[@]}"; do bun build "$entry" \ --target="$bun_target" \ --compile \ + "${defines[@]}" \ --outfile="$out" >/dev/null done From 4ea43261636580418bbee4cc936284237a31959b Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 12:32:10 +0800 Subject: [PATCH 07/11] add entrypoint source --- cli/bin/run.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100755 cli/bin/run.ts diff --git a/cli/bin/run.ts b/cli/bin/run.ts new file mode 100755 index 00000000000000..6c753b56380bf8 --- /dev/null +++ b/cli/bin/run.ts @@ -0,0 +1,10 @@ +#!/usr/bin/env node +// Production entry compiled by `bun build --compile` (see scripts/release-build.sh). +// Imports from src/ so the release pipeline doesn't need `pnpm build` (dist/). +// +// bin/run.js is kept for the local `pnpm build` + node execute path; this file +// is only consumed by Bun. +import { commandTree } from '../src/commands/tree.js' +import { run } from '../src/framework/run.js' + +await run(commandTree, process.argv.slice(2)) From cbd3b1fa81e6c8cb2917fcd857a8902519c17bcc Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 13:04:47 +0800 Subject: [PATCH 08/11] simplify build --- cli/bin/run.js | 6 ------ cli/bin/run.ts | 8 ++++---- cli/package.json | 3 --- cli/scripts/release-build.sh | 31 +++++++++++++++++++++---------- 4 files changed, 25 insertions(+), 23 deletions(-) delete mode 100755 cli/bin/run.js diff --git a/cli/bin/run.js b/cli/bin/run.js deleted file mode 100755 index b0c44b653cb61d..00000000000000 --- a/cli/bin/run.js +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env node - -import { commandTree } from '../dist/commands/tree.js' -import { run } from '../dist/framework/run.js' - -await run(commandTree, process.argv.slice(2)) diff --git a/cli/bin/run.ts b/cli/bin/run.ts index 6c753b56380bf8..27b99776be4e13 100755 --- a/cli/bin/run.ts +++ b/cli/bin/run.ts @@ -1,10 +1,10 @@ #!/usr/bin/env node // Production entry compiled by `bun build --compile` (see scripts/release-build.sh). // Imports from src/ so the release pipeline doesn't need `pnpm build` (dist/). -// -// bin/run.js is kept for the local `pnpm build` + node execute path; this file -// is only consumed by Bun. import { commandTree } from '../src/commands/tree.js' import { run } from '../src/framework/run.js' -await run(commandTree, process.argv.slice(2)) +// Wrapped instead of top-level await — `bun build --bytecode` doesn't support TLA. +void (async () => { + await run(commandTree, process.argv.slice(2)) +})() diff --git a/cli/package.json b/cli/package.json index 43c925d37a66e5..019e361b048538 100644 --- a/cli/package.json +++ b/cli/package.json @@ -17,9 +17,6 @@ "import": "./dist/index.js" } }, - "bin": { - "difyctl": "./bin/run.js" - }, "files": [ "README.md", "bin", diff --git a/cli/scripts/release-build.sh b/cli/scripts/release-build.sh index 3014a901e3cc97..500af0f7286a5a 100755 --- a/cli/scripts/release-build.sh +++ b/cli/scripts/release-build.sh @@ -10,9 +10,15 @@ # `NPM_CONFIG_USERCONFIG=cli/scripts/cross-arch.npmrc pnpm install --force` # to populate them. # -# Required env: CLI_VERSION, DIFYCTL_CHANNEL, DIFYCTL_MIN_DIFY, DIFYCTL_MAX_DIFY, -# DIFYCTL_COMMIT, DIFYCTL_BUILD_DATE. -# Output: dist/bin/difyctl-v-[.exe] +# Env (all optional; defaults derived from cli/package.json + git): +# CLI_VERSION — package.json `version` +# DIFYCTL_CHANNEL — package.json `difyctl.channel` +# DIFYCTL_MIN_DIFY — package.json `difyctl.compat.minDify` +# DIFYCTL_MAX_DIFY — package.json `difyctl.compat.maxDify` +# DIFYCTL_COMMIT — `git rev-parse HEAD` (or "unknown") +# DIFYCTL_BUILD_DATE — current UTC time +# +# Output: dist/bin/difyctl-v-[.exe] set -euo pipefail @@ -22,17 +28,21 @@ source "${_dir}/lib/common.sh" require bun -: "${CLI_VERSION:?CLI_VERSION is required}" -: "${DIFYCTL_CHANNEL:?DIFYCTL_CHANNEL is required}" -: "${DIFYCTL_MIN_DIFY:?DIFYCTL_MIN_DIFY is required}" -: "${DIFYCTL_MAX_DIFY:?DIFYCTL_MAX_DIFY is required}" -: "${DIFYCTL_COMMIT:?DIFYCTL_COMMIT is required}" -: "${DIFYCTL_BUILD_DATE:?DIFYCTL_BUILD_DATE is required}" - cli_root="$(cli::root)" entry="${cli_root}/bin/run.ts" out_dir="${cli_root}/dist/bin" +read_pkg() { node -p "require('${cli_root}/package.json').$1" 2>/dev/null; } + +CLI_VERSION="${CLI_VERSION:-$(read_pkg version)}" +DIFYCTL_CHANNEL="${DIFYCTL_CHANNEL:-$(read_pkg difyctl.channel)}" +DIFYCTL_MIN_DIFY="${DIFYCTL_MIN_DIFY:-$(read_pkg difyctl.compat.minDify)}" +DIFYCTL_MAX_DIFY="${DIFYCTL_MAX_DIFY:-$(read_pkg difyctl.compat.maxDify)}" +DIFYCTL_COMMIT="${DIFYCTL_COMMIT:-$(git -C "$cli_root" rev-parse HEAD 2>/dev/null || echo unknown)}" +DIFYCTL_BUILD_DATE="${DIFYCTL_BUILD_DATE:-$(date -u +%Y-%m-%dT%H:%M:%SZ)}" + +[[ "$CLI_VERSION" != "undefined" ]] || die "CLI_VERSION could not be derived from package.json" + [[ -f "$entry" ]] || die "entry not found: $entry" rm -rf "$out_dir" @@ -72,6 +82,7 @@ for spec in "${targets[@]}"; do bun build "$entry" \ --target="$bun_target" \ --compile \ + --minify \ "${defines[@]}" \ --outfile="$out" >/dev/null done From b4920e73e0a9f3392fc75a8a45124b7c505a6199 Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 14:01:39 +0800 Subject: [PATCH 09/11] use release asset --- .github/workflows/cli-release.yml | 37 +++++++++++++++++++++++-------- cli/package.json | 4 ++-- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/.github/workflows/cli-release.yml b/.github/workflows/cli-release.yml index 60b722c6430d1f..68578827eb6c71 100644 --- a/.github/workflows/cli-release.yml +++ b/.github/workflows/cli-release.yml @@ -13,7 +13,7 @@ jobs: runs-on: depot-ubuntu-24.04 if: github.repository == 'langgenius/dify' permissions: - contents: read + contents: write defaults: run: shell: bash @@ -73,11 +73,30 @@ jobs: CLI_VERSION: ${{ steps.manifest.outputs.version }} run: scripts/release-write-checksums.sh - - name: Upload release artifact - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: difyctl-${{ steps.manifest.outputs.version }} - path: | - cli/dist/bin/difyctl-v* - retention-days: 21 - if-no-files-found: error + - name: Publish GitHub Release + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + TAG: difyctl-v${{ steps.manifest.outputs.version }} + VERSION: ${{ steps.manifest.outputs.version }} + CHANNEL: ${{ steps.manifest.outputs.channel }} + working-directory: ./cli/dist/bin + run: | + prerelease_flag="" + if [ "$CHANNEL" != "stable" ]; then + prerelease_flag="--prerelease" + fi + + if gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then + echo "Release $TAG exists — replacing assets" + gh release upload "$TAG" --repo "$REPO" --clobber difyctl-v* + else + echo "Creating release $TAG" + gh release create "$TAG" \ + --repo "$REPO" \ + --target "$GITHUB_SHA" \ + --title "difyctl $VERSION" \ + --notes "Automated release built by \`cli-release.yml\` (commit ${GITHUB_SHA:0:7})." \ + $prerelease_flag \ + difyctl-v* + fi diff --git a/cli/package.json b/cli/package.json index 019e361b048538..d5e9ba46d63a3d 100644 --- a/cli/package.json +++ b/cli/package.json @@ -6,8 +6,8 @@ "difyctl": { "channel": "rc", "compat": { - "minDify": "1.6.0", - "maxDify": "1.7.0" + "minDify": "1.14.0", + "maxDify": "1.15.0" } }, "license": "Apache-2.0", From 7bff0f50d1573bfbd8abbc4d74b69fe3cebadcbe Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 14:09:41 +0800 Subject: [PATCH 10/11] use --help as single source of truth --- cli/README.md | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/cli/README.md b/cli/README.md index 3c1b98c33219b4..4d46465945dfdd 100644 --- a/cli/README.md +++ b/cli/README.md @@ -37,17 +37,7 @@ Background docs: `difyctl help account`, `difyctl help external`, `difyctl help ## Commands -| Group | Commands | -| ---------- | -------------------------------------------------------------------------------------------------- | -| `auth` | `login`, `logout`, `status`, `whoami`, `use `, `devices list/revoke` | -| `get` | `get app [] [-A] [--mode] [--name] [--tag] [-o json\|yaml\|name\|wide]`, `get workspace` | -| `describe` | `describe app [--refresh] [-o json\|yaml]` | -| `run` | `run app [] [--input k=v]... [--conversation ] [--stream] [-o json\|yaml\|text]` | -| `config` | `view`, `get `, `set `, `unset `, `path` | -| `env` | `list` | -| `help` | `account`, `external`, `environment` | -| `version` | `version [--json]` | - +Run `difyctl --help` for the full list of commands. Run `difyctl --help` for per-command reference. ## Output formats From a3659d8432a4a52282653c79fed8fd2153f72e48 Mon Sep 17 00:00:00 2001 From: "yunlu.wen" Date: Tue, 19 May 2026 14:50:37 +0800 Subject: [PATCH 11/11] replace tsx with bun --- cli/bin/dev.js | 2 +- cli/package.json | 9 +- cli/scripts/run-smoke.ts | 4 +- pnpm-lock.yaml | 367 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 356 insertions(+), 26 deletions(-) diff --git a/cli/bin/dev.js b/cli/bin/dev.js index f44b1d8b17e1e3..bb141c29a95b48 100755 --- a/cli/bin/dev.js +++ b/cli/bin/dev.js @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --import tsx +#!/usr/bin/env -S bun globalThis.__DIFYCTL_VERSION__ = process.env.DIFYCTL_VERSION ?? '0.0.0-dev' globalThis.__DIFYCTL_COMMIT__ = process.env.DIFYCTL_COMMIT ?? 'HEAD' diff --git a/cli/package.json b/cli/package.json index d5e9ba46d63a3d..ae72de309cf1a8 100644 --- a/cli/package.json +++ b/cli/package.json @@ -27,20 +27,20 @@ }, "scripts": { "build": "vp pack", - "dev": "tsx bin/dev.js", + "dev": "bun bin/dev.js", "test": "vp test", "test:coverage": "vp test --coverage", "lint": "eslint", "lint:fix": "eslint --fix", "type-check": "tsc", - "tree:gen": "tsx scripts/generate-command-tree.ts", - "tree:check": "tsx scripts/generate-command-tree.ts --check", + "tree:gen": "bun scripts/generate-command-tree.ts", + "tree:check": "bun scripts/generate-command-tree.ts --check", "prebuild": "pnpm tree:gen", "predev": "pnpm tree:gen", "pretest": "pnpm tree:gen", "ci": "pnpm tree:check && pnpm type-check && pnpm lint && pnpm test:coverage && pnpm build", "clean": "rm -rf dist node_modules/.cache", - "version:info": "tsx scripts/print-buildinfo.ts", + "version:info": "bun scripts/print-buildinfo.ts", "docker:build-dev": "scripts/docker-build-dev.sh", "sync-models": "scripts/sync-models.sh", "build:bin": "scripts/release-build.sh" @@ -65,7 +65,6 @@ "@vitest/coverage-v8": "catalog:", "eslint": "catalog:", "hono": "catalog:", - "tsx": "catalog:", "typescript": "catalog:", "vite": "catalog:", "vite-plus": "catalog:", diff --git a/cli/scripts/run-smoke.ts b/cli/scripts/run-smoke.ts index e83f35a4fb8cd7..7c4e776393701c 100644 --- a/cli/scripts/run-smoke.ts +++ b/cli/scripts/run-smoke.ts @@ -1,4 +1,4 @@ -#!/usr/bin/env -S node --import tsx +#!/usr/bin/env -S bun import { execSync } from 'node:child_process' type Check = { name: string, run: () => void } @@ -13,7 +13,7 @@ if (!baseUrl) { const env = { ...process.env, DIFY_BASE_URL: baseUrl } function cli(args: string): string { - return execSync(`pnpm exec tsx bin/dev.js ${args}`, { env, encoding: 'utf8' }) + return execSync(`bun bin/dev.js ${args}`, { env, encoding: 'utf8' }) } const checks: Check[] = [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb2e43f7c6409e..545474ed399d59 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -619,7 +619,7 @@ importers: devDependencies: '@antfu/eslint-config': specifier: 'catalog:' - version: 9.0.0(@eslint-react/eslint-plugin@5.7.7(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@next/eslint-plugin-next@16.2.6)(@types/node@25.7.0)(@typescript-eslint/typescript-estree@8.59.3(typescript@6.0.3))(@typescript-eslint/utils@8.59.3(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.3.0(jiti@2.7.0)))(eslint@10.3.0(jiti@2.7.0))(happy-dom@20.9.0)(jiti@2.7.0)(oxlint@1.61.0(oxlint-tsgolint@0.22.0))(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 9.0.0(@eslint-react/eslint-plugin@5.7.7(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@next/eslint-plugin-next@16.2.6)(@types/node@25.7.0)(@typescript-eslint/typescript-estree@8.59.3(typescript@6.0.3))(@typescript-eslint/utils@8.59.3(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.3.0(jiti@2.7.0)))(eslint@10.3.0(jiti@2.7.0))(happy-dom@20.9.0)(jiti@2.7.0)(oxlint@1.61.0(oxlint-tsgolint@0.22.0))(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) concurrently: specifier: 'catalog:' version: 9.2.1 @@ -640,7 +640,7 @@ importers: version: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) cli: dependencies: @@ -696,9 +696,6 @@ importers: hono: specifier: 'catalog:' version: 4.12.18 - tsx: - specifier: 'catalog:' - version: 4.21.0 typescript: specifier: 'catalog:' version: 6.0.3 @@ -740,7 +737,7 @@ importers: version: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) packages/contracts: dependencies: @@ -777,7 +774,7 @@ importers: version: 6.0.3 vite-plus: specifier: 'catalog:' - version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) packages/dev-proxy: dependencies: @@ -805,10 +802,10 @@ importers: version: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) vitest: specifier: npm:@voidzero-dev/vite-plus-test@0.1.20 - version: '@voidzero-dev/vite-plus-test@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + version: '@voidzero-dev/vite-plus-test@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' packages/dify-ui: dependencies: @@ -824,7 +821,7 @@ importers: version: 1.4.1(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@chromatic-com/storybook': specifier: 'catalog:' - version: 5.1.2(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + version: 5.1.2(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) '@dify/tsconfig': specifier: workspace:* version: link:../tsconfig @@ -836,16 +833,16 @@ importers: version: 1.2.10 '@storybook/addon-docs': specifier: 'catalog:' - version: 10.3.6(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + version: 10.3.6(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) '@storybook/addon-links': specifier: 'catalog:' - version: 10.3.6(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + version: 10.3.6(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) '@storybook/addon-themes': specifier: 'catalog:' - version: 10.3.6(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + version: 10.3.6(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) '@storybook/react-vite': specifier: 'catalog:' - version: 10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3) + version: 10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3) '@tailwindcss/vite': specifier: 'catalog:' version: 4.3.0(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) @@ -881,7 +878,7 @@ importers: version: 19.2.6(react@19.2.6) storybook: specifier: 'catalog:' - version: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + version: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) tailwindcss: specifier: 'catalog:' version: 4.3.0 @@ -893,7 +890,7 @@ importers: version: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) vitest-browser-react: specifier: 'catalog:' version: 2.2.0(@types/node@25.7.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) @@ -927,7 +924,7 @@ importers: version: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' vite-plus: specifier: 'catalog:' - version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + version: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) packages/tsconfig: {} @@ -9025,6 +9022,87 @@ snapshots: - vite - yaml + '@antfu/eslint-config@9.0.0(@eslint-react/eslint-plugin@5.7.7(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@next/eslint-plugin-next@16.2.6)(@types/node@25.7.0)(@typescript-eslint/typescript-estree@8.59.3(typescript@6.0.3))(@typescript-eslint/utils@8.59.3(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(eslint-plugin-react-refresh@0.5.2(eslint@10.3.0(jiti@2.7.0)))(eslint@10.3.0(jiti@2.7.0))(happy-dom@20.9.0)(jiti@2.7.0)(oxlint@1.61.0(oxlint-tsgolint@0.22.0))(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)': + dependencies: + '@antfu/install-pkg': 1.1.0 + '@clack/prompts': 1.4.0 + '@e18e/eslint-plugin': 0.4.1(eslint@10.3.0(jiti@2.7.0))(oxlint@1.61.0(oxlint-tsgolint@0.22.0)) + '@eslint-community/eslint-plugin-eslint-comments': 4.7.1(eslint@10.3.0(jiti@2.7.0)) + '@eslint/markdown': 8.0.1 + '@stylistic/eslint-plugin': 5.10.0(eslint@10.3.0(jiti@2.7.0)) + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + '@typescript-eslint/parser': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + '@vitest/eslint-plugin': 1.6.17(@types/node@25.7.0)(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(eslint@10.3.0(jiti@2.7.0))(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + ansis: 4.2.0 + cac: 7.0.0 + eslint: 10.3.0(jiti@2.7.0) + eslint-config-flat-gitignore: 2.3.0(eslint@10.3.0(jiti@2.7.0)) + eslint-flat-config-utils: 3.2.0 + eslint-merge-processors: 2.0.0(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-antfu: 3.2.3(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-command: 3.5.2(@typescript-eslint/typescript-estree@8.59.3(typescript@6.0.3))(@typescript-eslint/utils@8.59.3(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-import-lite: 0.6.0(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-jsdoc: 62.9.0(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-jsonc: 3.1.2(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-n: 18.0.1(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-no-only-tests: 3.4.0 + eslint-plugin-perfectionist: 5.9.0(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + eslint-plugin-pnpm: 1.6.0(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-regexp: 3.1.0(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-toml: 1.3.1(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-unicorn: 64.0.0(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-unused-imports: 4.4.1(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0)) + eslint-plugin-vue: 10.9.1(@stylistic/eslint-plugin@5.10.0(eslint@10.3.0(jiti@2.7.0)))(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(vue-eslint-parser@10.4.0(eslint@10.3.0(jiti@2.7.0))) + eslint-plugin-yml: 3.3.2(eslint@10.3.0(jiti@2.7.0)) + eslint-processor-vue-blocks: 2.0.0(eslint@10.3.0(jiti@2.7.0)) + globals: 17.6.0 + local-pkg: 1.1.2 + parse-gitignore: 2.0.0 + toml-eslint-parser: 1.0.3 + vue-eslint-parser: 10.4.0(eslint@10.3.0(jiti@2.7.0)) + yaml-eslint-parser: 2.0.0 + optionalDependencies: + '@eslint-react/eslint-plugin': 5.7.7(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + '@next/eslint-plugin-next': 16.2.6 + eslint-plugin-react-refresh: 0.5.2(eslint@10.3.0(jiti@2.7.0)) + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@edge-runtime/vm' + - '@eslint/json' + - '@opentelemetry/api' + - '@tsdown/css' + - '@tsdown/exe' + - '@types/node' + - '@typescript-eslint/rule-tester' + - '@typescript-eslint/typescript-estree' + - '@typescript-eslint/utils' + - '@vitejs/devtools' + - '@vitest/coverage-istanbul' + - '@vitest/coverage-v8' + - '@vitest/ui' + - '@vue/compiler-sfc' + - bufferutil + - esbuild + - happy-dom + - jiti + - jsdom + - less + - oxlint + - publint + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - ts-declaration-location + - tsx + - typescript + - unplugin-unused + - utf-8-validate + - vite + - yaml + '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.6.0 @@ -9190,6 +9268,18 @@ snapshots: - '@chromatic-com/cypress' - '@chromatic-com/playwright' + '@chromatic-com/storybook@5.1.2(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + '@neoconfetti/react': 1.0.0 + chromatic: 13.3.5 + filesize: 10.1.6 + jsonfile: 6.2.0 + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + strip-ansi: 7.2.0 + transitivePeerDependencies: + - '@chromatic-com/cypress' + - '@chromatic-com/playwright' + '@clack/core@1.3.1': dependencies: fast-wrap-ansi: 0.2.0 @@ -11014,6 +11104,23 @@ snapshots: - vite - webpack + '@storybook/addon-docs@10.3.6(@types/react@19.2.14)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.6) + '@storybook/csf-plugin': 10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + '@storybook/icons': 2.0.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@storybook/react-dom-shim': 10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + ts-dedent: 2.2.0 + transitivePeerDependencies: + - '@types/react' + - esbuild + - rollup + - vite + - webpack + '@storybook/addon-links@10.3.6(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': dependencies: '@storybook/global': 5.0.0 @@ -11021,6 +11128,13 @@ snapshots: optionalDependencies: react: 19.2.6 + '@storybook/addon-links@10.3.6(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + '@storybook/global': 5.0.0 + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + optionalDependencies: + react: 19.2.6 + '@storybook/addon-onboarding@10.3.6(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': dependencies: storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) @@ -11030,6 +11144,11 @@ snapshots: storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) ts-dedent: 2.2.0 + '@storybook/addon-themes@10.3.6(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + ts-dedent: 2.2.0 + '@storybook/builder-vite@10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': dependencies: '@storybook/csf-plugin': 10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) @@ -11041,6 +11160,17 @@ snapshots: - rollup - webpack + '@storybook/builder-vite@10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + '@storybook/csf-plugin': 10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + ts-dedent: 2.2.0 + vite: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + transitivePeerDependencies: + - esbuild + - rollup + - webpack + '@storybook/csf-plugin@10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': dependencies: storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) @@ -11049,6 +11179,14 @@ snapshots: esbuild: 0.27.2 vite: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + '@storybook/csf-plugin@10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + unplugin: 2.3.11 + optionalDependencies: + esbuild: 0.27.2 + vite: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + '@storybook/global@5.0.0': {} '@storybook/icons@2.0.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': @@ -11084,6 +11222,12 @@ snapshots: react-dom: 19.2.6(react@19.2.6) storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + '@storybook/react-dom-shim@10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))': + dependencies: + react: 19.2.6 + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + '@storybook/react-vite@10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3)': dependencies: '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(typescript@6.0.3) @@ -11106,6 +11250,28 @@ snapshots: - typescript - webpack + '@storybook/react-vite@10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3)': + dependencies: + '@joshwooding/vite-plugin-react-docgen-typescript': 0.7.0(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(typescript@6.0.3) + '@rollup/pluginutils': 5.3.0 + '@storybook/builder-vite': 10.3.6(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + '@storybook/react': 10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3) + empathic: 2.0.0 + magic-string: 0.30.21 + react: 19.2.6 + react-docgen: 8.0.3 + react-dom: 19.2.6(react@19.2.6) + resolve: 1.22.11 + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + tsconfig-paths: 4.2.0 + vite: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + transitivePeerDependencies: + - esbuild + - rollup + - supports-color + - typescript + - webpack + '@storybook/react@10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3)': dependencies: '@storybook/global': 5.0.0 @@ -11120,6 +11286,20 @@ snapshots: transitivePeerDependencies: - supports-color + '@storybook/react@10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)))(typescript@6.0.3)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/react-dom-shim': 10.3.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))) + react: 19.2.6 + react-docgen: 8.0.3 + react-docgen-typescript: 2.4.0(typescript@6.0.3) + react-dom: 19.2.6(react@19.2.6) + storybook: 10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)) + optionalDependencies: + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + '@streamdown/math@1.0.2(react@19.2.6)': dependencies: katex: 0.16.45 @@ -12047,6 +12227,45 @@ snapshots: - vite - yaml + '@vitest/eslint-plugin@1.6.17(@types/node@25.7.0)(@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(eslint@10.3.0(jiti@2.7.0))(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/utils': 8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + eslint: 10.3.0(jiti@2.7.0) + vitest: '@voidzero-dev/vite-plus-test@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.59.2(@typescript-eslint/parser@8.59.2(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3))(eslint@10.3.0(jiti@2.7.0))(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@edge-runtime/vm' + - '@opentelemetry/api' + - '@tsdown/css' + - '@tsdown/exe' + - '@types/node' + - '@vitejs/devtools' + - '@vitest/coverage-istanbul' + - '@vitest/coverage-v8' + - '@vitest/ui' + - bufferutil + - esbuild + - happy-dom + - jiti + - jsdom + - less + - publint + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - unplugin-unused + - utf-8-validate + - vite + - yaml + '@vitest/expect@3.2.4': dependencies: '@types/chai': 5.2.3 @@ -12153,6 +12372,47 @@ snapshots: - utf-8-validate - yaml + '@voidzero-dev/vite-plus-test@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)': + dependencies: + '@standard-schema/spec': 1.1.0 + '@types/chai': 5.2.3 + '@voidzero-dev/vite-plus-core': 0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + es-module-lexer: 1.7.0 + obug: 2.1.1 + pixelmatch: 7.1.0 + pngjs: 7.0.0 + sirv: 3.0.2 + std-env: 4.0.0 + tinybench: 2.9.0 + tinyexec: 1.0.4 + tinyglobby: 0.2.16 + vite: '@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + ws: 8.20.0 + optionalDependencies: + '@types/node': 25.7.0 + '@vitest/coverage-v8': 4.1.6(@voidzero-dev/vite-plus-test@0.1.20) + happy-dom: 20.9.0 + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@tsdown/css' + - '@tsdown/exe' + - '@vitejs/devtools' + - bufferutil + - esbuild + - jiti + - less + - publint + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - typescript + - unplugin-unused + - utf-8-validate + - yaml + '@voidzero-dev/vite-plus-win32-arm64-msvc@0.1.20': optional: true @@ -16051,6 +16311,30 @@ snapshots: - react-dom - utf-8-validate + storybook@10.3.6(@testing-library/dom@10.4.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)): + dependencies: + '@storybook/global': 5.0.0 + '@storybook/icons': 2.0.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + '@testing-library/jest-dom': 6.9.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.1) + '@vitest/expect': 3.2.4 + '@vitest/spy': 3.2.4 + '@webcontainer/env': 1.1.1 + esbuild: 0.27.2 + open: 10.2.0 + recast: 0.23.11 + semver: 7.7.4 + use-sync-external-store: 1.6.0(react@19.2.6) + ws: 8.20.0 + optionalDependencies: + vite-plus: 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + transitivePeerDependencies: + - '@testing-library/dom' + - bufferutil + - react + - react-dom + - utf-8-validate + streamdown@2.5.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: clsx: 2.1.1 @@ -16618,6 +16902,53 @@ snapshots: - vite - yaml + vite-plus@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3): + dependencies: + '@oxc-project/types': 0.127.0 + '@voidzero-dev/vite-plus-core': 0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3) + oxfmt: 0.46.0 + oxlint: 1.61.0(oxlint-tsgolint@0.22.0) + oxlint-tsgolint: 0.22.0 + optionalDependencies: + '@voidzero-dev/vite-plus-darwin-arm64': 0.1.20 + '@voidzero-dev/vite-plus-darwin-x64': 0.1.20 + '@voidzero-dev/vite-plus-linux-arm64-gnu': 0.1.20 + '@voidzero-dev/vite-plus-linux-arm64-musl': 0.1.20 + '@voidzero-dev/vite-plus-linux-x64-gnu': 0.1.20 + '@voidzero-dev/vite-plus-linux-x64-musl': 0.1.20 + '@voidzero-dev/vite-plus-win32-arm64-msvc': 0.1.20 + '@voidzero-dev/vite-plus-win32-x64-msvc': 0.1.20 + transitivePeerDependencies: + - '@arethetypeswrong/core' + - '@edge-runtime/vm' + - '@opentelemetry/api' + - '@tsdown/css' + - '@tsdown/exe' + - '@types/node' + - '@vitejs/devtools' + - '@vitest/coverage-istanbul' + - '@vitest/coverage-v8' + - '@vitest/ui' + - bufferutil + - esbuild + - happy-dom + - jiti + - jsdom + - less + - publint + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - typescript + - unplugin-unused + - utf-8-validate + - vite + - yaml + vite-tsconfig-paths@5.1.4(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(typescript@6.0.3): dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -16647,7 +16978,7 @@ snapshots: dependencies: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - vitest: '@voidzero-dev/vite-plus-test@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6(@voidzero-dev/vite-plus-test@0.1.20))(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' + vitest: '@voidzero-dev/vite-plus-test@0.1.20(@types/node@25.7.0)(@vitest/coverage-v8@4.1.6)(@voidzero-dev/vite-plus-core@0.1.20(@types/node@25.7.0)(esbuild@0.27.2)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3))(esbuild@0.27.2)(happy-dom@20.9.0)(jiti@2.7.0)(tsx@4.21.0)(typescript@6.0.3)(yaml@2.8.3)' optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14)