多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

BrewUI:macOS上Homebrew的图形化管家,用SwiftUI重构包管理体验

BrewUI:macOS上Homebrew的图形化管家,用SwiftUI重构包管理体验 1. 项目起源命令行世界里的一块图形化拼图老实说Homebrew 几乎是我在 macOS 上装软件的第一选择没有之一。从开发工具到日常应用一条brew install能搞定大部分需求。但问题在于不是每个人都愿意打开终端也不是每个人都熟悉brew list、brew outdated、brew cleanup这一堆命令的用法。我刚接触 macOS 那会儿光是理解“什么是依赖”“为什么卸载软件还要看依赖关系”就花了不少时间。BrewUI 这个项目最初就是冲着这个痛点去的。它做的事情很简单把 Homebrew 的核心能力用图形界面的方式呈现出来。你不用再背命令不用再盯着终端里飞速滚动的日志发愁鼠标点几下就能完成软件的搜索、安装、升级、卸载和清理。它适合几类人刚转 macOS 的新手、平时主要用图形界面办公但偶尔需要装软件的用户以及那些管理着几十上百个包、希望快速看清全貌的开发者。当然我这里说的不是做一个“命令行模拟器”而是真正站在用户操作习惯的角度重新设计交互。Homebrew 本身足够强大缺的不是功能而是一层让人更容易理解、更容易上手的“外壳”。BrewUI 就是这层外壳。1.1 Homebrew 很好用但终端确实有门槛Homebrew 的底层逻辑其实非常清晰一个用 Ruby 写的包管理器通过 Git 拉取软件仓库然后用预编译的二进制包或本地源码编译的方式安装软件。它内部维护了一套完整的依赖关系图这也是为什么你安装某款软件时它会自动帮你装好几十个依赖库。但问题在于这些信息在终端里呈现给用户时门槛并不低。brew list只能看到一个扁平列表brew deps --tree虽然能画出依赖树但输出一大片字符普通人很难快速读懂。更别提还有brew doctor那一大堆令人头大的警告和提示新手看到之后经常不知道该不该管、怎么管。另外Homebrew 的交互反馈也比较“程序员化”。安装一个大型软件时终端里密密麻麻的日志大部分人是直接跳过的——但万一中间出了问题那一屏的报错很容易让人不知所措。图形界面的价值就在这里可以用颜色、图表、进度条和状态标签把原本需要阅读和分析的信息变成一眼就能看懂的视觉元素。1.2 BrewUI 的定位不是替代 brew而是降低操作门槛我在设计 BrewUI 时脑子里一直有一个原则绝不试图“包办”所有 Homebrew 功能。Homebrew 有很多高阶玩法比如创建自己的 Formula、批量操作、环境变量管理、CI 集成等这些在命令行里效率极高强行 GUI 化反而是一种倒退。所以 BrewUI 的定位非常明确——它只覆盖日常高频操作并且把低频但重要的“体检”功能做到可视化。具体来说核心场景就四类浏览和管理当前已安装的软件包包括版本信息、依赖关系、安装路径等搜索软件仓库里的可用软件一键安装或卸载查看软件更新情况支持逐项升级和全部升级清理缓存、卸载孤儿依赖、运行环境体检。这样做的直接好处是用户不需要理解 Homebrew 的完整概念体系只需要知道“我想装个软件”“我想把旧软件升级到最新版”“我想清理一下磁盘空间”就能在 BrewUI 里轻松完成。1.3 同类工具现状为什么还要自己做在动手之前我其实也研究过市面上已有的同类工具。坦率说它们解决了部分问题但也都有我不能接受的地方。有的工具停留在菜单栏弹窗模式功能太少连依赖分析和日志查看都做不到有的用 WebView 套壳界面响应慢内存占用夸张启动一次要等好几秒还有的开源了但维护基本停滞Homebrew 的 JSON API 早就变了它还在用旧的解析逻辑动不动就崩溃。我自己评价一个 GUI 工具是否合格标准其实很朴素安装包小、启动快、常驻内存低、交互符合 macOS 用户习惯。Electron 那种动辄上百 MB 的方案我直接否掉。既然处理的是 Homebrew 这种原生命令行工具用原生技术栈来写才是正路这也是最终选择 Swift SwiftUI 的核心原因。后面我会专门说技术架构上的考量。2. 技术选型与架构设计为什么是 Swift SwiftUIBrewUI 的客户端我最终选了 Swift SwiftUI 这套组合。这个选择不是拍脑袋定的而是结合了性能、开发效率、系统集成度和长期维护成本之后的结果。2.1 技术栈选择原生优先交互体验才有下限保证先说说为什么不是 Electron、Tauri 或者其他跨平台框架。Electron 的优势是 Web 技术栈、开发快但代价是包体积几十 MB 起步、内存经常吃掉几百 MB。Tauri 比 Electron 轻量不少但它本质上是“系统 WebView Rust 后端”对于这种需要频繁调用外部进程、读取系统状态的工具来说中间隔了一层桥接调试起来心智负担很重。SwiftUI 从 macOS 11 开始逐步成熟到现在的版本在窗口管理、列表渲染、图表绘制、菜单栏应用等场景下表现都相当能打。最重要的是SwiftUI 是苹果亲儿子系统更新之后它能第一时间兼容不会有新技术不兼容的问题。配合 Swift 的Process类直接调用外部命令整个链路非常顺滑逻辑层用 Swift 管进程、解析输出UI 层用 SwiftUI 绑定状态、订阅事件全程不跨语言开发效率并不低。内存占用方面实测 BrewUI 完整窗口打开、数据列表全部加载的情况下内存稳定在 80 MB 左右菜单栏驻留模式更低。这个数字在 Electron 时代是想都不敢想的。2.2 整体架构UI、服务、数据三层分离BrewUI 的内部结构我分成了三层各司其职UI 层SwiftUI 的 View ViewModel负责界面渲染和用户交互Service 层BrewService负责执行 Homebrew 命令BrewParser负责解析命令输出把文本转成结构化的模型Data 层负责本地持久化包括用户偏好、软件包历史记录、缓存数据等。UI 和 Service 之间用 Combine 的ObservableObject做桥接。用户界面上点一个“升级全部”按钮ViewModel 会创建一个升级任务交给BrewServiceService 在后台队列执行命令每个阶段等待、执行中、成功、失败都通过Published状态同步回 UI。这样用户随时能看到当前进度而不是傻等一个回执。数据层的持久化我用的是UserDefaults 本地 JSON 文件。像“用户上次更新时间”“已忽略更新提醒的软件列表”这类轻量数据UserDefaults 足够软件包历史状态记录会稍微多一点就用 JSON 文件保存到 Application Support 目录下。为什么不上 Core Data 或 SQLite因为 BrewUI 的数据量级确实不大全量索引几千个软件包的信息一个 JSON 文件也就几百 KB用 SQLite 反而增加复杂度。2.3 与 Homebrew 通信的核心Process 管道 JSON 解析整个项目最核心的技术细节其实是“如何跟 Homebrew 安全可靠地通信”。Homebrew 本身是一个命令行程序要和它交互最朴素的方式就是用Process直接执行brew命令。但问题在于brew命令的默认输出是给人看的美化文本有颜色、有表格、有不同类型的提示语直接解析这些文本很容易被各种异常格式干扰。因此在设计上所有需要解析的输出我都要求 Homebrew 输出 JSON 格式。比如struct BrewCommandRunner { let brewPath: String func run(_ arguments: [String]) throws - Data { let process Process() let pipe Pipe() process.executableURL URL(fileURLWithPath: brewPath) process.arguments arguments process.standardOutput pipe process.standardError pipe try process.run() process.waitUntilExit() return pipe.fileHandleForReading.readDataToEndOfFile() } }实际调用的命令会带上 JSON 参数比如brew list --formula --jsonv2列出所有已安装的 formula 及版本信息brew info --jsonv2 formula获取单个软件包的完整信息brew search keyword --formula --jsonv2在仓库中搜索软件包brew outdated --jsonv2获取所有可升级的软件包及当前版本、目标版本brew update --preinstall更新仓库数据。之所以坚持用 JSON 输出而不直接解析文本是因为 JSON 有完整的类型结构版本号、依赖列表、更新时间等字段都清晰可查。这样做解析代码不用对付各种边缘情况稳定性高很多。唯一要注意的是老的 Homebrew 版本对 JSON 参数支持并不好所以后续我在启动时增加了自动检测 Homebrew 版本并进行提示逻辑——如果版本太低就直接引导用户升级 Homebrew 到最新版。3. 核心功能拆解与实现细节每个按钮背后都有讲究功能设计上我花了最多心思的不是“命令调用”而是“信息呈现方式”。Homebrew 能提供的信息就那么多怎么让用户不混乱、不害怕、愿意用才是一场真正的较量。3.1 仪表盘打开应用马上知道自己的系统处于什么状态BrewUI 的主界面第一屏是仪表盘。它承担的任务只有一个让用户在 3 秒内判断出“我的开发环境健不健康”。仪表盘分了几个模块系统概览当前 Homebrew 版本、前缀路径、运行平台、Git 仓库状态统计卡片已安装软件包数量、可升级数量、待清理缓存大小、孤儿依赖数量快速操作区一键更新仓库、一键升级全部、一键清理最近动态最近一次安装/升级/卸载操作的时间、内容、结果。统计卡片有一个细节可升级数量那个卡片不仅展示数字还会列出其中最旧的三个软件包并标出其“过时天数”。这个数据来自 Homebrew 提供的安装时间戳能帮用户判断哪些软件一直没管过面对几十个待升级包时就有了轻重缓急。仪表盘的刷新策略也很重要。如果每次打开窗口都重新执行一系列brew命令启动速度会慢得让人绝望。所以我把指标分成了两类一类是经常变化的比如可升级数量、更新状态会在窗口启动后异步刷新另一类相对稳定的比如 Homebrew 安装路径、版本、平台信息则直接读取本地缓存秒开。3.2 软件包管理搜索、安装、升级、卸载的操作闭环软件包列表是另一个核心界面。顶部有搜索框支持模糊搜索、按 Formula 类型筛选、只看已安装、只看可升级。搜索功能的实现用的是brew search的 JSON 输出拿到结果后在本地做关键词匹配排序。排序规则我调过几轮关键词出现在名字开头的最靠前包含关键词的靠中间描述信息里命中的排在最后。这样符合直觉。安装操作我做了“安装前确认”逻辑。点击安装按钮后会先弹出确认框里面不仅显示要装的软件包名称还会列出其依赖树。这样用户就知道“装这个软件顺带会装哪些依赖”避免装完之后发现系统里多了一堆不认识的东西而心慌。升级功能同样做了依赖影响分析。点击升级后会先展示一个反向依赖列表。比如你准备升级 OpenSSL 1.1 到 3.x界面会提示“以下 12 个已安装软件依赖此包可能同步受影响”。有些用户并不需要这些信息但一旦出现过一次“升级某个库导致其他工具崩了”的事故你就会明白这种提示值多少钱。卸载流程我有意做得比安装更谨慎。因为 Homebrew 卸载软件包时默认不检查它是否被其他软件依赖直接卸载可能导致依赖链断裂。BrewUI 在点击卸载后会先查询反向依赖。如果确认没有其他软件依赖它才允许直接卸载如果有依赖界面会明确列出依赖者列表提示用户后果并且默认不推荐卸载。针对有的用户确实想“彻底清干净”的需求我还提供了一键卸载并清理孤儿依赖的选项。3.3 依赖关系可视化把复杂结构变成能看懂的图依赖关系是 Homebrew 里最核心、也最难理解的概念。我一直认为GUI 工具最有价值的地方就是把这种复杂但重要的结构可视化。BrewUI 的软件包详情页有一个“依赖分析”区域用两种方式展示依赖信息正向依赖这个软件包依赖哪些库反向依赖哪些已安装的软件包依赖它。界面用的是圈层图中心节点是当前软件包外圈是直接依赖/依赖它的软件包再外圈是二级依赖。颜色用于区分状态正常是蓝色有更新可用是橙色缺失或异常是红色。隐含循环依赖的情况我也遇到过比如两个软件包互相依赖对方。这种情况在二叉树视图里会崩但在圈层图里只要加一个最大深度限制超出深度就不展开就能避免死循环。最终我实现时设定最多展示两层再多提示“更多层级请到终端查看”这也符合我“不包办一切”的定位。3.4 菜单栏驻留、日志系统和错误可读化菜单栏驻留功能是很多用户的高频入口。开启后菜单栏会出现一个图标点开就能看到简化的状态面板当前可升级数量、最近一次更新结果、快速升级按钮。这一模式对后台开发很友好不需要随时开着一个大窗口但又不会错过重要的版本更新。日志系统是一个容易被忽略、但我坚持要做的功能。每次执行命令BrewUI 都会把完整输出存到~/Library/Logs/BrewUI/下按日期命名文件。为什么要这么做因为 GUI 工具最容易出现的问题就是“执行失败但用户不知道为什么失败”。有了日志系统遇到问题时可以导出日志、或者直接打开日志目录给到排查者省去了很多沟通成本。错误可读化是我花了不少功夫的地方。Homebrew 的命令行报错非常“程序猿”比如Error: The following directories are not writable by your user: /usr/local/share新手看到这种报错大概率是懵的。BrewUI 的提示器会识别这些常见场景转换成人类语言部分目录权限异常。你可能需要用sudo chown -R $(whoami) /usr/local/share修复权限或者检查是否使用了错误的前缀路径。同时还附上“拷贝修复命令”按钮用户一键就能复制。不是说好不教用户用终端吗实际上不矛盾因为有些问题确实需要终端才能解决我能做的是让这个切换过程尽可能顺畅自然。4. 实操过程从安装配置到完成第一个包管理操作说了一堆设计理念下面进入实操环节。我会完整走一遍从零开始用 BrewUI 完成环境检查和包管理的全过程。如果你也想自己搭一个类似的项目这一节可以直接作为功能蓝图来抄作业。4.1 安装与环境自检启动后的第一道关卡BrewUI 首次启动时会执行一个“环境自检”流程逐个检查后续操作需要的基础条件。自检项包括检查项判断标准不通过时提示Homebrew 是否已安装可执行brew --version引导用户到终端安装 Homebrew并等待确认Homebrew 版本是否过新版本号是否低于 4.0提示更新 Homebrew避免 JSON 参数兼容问题Git 是否可访问git --version提示安装 Command Line Tools当前用户对前缀目录是否可写brew config返回值提示用sudo chown修复权限仓库索引是否存在执行一次轻量brew list是否成功提示先运行brew update自检过程是异步的每完成一项就在界面上打一个绿勾或红叉用户能直观看到环境卡在哪。我记得第一次启动时自检耗时大概 2 秒大部分时间花在brew --version的文件 IO 上体验可以接受。4.2 初次扫描建立本地数据索引通过自检后应用会进行一次全量数据扫描目的是把本地已安装的软件包、仓库里可用的软件包、依赖关系等数据建立成本地索引。扫描命令就是前面提到的brew list --formula --jsonv2和brew search。扫描过程我做了三步获取已安装的 formula 和 cask 列表解析为结构化模型获取仓库中全部可用 formula 的元信息名称、简介、版本、依赖做本地模糊搜索索引获取 Homebrew 配置信息和本地仓库路径建立全局配置状态。全量仓库元信息首次拉取会比较耗时视仓库大小在 10 到 30 秒之间。我做了一个进度条和实时日志窗口避免用户以为是卡死了。有一个优化点值得说一下首次索引建立之后后续启动时我会把上次的扫描结果作为“快速启动数据”让界面秒开后台再异步刷新。这样既保证了首屏响应速度又保证了数据不是过时的。4.3 实操用 BrewUI 完整走一遍“搜索-安装-使用-升级-卸载”下面用实际案例演示一次完整操作。假设我需要一个新的命令行工具jq。搜索打开软件包列表输入jq结果里第一个就是 Formula 类型描述是 “A lightweight and flexible command-line JSON processor”。点击进入详情页能看到当前仓库版本号和简介。安装点击“安装”确认框弹出显示依赖树。jq没有额外依赖确认后立即执行。底部状态栏出现进度条顶部显示当前执行的brew install jq命令。整个过程大约 5 秒比在终端里还能多看一屏进度信息。验证安装完成后详情页刷新软件包状态从“未安装”变为“已安装”并显示安装路径/usr/local/Cellar/jq/1.7.1。这个版本号和数据在详细信息面板里都清晰可见。升级过几天仓库里出了 1.7.2 版本仪表盘的可升级数量卡片会变成 1软件包列表的“可升级”筛选中也能看到jq以橙色标签标出。点升级确认框里这次多了一项反向依赖列表。因为我的系统上没有其他已安装软件依赖jq所以可以直接升。卸载想卸掉它时系统会先检查反向依赖显示“无已安装软件依赖此包”确认卸载。如果想清理它下载过的缓存文件勾选“同时清理缓存和孤儿依赖”完成。4.4 清理缓存与生成系统体检报告brew cleanup是很多人很少执行、但磁盘富余度很低时必须掌握的操作。BrewUI 在仪表盘放了一个“清理”按钮点击后会先显示“可清理大小”再让用户确认。清理逻辑我做了两级一级是 “基础清理”执行brew cleanup --pruneall清掉所有旧版本和缓存压缩包另一级是 “深度清理”额外执行brew autoremove移除所有孤立依赖。体检报告本质上是对brew doctor输出的结构化整理。Homebrew 的 doctor 输出很杂乱我按类型做了分类问题类型严重级别示例路径配置异常高duplicate 或者非标准前缀目录环境变量问题中未设置JAVA_HOME等未提交的仓库变更低Homebrew 源码目录有本地修改软链接冲突高多个软件包提供同名二进制分类之后用户看到的不再是一堆“WARNING”而是“你有 2 个高优先级问题需要处理、1 个建议优化项”。点开每个问题都有相应的修复建议按钮一键复制命令到剪贴板交给终端执行。这样既保持了 GUI 的友好又不真正脱离终端的生态。5. 常见问题与排查技巧实录开发和使用过程中我踩过不少坑。下面这些是在真实使用中大概率会遇到的典型问题整理成一个速查表遇到时可以直接查阅。现象根本原因解决办法“brew command not found”PATH 环境变量异常GUI 应用通常不会加载 shell 配置文件在 BrewUI 设置中手动配置 brew 路径通常是/opt/homebrew/bin/brewApple Silicon或/usr/local/bin/brewIntel权限不足无法写入前缀目录Homebrew 前缀目录权限不是当前用户用sudo chown -R $(whoami) /usr/local重置归属或者在设置中切换为当前用户可写的前缀安装软件卡在 “Downloading” 状态网络环境不稳定或仓库源延迟高等待超时后重试或先手动运行一次brew update保证仓库索引正常更新时报 “Another active Homebrew update process is in progress”上一个brew update进程没有正常退出锁文件残留等待几秒后重试若持续存在运行brew update --force清理锁缓存卸载后提示 “orphaned dependencies”Homebrew 不会自动移除依赖库使用深度清理功能执行brew autoremove软件包列表和终端打开的不一致GUI 缓存数据未及时刷新手动触发一次全量扫描或重启 BrewUI下面挑几个重大问题的排查思路展开说。5.1 环境变量问题GUI 应用最容易踩的坑这个问题的根源在于从命令行终端启动的brew会继承用户在.zshrc里设置的 PATH而 macOS 的 GUI 应用默认只继承系统级 PATH不加载 shell 配置文件。所以很多用户在终端里brew --version能跑但在 GUI 工具里调用brew时直接报 “command not found”。排查时必须先确认 brew 的实际路径。Apple Silicon 机型上Homebrew 默认安装到/opt/homebrew/bin/brewIntel 机型上则是/usr/local/bin/brew如果是自定义位置就用which brew在终端里查一下然后把完整路径填到 BrewUI 的设置里这个问题就解决了。这也是我在代码里不依赖 PATH 查找、而是直接记录 brew 完整路径的原因。5.2 网络原因导致的更新失败重试策略和日志分析更新仓库时最常见的失败原因是网络问题。brew update本质上是一个 Git pull 操作如果仓库源太远或者中间链路不稳定很容易超时。遇到这类问题我的处理建议是先不要盲目反复重试。可以在终端里手动执行一次brew update --verbose看看输出停在哪一步。如果停在 “Updating Homebrew...” 后长时间没反应说明仓库源确实连不通可以等一段时间再试或者检查网络环境。BrewUI 的日志系统在这里能帮上大忙。每次失败会把完整输出存到指定日志目录打开日志文件能清楚看到 Git 输出的具体报错信息。定位到具体报错原因后再决定是调整网络、还是换个时段重试效率就高得多。5.3 锁文件的坑别在报错后直接杀掉进程Homebrew 的更新操作有锁机制。如果上次brew update没有正常结束比如终端被强制关闭、进程被 kill锁文件就会残留。再次执行更新时会一直提示 “Another active Homebrew update process is in progress”。这个问题的处理并不复杂关键是不要直接去kill -9那些可疑进程那样可能会损坏仓库的 Git 状态。正确姿势是先确认确实没有 brew 进程在运行用ps aux | grep brew查看确认没有之后再执行brew update --force清理锁文件、重新走一遍更新逻辑。我把这个流程做成了 GUI 提示——检测到锁文件时界面会提示“检测到未完结的更新进程”然后给出两个按钮一个是“检查进程状态”一个是“强制清理并在安全后重试”。减少用户面对终端时的恐惧感。5.4 卸载残留依赖图和孤儿依赖Homebrew 卸载软件包时不会自动处理该软件引入的依赖库。比如你装了 AA 带了 B、C、D 三个依赖卸载 A 之后B、C、D 还留在系统里。如果之后没有其他软件用到它们就成了“孤儿依赖”。BrewUI 的深度清理按钮专门用来处理这个问题。执行brew autoremove后Homebrew 会自己计算所有已卸包的反向依赖把无人使用的依赖库找出来并卸载。这个功能尤其适合经常试用各种工具、又比较在意磁盘空间的用户。6. 项目现阶段状态与核心经验复盘BrewUI 目前已经具备了我在前面描述的全部功能仪表盘、软件包管理、依赖分析与可视化、菜单栏驻留、日志系统、深度清理、环境体检。当前版本的体验重点放在稳定性和容错性上。Homebrew 是一个活的外部系统它的命令行为、输出格式、JSON 字段都可能随着版本发生变化所以我专门写了一个“兼容性测试”模块每次 Homebrew 发布新版本后可以自动跑一遍全部的命令调用输出是否有字段变更、异常报错然后根据结果决定是否调整解析层代码。6.1 规划中的功能下一阶段我计划做几件更有意思的事情公式编辑向导允许用户在图形界面里创建自定义 Formula 文件通过表单填模板生成后保存到本地仓库进一步细化升级影响分析结合反向依赖列表在升级前自动生成一份“升级可能影响清单”并一键回滚到上一版本对应brew upgrade formula前置检查多仓库支持允许管理和切换不同的 Homebrew 仓库源针对国内网络环境做同步配置云同步配置将 BrewUI 的偏好设置、忽略列表、自定义软件分组通过 iCloud 在多台设备间同步。其中云同步这个点子我还在犹豫是否值得做。毕竟 BrewUI 的核心价值在本地管理和可视化云同步带来的复杂度不小而且对用户的实际收益可能有限。我会观察一下社区反馈再决定优先级。6.2 开发中我学到最深的几件事复盘整个项目开发过程有几件事我认为对以后做同类工具的人会有价值。第一GUI 工具的容错设计应该比命令行工具更严格。用户在终端里看到报错会自己去查但在 GUI 里任何一行不友好的报错都可能让用户流失。所以错误信息一定要分级、分类、可操作不要把一个裸的异常堆栈直接扔在界面上。第二不要试图在 UI 线程里执行耗时操作。这是我早期犯过的错误。最开始我直接在 SwiftUI 的按钮 Action 里同步执行Process.run()结果安装一个大型软件时整个 App 直接无响应界面卡得像个假死。后来改成后台队列 状态回调才彻底解决。第三日志是最容易被忽视、也是最有价值的功能。你可能觉得日志没什么好做的但只有当你收到用户反馈“这个东西又崩了”却找不到任何线索时才会明白日志系统有多重要。BrewUI 的日志不仅记录命令输出还会附带执行时间、执行参数、结果码相当于每一步操作都有据可查。还有一个小技巧想分享每次处理 Homebrew 的性能敏感操作时一定要先设定超时机制。否则遇到一个网络状况差的场景进程会一直在后台挂起既不返回结果也不提示进展用户的第一反应就是“App 崩溃了”。我的做法是给所有命令设置默认 60 秒超时超过之后主动终止进程并提示“操作超时请检查网络或手动在终端执行”这样至少用户知道发生了什么而不是对着卡死的界面干着急。做 BrewUI 这个项目我最深的体会是一个工具如果不能帮用户省心反而制造新的认知负担那它就没有存在的价值。命令行本身没有错它的高效是任何界面都无法替代的但在从终端向普通用户过渡的过程中一个细致、克制、把复杂度吸收在背后的图形层确确实实地填补了一个空白。后面我会继续打磨它让它越来越贴近“装了不后悔”的标准。
返回列表