Skip to content

Repository files navigation

Effective Tool

一个用 Rust 编写的开发效率工具 CLI。

当前版本:0.2.0。完整版本记录请参阅 CHANGELOG.md

v0.2.0 新功能

  • 递归扫描并清理指定目录下的 Flutter 项目,实时反馈清理进度和释放空间。
  • 内置 et update 安全升级,并在每天第一次交互使用时检查新版本。
  • 文件大小自动选择 BkBMBGB,显示更直观。

在真实交互终端中,主菜单、子菜单以及 y/n 确认均为单键选择,按下对应数字或 字母后立即响应,不需要回车;直接按回车仍可选择默认项。路径、数字参数和密码等 完整内容输入仍需回车。管道、CI 和重定向输入会自动保留按行读取模式。

安装为全局 et

macOS 可以直接下载同时支持 Apple Silicon 与 Intel 的 Universal Binary:

curl -LO https://github.com/drainlin/EffectiveTool/releases/latest/download/EffectiveTool-macos-universal.tar.gz
tar -xzf EffectiveTool-macos-universal.tar.gz
sudo install -m 755 EffectiveTool-macos-universal/et /usr/local/bin/et
et --version

普通用户升级

et 每个自然日第一次在交互终端中运行时会自动检查一次最新正式版。检查不会发生在 管道或 CI 中,网络失败也不会影响当前功能;发现新版本时只显示提示,不会自动安装。 用户可以运行下面的命令完成升级:

et update

升级程序会自动下载 macOS Universal Binary、校验 SHA-256,并替换当前使用的 et。 如果安装位置是 /usr/local/bin/et,安装阶段会请求一次系统管理员密码。也可以只检查 而不安装:

et update --check

交互菜单中的 7. 检查并更新 Effective Tool 提供相同功能。如果需要禁用每日自动 检查,可以设置环境变量 ET_NO_UPDATE_CHECK=1

v0.1.0 升级到首个支持内置更新的 v0.2.0 时,需要按下面的备用方式手动覆盖 一次。完成这次升级后,后续版本都可以直接使用 et update

如果内置更新不可用,可以重新下载最新版并手动覆盖原来的 et,不需要安装 Rust, 也不需要先卸载旧版本:

et --version

et_update_dir="$(mktemp -d)"
curl -fL \
  https://github.com/drainlin/EffectiveTool/releases/latest/download/EffectiveTool-macos-universal.tar.gz \
  -o "$et_update_dir/EffectiveTool-macos-universal.tar.gz"
tar -xzf "$et_update_dir/EffectiveTool-macos-universal.tar.gz" \
  -C "$et_update_dir"
sudo install -m 755 \
  "$et_update_dir/EffectiveTool-macos-universal/et" \
  /usr/local/bin/et
rm -R "$et_update_dir"

et --version

最后一次 et --version 应显示新版本号。升级只会替换 /usr/local/bin/et 可执行文件, 不会清理或修改用户的项目文件。如果 command -v et 显示的不是 /usr/local/bin/et,说明当前使用的是其他位置安装的版本,应升级该路径对应的安装。

也可以使用 Rust 工具链直接从 GitHub 安装:

cargo install --git https://github.com/drainlin/EffectiveTool.git --locked --force

也可以克隆仓库后在项目根目录安装:

cargo install --path . --locked --force

Cargo 会把可执行文件安装到 ${CARGO_HOME:-$HOME/.cargo}/bin/et。确认该目录在 PATH 中后,可以从任意目录直接运行:

et --version
et --help
et

如果终端找不到 et,macOS/Linux 可把下面一行加入 shell 配置并重新打开终端:

export PATH="$HOME/.cargo/bin:$PATH"

使用 Rust 工具链安装的用户,更新时再次执行对应的 cargo install 命令并保留 --force 即可覆盖旧版本。卸载:

cargo uninstall effective-tool

首次从源码构建需要网络,以下载并校验需要嵌入的 Firebase uploader 和对应架构的 FFmpeg;安装完成后的 et 是自包含产物,日常使用不再下载这些组件。

CLI 总览

不带子命令运行 et 会进入面向用户的交互菜单。脚本、CI 和 AI Agent 应直接调用 非交互子命令:

功能 命令
上传 Firebase dSYM et upload-dsyms
JPG / PNG / WebP 转换 et convert-image
创建 Android JKS et create-jks
视频转 WebP 动图 et video-to-webp
生成 iOS / Android App 图标 et generate-app-icons
递归清理 Flutter 项目 et clean-flutter
检查并安装新版本 et update

查看任一命令的完整参数:

et <SUBCOMMAND> --help

