ci: 重构 CI 工作流并统一构建发布流程

- 删除 build.yml 和 release.yml,合并为单一 ci.yml
- 新增版本一致性校验及 tag 匹配检查
- 使用 npm ci 与 Cargo --locked 锁定依赖
- 缓存 Tauri CLI 2.12.1 并按 tag 触发发布
- 提交 package-lock.json 并忽略生成的 tailwind.css
This commit is contained in:
ASLant committed 2026-10-07 12:00:09 +08:00
1 parent dc38076476
commit 721cdb25d5
9 files changed
+2860 -236

No files matched your search

-59
View File
@@ -1,59 +0,0 @@
name: Build
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
env:
CARGO_TERM_COLOR: always
jobs:
build:
if: >
contains(github.event.head_commit.message, 'build:') ||
github.event_name == 'pull_request'
strategy:
fail-fast: false
matrix:
platform:
- os: windows-latest
target: x86_64-pc-windows-msvc
name: Windows x64
runs-on: ${{ matrix.platform.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform.target }}
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2.0.0" --locked
- name: Build Tauri app
working-directory: ./src-tauri
run: cargo tauri build --verbose
- name: Upload artifacts (Windows)
if: matrix.platform.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: UPX-Tools-${{ matrix.platform.name }}
path: |
src-tauri/target/release/bundle/msi/*.msi
src-tauri/target/release/bundle/nsis/*.exe
if-no-files-found: warn
+130 -27
View File
@@ -2,45 +2,148 @@ name: CI
on: on:
push: push:
branches: [ main, master ] branches: [main, master]
tags: tags: ['v*']
- 'v*'
pull_request: pull_request:
branches: [ main, master ] branches: [main, master]
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }}
env: env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} npm_config_loglevel: warn
TAURI_CLI_VERSION: '2.12.1'
jobs: jobs:
test: build:
name: Check and build Windows x64
runs-on: windows-latest runs-on: windows-latest
if: > timeout-minutes: 45
contains(github.event.head_commit.message, 'build:') || outputs:
contains(github.event.head_commit.message, 'tag') || version: ${{ steps.version.outputs.version }}
startsWith(github.ref, 'refs/tags/') ||
github.event_name == 'pull_request'
steps: steps:
- name: Checkout repository - uses: actions/checkout@v4
uses: actions/checkout@v4 with:
persist-credentials: false
- name: Setup Rust - uses: actions/setup-node@v4
uses: dtolnay/rust-toolchain@stable with:
node-version: '22'
cache: npm
- name: Rust cache - uses: dtolnay/rust-toolchain@stable
uses: Swatinem/rust-cache@v2 with:
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with: with:
workspaces: './src-tauri -> target' workspaces: './src-tauri -> target'
- name: Check formatting - name: Validate versions
working-directory: ./src-tauri id: version
run: cargo fmt --all -- --check shell: pwsh
run: |
$version = (Get-Content package.json -Raw -Encoding utf8 | ConvertFrom-Json).version
$tauriVersion = (Get-Content src-tauri/tauri.conf.json -Raw -Encoding utf8 | ConvertFrom-Json).version
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
$metadata = cargo metadata --manifest-path src-tauri/Cargo.toml --locked --no-deps --format-version 1
if ($LASTEXITCODE -ne 0) { throw 'Cannot read Cargo package version' }
$cargoVersion = ($metadata | ConvertFrom-Json).packages[0].version
if ($version -cne $tauriVersion -or $version -cne $cargoVersion) {
throw "Version mismatch: npm=$version, Tauri=$tauriVersion, Cargo=$cargoVersion"
}
if ($env:GITHUB_REF -like 'refs/tags/*' -and $env:GITHUB_REF -cne "refs/tags/v$version") {
throw "Tag $env:GITHUB_REF does not match v$version"
}
Add-Content -Path $env:GITHUB_OUTPUT -Value "version=$version" -Encoding utf8
- name: Run clippy - name: Install frontend dependencies
working-directory: ./src-tauri run: npm ci
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run tests - name: Check frontend
working-directory: ./src-tauri run: npm run check
run: cargo test
- name: Check Rust
run: |
cargo fmt --manifest-path src-tauri/Cargo.toml --all -- --check
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
cargo clippy --manifest-path src-tauri/Cargo.toml --locked --all-targets --all-features -- -D warnings
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
cargo test --manifest-path src-tauri/Cargo.toml --locked
- name: Cache Tauri CLI
id: tauri-cli
uses: actions/cache@v4
with:
path: ~/.cargo/bin/cargo-tauri.exe
key: tauri-cli-${{ env.TAURI_CLI_VERSION }}-windows-x64
- name: Install Tauri CLI
if: steps.tauri-cli.outputs.cache-hit != 'true'
run: cargo install tauri-cli --version "=$env:TAURI_CLI_VERSION" --locked
- name: Build CSS
run: npm run build:css
- name: Build application and installers
run: npm run build
- name: Prepare artifacts
shell: pwsh
env:
APP_VERSION: ${{ steps.version.outputs.version }}
run: |
$version = $env:APP_VERSION
$files = @{
'src-tauri/target/release/bundle/Portable/UPX-Tools.exe' = "UPX-Tools-$version-x64-portable.exe"
"src-tauri/target/release/bundle/msi/UPX-Tools_${version}_x64_zh-CN.msi" = "UPX-Tools-$version-x64.msi"
"src-tauri/target/release/bundle/nsis/UPX-Tools_${version}_x64-setup.exe" = "UPX-Tools-$version-x64-setup.exe"
}
foreach ($source in $files.Keys) {
if (!(Test-Path -LiteralPath $source -PathType Leaf) -or (Get-Item -LiteralPath $source).Length -eq 0) {
throw "Missing or empty build artifact: $source"
}
}
New-Item release -ItemType Directory -Force | Out-Null
foreach ($source in $files.Keys) {
Copy-Item -LiteralPath $source -Destination (Join-Path release $files[$source])
}
- name: Upload Windows packages
uses: actions/upload-artifact@v4
with:
name: UPX-Tools-Windows-x64
path: release/*
if-no-files-found: error
compression-level: 0
release:
name: Publish release
needs: build
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
steps:
- uses: actions/download-artifact@v4
with:
name: UPX-Tools-Windows-x64
path: release
- uses: softprops/action-gh-release@v2
with:
files: |
release/UPX-Tools-${{ needs.build.outputs.version }}-x64-portable.exe
release/UPX-Tools-${{ needs.build.outputs.version }}-x64.msi
release/UPX-Tools-${{ needs.build.outputs.version }}-x64-setup.exe
fail_on_unmatched_files: true
prerelease: ${{ contains(needs.build.outputs.version, '-') }}
generate_release_notes: true
-127
View File
@@ -1,127 +0,0 @@
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
release:
strategy:
fail-fast: false
matrix:
platform:
- os: windows-latest
target: x86_64-pc-windows-msvc
name: Windows-x64
runs-on: ${{ matrix.platform.os }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.platform.target }}
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: './src-tauri -> target'
- name: Install Tauri CLI
run: cargo install tauri-cli --version "^2.0.0" --locked
- name: Build Tauri app
working-directory: ./src-tauri
run: cargo tauri build --verbose
- name: Copy portable exe to bundle
shell: pwsh
run: |
Write-Host "=== Checking release directory ==="
Get-ChildItem -Path "src-tauri/target/release/" -Filter "*.exe" | ForEach-Object { Write-Host $_.FullName }
$sourceExe = "src-tauri/target/release/UPX-Tools.exe"
if (Test-Path $sourceExe) {
New-Item -Path "src-tauri/target/release/bundle/Portable" -ItemType Directory -Force
Copy-Item $sourceExe "src-tauri/target/release/bundle/Portable/"
Write-Host "Portable exe copied successfully"
} else {
Write-Host "WARNING: $sourceExe not found!"
Write-Host "Available files:"
Get-ChildItem -Path "src-tauri/target/release/" -Recurse -Filter "*.exe" | ForEach-Object { Write-Host $_.FullName }
}
- name: Get version from tag
id: get_version
shell: bash
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Prepare release files (Windows)
if: matrix.platform.os == 'windows-latest'
shell: pwsh
run: |
New-Item -Path "release" -ItemType Directory -Force
$version = "${env:GITHUB_REF}" -replace "refs/tags/v", ""
Write-Host "=== Version: $version ==="
# 复制便携版 (单文件,已嵌入 UPX)
$portableExe = "src-tauri/target/release/bundle/Portable/UPX-Tools.exe"
Write-Host "Checking portable: $portableExe"
if (Test-Path $portableExe) {
$newName = "UPX-Tools-${version}-x64-portable.exe"
Copy-Item $portableExe -Destination "release/$newName"
Write-Host "✓ Created: $newName"
} else {
# 尝试从 release 目录直接复制
$fallbackExe = "src-tauri/target/release/UPX-Tools.exe"
Write-Host "Portable not found, trying fallback: $fallbackExe"
if (Test-Path $fallbackExe) {
$newName = "UPX-Tools-${version}-x64-portable.exe"
Copy-Item $fallbackExe -Destination "release/$newName"
Write-Host "✓ Created (fallback): $newName"
} else {
Write-Host "✗ Portable exe not found!"
}
}
# 复制并重命名 MSI 文件
Get-ChildItem -Path "src-tauri/target/release/bundle/msi/*.msi" -ErrorAction SilentlyContinue | ForEach-Object {
$newName = "UPX-Tools-${version}-x64.msi"
Copy-Item $_.FullName -Destination "release/$newName"
Write-Host "✓ Created: $newName"
}
# 复制并重命名 NSIS 文件
Get-ChildItem -Path "src-tauri/target/release/bundle/nsis/*.exe" -ErrorAction SilentlyContinue | ForEach-Object {
$newName = "UPX-Tools-${version}-x64-setup.exe"
Copy-Item $_.FullName -Destination "release/$newName"
Write-Host "✓ Created: $newName"
}
Write-Host "=== Release files ==="
Get-ChildItem -Path "release/" | ForEach-Object { Write-Host " - $($_.Name) ($($_.Length) bytes)" }
- name: Upload release assets
uses: softprops/action-gh-release@v2
with:
files: release/*
draft: false
prerelease: false
generate_release_notes: true
fail_on_unmatched_files: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-1
View File
@@ -19,7 +19,6 @@ target
# Node.js # Node.js
node_modules/ node_modules/
package-lock.json
dist/ dist/
# RustRover # RustRover
+1
View File
@@ -8,3 +8,4 @@ img/
dist/ dist/
target/ target/
package-lock.json package-lock.json
ui/css/tailwind.css
+12 -9
View File
@@ -26,7 +26,7 @@ npm run build:css
cargo tauri dev cargo tauri dev
# 编译安装包及 release 主程序(不会自动构建 CSS) # 编译安装包及 release 主程序(不会自动构建 CSS)
cargo tauri build cargo tauri build -- --locked
# 编译产物位置 # 编译产物位置
# src-tauri/target/release/bundle/ # src-tauri/target/release/bundle/
@@ -44,7 +44,7 @@ npm run build:css # 编译并压缩 Tailwind CSS
npm run watch:css # 监听模式编译 Tailwind CSS npm run watch:css # 监听模式编译 Tailwind CSS
# 完整构建(包含便携版复制) # 完整构建(包含便携版复制)
npm run build # 编译 Tauri 并复制便携版到 bundle 目录 npm run build # 锁定 Cargo 依赖构建,再复制便携版;复制失败即中止
# 可选 just 快捷入口(6 个常用入口,底层 npm/Cargo 命令仍可单独运行) # 可选 just 快捷入口(6 个常用入口,底层 npm/Cargo 命令仍可单独运行)
just # 显示菜单,默认配方不在列表中显示 just # 显示菜单,默认配方不在列表中显示
@@ -95,9 +95,9 @@ cargo test --manifest-path src-tauri/Cargo.toml
- `src-tauri/tauri.conf.json` - Tauri 配置,定义窗口属性、权限、打包设置 - `src-tauri/tauri.conf.json` - Tauri 配置,定义窗口属性、权限、打包设置
- `src-tauri/Cargo.toml` - Rust 依赖,release profile 优化(strip、lto、opt-level=z) - `src-tauri/Cargo.toml` - Rust 依赖,release profile 优化(strip、lto、opt-level=z)
- `.justfile` - 可选的开发、CSS 构建、检查和格式化快捷入口 - `.justfile` - 可选的开发、CSS 构建、检查和格式化快捷入口
- `.github/workflows/ci.yml` - Rust 格式检查、严格 clippy 和测试 - `.github/workflows/ci.yml` - 唯一工作流:PR/主分支检查并构建 Windows x64 三种包,`v*` tag 在构建成功后发布已有 artifact
- `.github/workflows/build.yml` - Windows x64 MSI/NSIS 构建与 artifact 上传 - `package-lock.json` / `src-tauri/Cargo.lock` - 随仓库提交;CI 使用 `npm ci` 和 Cargo `--locked`
- `.github/workflows/release.yml` - `v*` tag 自动发布 MSI、NSIS 安装包和 Portable 便携版;不运行前端检查或 CSS 构建 - `.prettierignore` - 排除生成的 `ui/css/tailwind.css`,不格式化压缩产物
## 重要细节 ## 重要细节
@@ -183,11 +183,14 @@ batchSize = Math.max(2, Math.min(cpuCores * 2, 16))
## 版本发布 ## 版本发布
1. 同步修改 `src-tauri/Cargo.toml`、`package.json` 和 `src-tauri/tauri.conf.json` 中的版本号;当前版本均为 `1.5.0`,更新检查使用 `env!("CARGO_PKG_VERSION")` 1. 同步修改 `src-tauri/Cargo.toml`、`package.json` 和 `src-tauri/tauri.conf.json` 中的版本号;当前版本均为 `1.5.0`,更新检查使用 `env!("CARGO_PKG_VERSION")`
2. 在本地运行前端检查并更新 CSS;GitHub Actions 不安装 Node.js,也不运行 Tailwind 构建 2. 同步更新两个锁文件,在本地检查前后端;CI 会自动构建 CSS,不依赖提交消息关键字
3. 推送 tag:`git tag v1.x.x && git push origin v1.x.x` 3. 推送 tag:`git tag v1.x.x && git push origin v1.x.x`;tag 必须与三个版本字段精确一致
4. GitHub Actions 在 Windows x64 上构建并发布 Release,资产版本名取自 tag: 4. `ci.yml` 的 Windows 构建 job 使用 Node.js 22、Rust stable 和固定的 Tauri CLI 2.12.1,依次执行版本校验、前后端检查、CSS 构建和打包;三种产物缺失或为空时失败
5. 发布 job 通过 `needs: build` 等待成功后下载 artifact,仅在 tag push 时运行;版本含 `-` 时标记 prerelease。资产名称:
- `UPX-Tools-{version}-x64.msi` - MSI 安装包 - `UPX-Tools-{version}-x64.msi` - MSI 安装包
- `UPX-Tools-{version}-x64-setup.exe` - NSIS 安装包(当前用户安装) - `UPX-Tools-{version}-x64-setup.exe` - NSIS 安装包(当前用户安装)
- `UPX-Tools-{version}-x64-portable.exe` - 便携版(release 主程序副本,单文件内嵌 UPX,仍依赖 WebView2) - `UPX-Tools-{version}-x64-portable.exe` - 便携版(release 主程序副本,单文件内嵌 UPX,仍依赖 WebView2)
构建环境要求 Windows、Rust stable/MSVC、Microsoft C++ Build Tools、WebView2 和 Tauri CLI 2;前端使用受支持的 Node.js LTS。安装 CLI 使用 `cargo install tauri-cli --version "^2.0.0" --locked`,npm CLI 不替代现有脚本中的 `cargo tauri`。 默认工作流权限为 `contents: read`,只有发布 job 使用 `contents: write`;分支/PR 会取消过时运行,tag 不主动取消正在执行的发布。Tauri CLI 二进制单独缓存,避免每次重新编译 CLI。
构建环境要求 Windows、Rust stable/MSVC、Microsoft C++ Build Tools、WebView2 和 Tauri CLI 2;前端使用 Node.js 22。安装使用 `npm ci` 和 `cargo install tauri-cli --version "=2.12.1" --locked`,npm CLI 不替代脚本中的 `cargo tauri`。
+19 -11
View File
@@ -120,12 +120,14 @@ Windows 依赖安装细节见 [Tauri 官方环境要求](https://v2.tauri.app/st
```bash ```bash
# 安装前端检查、格式化和 CSS 构建依赖 # 安装前端检查、格式化和 CSS 构建依赖
npm install npm ci
# 与 GitHub Actions 一致,安装 Tauri CLI 2 # 与 GitHub Actions 一致,安装 Tauri CLI 2
cargo install tauri-cli --version "^2.0.0" --locked cargo install tauri-cli --version "=2.12.1" --locked
``` ```
`package-lock.json` 和 `src-tauri/Cargo.lock` 随仓库提交。修改依赖或应用版本后同步更新锁文件;CI 使用 `npm ci` 和 Cargo `--locked`,不在构建中自动更新依赖。
确保 `upx/upx.exe` 存在:Rust 的 `include_bytes!` 在编译时读取它,安装包也将它作为资源打包。当前仓库内的 UPX 可执行文件版本为 **5.2.1**,可运行 `upx/upx.exe --version` 核对。 确保 `upx/upx.exe` 存在:Rust 的 `include_bytes!` 在编译时读取它,安装包也将它作为资源打包。当前仓库内的 UPX 可执行文件版本为 **5.2.1**,可运行 `upx/upx.exe --version` 核对。
### 开发与 CSS 构建 ### 开发与 CSS 构建
@@ -179,6 +181,8 @@ cargo clippy --manifest-path src-tauri/Cargo.toml --all-targets --all-features -
前端规范:4 空格缩进、单引号优先、不使用行尾分号。修改前端代码后运行 `npm run format`;修改 Rust 后运行 `cargo fmt`。 前端规范:4 空格缩进、单引号优先、不使用行尾分号。修改前端代码后运行 `npm run format`;修改 Rust 后运行 `cargo fmt`。
生成的 `ui/css/tailwind.css` 不参与 Prettier 检查;通过 `npm run build:css` 更新,避免格式化与压缩构建反复改写同一文件。
### 项目结构 ### 项目结构
```text ```text
@@ -215,10 +219,10 @@ npm run build:css
npm run build npm run build
# 只生成安装包及 release 主程序,不执行 Portable 目录复制 # 只生成安装包及 release 主程序,不执行 Portable 目录复制
cargo tauri build cargo tauri build -- --locked
``` ```
`npm run build` 等价于 `cargo tauri build && npm run post-build`,不会自动编译 CSS;使用 `just build` 则会先构建 CSS,再调用 `npm run build`。 `npm run build` 等价于 `cargo tauri build -- --locked && npm run post-build`,不会自动编译 CSS;使用 `just build` 则会先构建 CSS,再调用 `npm run build`。便携版复制失败时会中止,不把复制错误当作成功。
### 本地编译产物 ### 本地编译产物
@@ -246,9 +250,17 @@ Release profile 使用 `strip`、`opt-level = "z"`、LTO、单个 codegen unit
### 版本与 GitHub Actions ### 版本与 GitHub Actions
发布前同步修改 **三个**版本字段:`package.json`、`src-tauri/Cargo.toml`、`src-tauri/tauri.conf.json`。更新检查的当前版本来自 Cargo 包版本。 发布前同步修改 **三个**版本字段:`package.json`、`src-tauri/Cargo.toml`、`src-tauri/tauri.conf.json`,并同步更新两个锁文件。更新检查的当前版本来自 Cargo 包版本。
推送 `v{version}` tag 后,`release.yml` 在 Windows 上构建,并发布: GitHub Actions 已统一到 `.github/workflows/ci.yml`:
- `main`/`master` 分支推送及面向这两个分支的 PR:检查并构建 Windows x64 包,不再依赖提交消息中的特殊关键字。
- `v*` tag:执行同样的检查和构建;tag 必须与应用版本精确一致,检查或构建失败时不会发布。
- 构建 job 使用 Node.js 22、Rust stable 和固定版本的 Tauri CLI 2.12.1;缓存 npm、Rust 和 CLI。
- 顺序为版本校验、前端 lint/格式检查、Rust 格式/严格 clippy/测试、CSS 构建、安装包和便携版构建。
- 三种产物必须存在且非空,否则失败;成功后统一上传 `UPX-Tools-Windows-x64` artifact。tag 的发布 job 下载该 artifact,不重新构建。
tag 发布以下文件;版本含 `-` 的预发布版本标记为 prerelease:
| 文件 | 类型 | | 文件 | 类型 |
| --- | --- | | --- | --- |
@@ -256,11 +268,7 @@ Release profile 使用 `strip`、`opt-level = "z"`、LTO、单个 codegen unit
| `UPX-Tools-{version}-x64.msi` | MSI 安装包 | | `UPX-Tools-{version}-x64.msi` | MSI 安装包 |
| `UPX-Tools-{version}-x64-setup.exe` | NSIS 安装包(当前用户安装) | | `UPX-Tools-{version}-x64-setup.exe` | NSIS 安装包(当前用户安装) |
其他工作流: 普通分支/PR 的过时运行会自动取消,tag 运行不会被新运行主动取消。默认权限为 `contents: read`,仅 tag 发布 job 获取 `contents: write`。
- `ci.yml`:面向 `main`/`master` 的 PR、`v*` tag,以及提交消息包含 `build:` 或 `tag` 的分支推送,运行 Rust 格式检查、严格 clippy 和测试。
- `build.yml`:面向 `main`/`master` 的 PR 或提交消息包含 `build:` 的分支推送,构建并上传 MSI/NSIS artifact,不复制便携版。
- 当前工作流不安装 Node.js,也不运行前端检查或 Tailwind 构建;发布前需在本地检查前端并更新 `ui/css/tailwind.css`。
## 相关链接 ## 相关链接
+2696
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -11,8 +11,8 @@
"check": "npm run lint && npm run format:check", "check": "npm run lint && npm run format:check",
"build:css": "npx tailwindcss -i ./ui/css/main.css -o ./ui/css/tailwind.css --minify", "build:css": "npx tailwindcss -i ./ui/css/main.css -o ./ui/css/tailwind.css --minify",
"watch:css": "npx tailwindcss -i ./ui/css/main.css -o ./ui/css/tailwind.css --watch", "watch:css": "npx tailwindcss -i ./ui/css/main.css -o ./ui/css/tailwind.css --watch",
"build": "cargo tauri build && npm run post-build", "build": "cargo tauri build -- --locked && npm run post-build",
"post-build": "powershell -Command \"New-Item -Path 'src-tauri/target/release/bundle/Portable' -ItemType Directory -Force | Out-Null; Copy-Item 'src-tauri/target/release/UPX-Tools.exe' 'src-tauri/target/release/bundle/Portable/'\"" "post-build": "powershell -NoProfile -NonInteractive -Command \"$ErrorActionPreference = 'Stop'; New-Item -Path 'src-tauri/target/release/bundle/Portable' -ItemType Directory -Force | Out-Null; Copy-Item 'src-tauri/target/release/UPX-Tools.exe' 'src-tauri/target/release/bundle/Portable/'\""
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.39.2", "@eslint/js": "^9.39.2",