自动化调用建议使用绝对路径;生成 JKS、视频或图标时加 --no-open;只有明确允许 替换现有文件时才传 --overwrite。Firebase 上传应先执行 --dry-run,确认输入 后再进行真实上传。

AI Agent Skill

仓库内提供 effective-tool Skill,包含全部 CLI 选择规则、安全约束和可直接复用的命令模板。Codex 可以从项目根目录安装为全局 Skill:

mkdir -p "${CODEX_HOME:-$HOME/.codex}/skills"
ln -s "$(pwd)/skills/effective-tool" \
  "${CODEX_HOME:-$HOME/.codex}/skills/effective-tool"

然后在 Agent 请求中显式使用:

使用 $effective-tool 把 ./video.mp4 转成 720px、15 FPS 的 WebP 动图。

其他支持 SKILL.md 的 Agent 也可以直接加载 skills/effective-tool/SKILL.md。Agent 应使用子命令而不是编号菜单,并根据命令 退出码判断成功或失败。

清理 Flutter 项目

指定一个目录后,et 会递归检查该目录及所有子目录,识别 pubspec.yaml 中声明了 Flutter SDK 的项目,并依次在每个项目中执行 flutter clean

et clean-flutter ~/Projects
et clean-flutter ~/Projects --jobs 8
et clean-flutter /path/to/projects --flutter /path/to/flutter/bin/flutter

默认并发任务数为 CPU 逻辑核心数Flutter 项目数 中的较小值;可以使用 -j, --jobs COUNT 手动限制并发数。清理过程中会显示正在启动的项目、已完成数量和 完成百分比;交互终端使用单行动态进度条原地刷新,不会为每个项目持续刷屏。清理时 不输出单个项目的空间统计。所有项目处理完成后,会汇总成功和失败数量, 并显示本次批量清理实际释放的总空间。单个项目失败不会阻止 后续项目继续清理;只要存在失败项目,命令最终会返回非零退出码。扫描不会跟随目录 软链接,因此不会越出用户指定的目录树。

不带子命令运行 et,选择 6. 清理 Flutter 项目 后输入目录。交互模式会先列出 发现的所有 Flutter 项目,用户确认后才开始清理。flutter 默认从 PATH 查找; 如需使用指定版本,可在命令模式传入 --flutter PATH

生成 iOS / Android App 图标

输入一张正方形 JPG、PNG 或 WebP,et 可以一次生成完整的 iOS 和 Android App 图标目录。默认同时生成两个平台,也可以只生成其中一个:

et generate-app-icons ./app-icon.png
et generate-app-icons ./app-icon.png --platform ios
et generate-app-icons ./app-icon.png --platform android --output ./icons

默认输出到输入图片旁的 icons/,目录结构兼容常见的 iOS 与 Android 工程:

icons/
├── ios/
│   └── AppIcon.appiconset/
│       ├── Contents.json
│       └── icon-*.png
└── android/
    ├── mipmap-ldpi/ ... mipmap-xxxhdpi/
    ├── mipmap-anydpi-v26/
    ├── values/
    └── playstore-icon.png

iOS 会生成参考目录中的全部 16 个 PNG 尺寸及 Xcode Contents.json,并移除 Alpha 通道。Android 除参考目录已有的传统 Launcher Icon 和 512×512 Play Store Icon 外,还会生成:

  • ic_launcher_round.png 圆形图标。
  • API 26+ Adaptive Icon 的 108dp 前景层、背景色和 XML。
  • Android 13+ Themed Icon 使用的 Monochrome Layer。
  • mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi,以及兼容参考目录的 ldpi 资源。

Adaptive Icon 会自动读取图片边角颜色作为背景,移除相近的背景色,将识别出的 前景缩放到 66dp 安全区,并用前景 Alpha 生成单色层。单张扁平图片无法像设计源 文件一样完美拆层,因此复杂渐变背景建议生成后检查 ic_launcher_foreground.png。建议输入至少 1024×1024;较小的正方形图片也能 生成,但 iOS 1024 图标会被放大。

常用参数:

  • --platform all|ios|android:默认 all
  • -o, --output DIRECTORY:指定输出目录。
  • --overwrite:更新已有输出目录中的同名生成文件。
  • --no-open:完成后不在文件管理器中定位输出目录。

交互模式选择 5. 生成 iOS / Android App 图标,可在子菜单中选择两个平台、 仅 iOS 或仅 Android;任一步输入 0bback 可返回主菜单。

视频转 WebP 动图

et 可以把 MP4、MOV、MKV 等 FFmpeg 能识别的视频转换成 WebP 动图。macOS Release 已内置静态 FFmpeg,Apple Silicon 使用 FFmpeg 8.1,Intel 使用 FFmpeg 8.0;用户不需要安装 Homebrew、FFmpeg 或其他动态库。

交互模式在主菜单选择:

4. 视频转 WebP 动图

然后依次选择视频、输出位置、帧率、宽度、质量和循环次数。转换期间会显示完成 百分比、视频时间、已处理帧数、处理帧率、速度和耗时。转换完成后默认在文件管理器 中定位输出文件。

命令模式:

et video-to-webp ./clip.mp4
et video-to-webp ./clip.mov \
  --output ./clip.webp \
  --fps 15 \
  --width 720 \
  --quality 80 \
  --loop 0

默认输出为输入文件同目录、同名的 .webp,默认参数是 15 FPS、720px 宽、 质量 80、无限循环。高度会保持比例并自动调整。常用参数:

  • --fps 1-60:输出帧率;帧率越高,动画越流畅,文件也越大。
  • --width 16-7680:输出宽度;设置为 0 保持视频原始尺寸。
  • -q, --quality 1-100:有损 WebP 质量。
  • --loop 0-65535:循环次数;0 表示无限循环。
  • --overwrite:允许原子替换已有输出。
  • --no-open:完成后不打开输出文件位置。
  • --ffmpeg PATH:使用指定的 FFmpeg,方便开发和调试。
  • --refresh-ffmpeg:从 et 自身重新释放内置 FFmpeg。

内置 FFmpeg 会在构建时按目标架构下载并验证 SHA-256,再使用 Zstandard 压缩后 嵌入 et。第一次转换时流式解压到用户缓存,之后直接复用并在每次使用前校验 原始 FFmpeg 的 SHA-256;转换过程不需要再次下载。当前内置版本仅支持 macOS; 其他平台可以暂时通过 --ffmpeg PATH 使用自行安装的 FFmpeg。

创建 JKS 密钥库

et 可以直接创建 Android 签名使用的 Java KeyStore(JKS)。RSA 私钥、自签名 X.509 证书、私钥保护和 JKS 编码均由 Rust 完成,运行时不需要 Java、keytool 或 OpenSSL。

交互模式在主菜单选择:

3. 创建 JKS 密钥库

程序会依次询问输出路径、别名、证书名称、有效期、RSA 密钥位数和密码。密码使用 隐藏输入,不会回显到终端;密钥库密码直接回车时默认为 123456,密钥密码留空 时会使用密钥库密码。任一步输入 0bback 均可返回主菜单。

也可以直接使用命令:

et create-jks
et create-jks \
  --output ./android/app/upload-keystore.jks \
  --alias upload \
  --dname "CN=Upload Key, O=Example, C=CN" \
  --validity-days 10000 \
  --key-size 2048

在交互终端中,命令会隐藏询问密钥库密码,直接回车使用默认值 123456。没有 终端或环境变量时也使用该默认值;密钥密码默认与密钥库密码相同。正式发布建议 通过环境变量设置独立的强密码,避免密码出现在 shell 历史和进程列表:

export ET_JKS_STORE_PASSWORD='your-secret-password'
export ET_JKS_KEY_PASSWORD='your-optional-key-password'
et create-jks --output ./upload-keystore.jks

也可以用 --store-password-env NAME--key-password-env NAME 指定自定义环境 变量名。密码至少 6 个字符;为保持 Java JKS 对密码编码的兼容性,目前仅接受 ASCII 字符。默认输出 upload-keystore.jks,默认别名为 upload,证书有效期 为 10000 天,RSA 密钥为 2048 位。使用 --overwrite 才会替换已有文件。

生成后,交互终端默认会在系统文件管理器中定位 JKS:macOS 在 Finder 中选中文件, Windows 在资源管理器中选中文件,Linux 打开所在目录。脚本可以传入 --no-open 禁用;CI 和重定向输出等非交互环境会自动跳过。

请安全备份 JKS 和密码。Android 应用发布密钥一旦丢失,通常无法再用同一密钥 签署后续更新。

图片格式转换

支持 JPG、PNG 和 WebP 之间的六种互转方向。命令模式:

et convert-image ./photo.png --to webp
et convert-image ./photo.webp --to jpg --quality 90
et convert-image ./photo.jpg --to png --output ./exports/photo.png

文件夹批量转换:

et convert-image ./images --to webp
et convert-image ./images --to jpg --quality 90 --output ./converted-images

批量模式只扫描文件夹第一层,不递归子目录。默认输出到输入文件夹下的 converted/,忽略子文件夹和非 JPG/PNG/WebP 文件。单个文件失败不会中断其余 转换,结束时会输出成功、跳过、失败和忽略数量;存在失败时命令返回非零退出码。

常用参数:

  • -t, --to jpg|png|webp:目标格式,jpeg 也可作为 jpg 的别名。
  • -o, --output PATH:单文件模式为输出文件;批量模式为输出文件夹。 省略时,单文件替换扩展名,文件夹输出到其 converted/ 子目录。
  • -q, --quality 1-100:JPG 和 WebP 编码质量,默认 85
  • --overwrite:允许原子替换已存在的输出文件;默认拒绝覆盖。

程序按文件内容识别输入格式。PNG 或 WebP 的透明像素转为 JPG 时会铺白色背景。 转换会先写入同目录临时文件,编码成功后再移动到目标位置。

交互模式中在主菜单选择:

2. JPG / PNG / WebP 格式转换

然后依次输入图片或文件夹、目标格式、质量和输出位置。拖入文件夹会自动进入 非递归批量模式。任一步输入 0bback 均可返回主菜单。

Firebase Crashlytics dSYM 上传

此功能仅能在 macOS 上执行。它会验证 .xcarchiveGoogleService-Info.plist,然后把 archive 中的所有 dSYM 上传到 Firebase Crashlytics。

安装后直接运行 et 即可进入交互模式:

程序会在打开主菜单以及进入具体功能时自动清屏;管道和 CI 环境不会输出清屏控制字符。

$ et
et — 开发效率工具

请选择功能:
1. 上传 Firebase Crashlytics dSYM
2. JPG / PNG / WebP 格式转换
3. 创建 JKS 密钥库
4. 视频转 WebP 动图
5. 生成 iOS / Android App 图标
6. 清理 Flutter 项目
7. 检查并更新 Effective Tool
0. 退出

请输入序号 [1](无需回车): 1

上传 Xcode archive 中的 dSYM 到 Firebase Crashlytics
可以把文件或目录直接拖到终端窗口中。

.xcarchive 或 dSYMs 目录路径:
GoogleService-Info.plist 路径:

交互模式默认上传 iOS dSYM,并会在上传前要求确认。 在路径提示中输入 0bback 即可返回主菜单。

也可以使用完整参数,适合脚本和 CI:

et upload-dsyms \
  --archive ~/Library/Developer/Xcode/Archives/2026-07-31/MyApp.xcarchive \
  --google-service-info ./MyApp/GoogleService-Info.plist

也兼容 Firebase upload-symbols 常用的参数形式,直接传入 dSYMs 目录:

et upload-dsyms \
  -gsp ./ios/Runner/GoogleService-Info.plist \
  -p ios \
  ./build/ios/archive/Runner.xcarchive/dSYMs

如果希望使用项目 Pods 中的 uploader:

et upload-dsyms \
  --upload-symbols ./ios/Pods/FirebaseCrashlytics/upload-symbols \
  -gsp ./ios/Runner/GoogleService-Info.plist \
  -p ios \
  ./build/ios/archive/Runner.xcarchive/dSYMs

Firebase 官方 upload-symbols 12.14.0 通用二进制已经嵌入 et(支持 Apple Silicon 和 Intel Mac)。首次执行时只会从 et 自身释放到用户缓存并进行 SHA-256 校验,不会访问 GitHub,也不依赖 CocoaPods 或本机预装 Firebase。 实际上传 dSYM 到 Firebase 服务仍然需要网络。

上传期间,交互终端会显示活动状态和实时耗时:

⠹ 正在上传 Firebase dSYM · 已用时 00:18

Firebase 原始的成功、失败和重试日志会继续显示。--debug 模式下会关闭动画, 优先展示 Firebase 的详细日志;CI 和重定向输出中只输出普通状态文本。

上传前只进行校验并查看将要执行的命令:

et upload-dsyms \
  --archive /path/to/MyApp.xcarchive \
  --google-service-info /path/to/GoogleService-Info.plist \
  --dry-run

其他常用选项:

  • --platform ios|mac|tvos:目标平台,默认 ios;Catalyst 使用 mac
  • --debug:显示 Firebase uploader 的详细日志。
  • --refresh-uploader:从 et 自身重新释放内置 uploader。
  • --upload-symbols /path/to/upload-symbols:改用指定的 Firebase uploader。
  • --allow-bundle-id-mismatch:明确允许 archive 与 Firebase plist 的 bundle ID 不同。

查看完整帮助:

et upload-dsyms \
  --help

开源许可

Effective Tool 自有源代码采用 MIT License。构建过程下载并嵌入的 Firebase uploader 与 FFmpeg 等第三方组件继续适用各自的许可证;版本、来源及 许可信息请参阅 THIRD_PARTY_NOTICES.md

About

Rust 开发效率工具 CLI:Firebase dSYM、图片与视频转换、JKS 和 App 图标

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages