Claude Code 是我用过最强的编程 AI。但每天启动它 30 次,每次都要打开终端、cd 到项目目录、输入命令——这个流程让我抓狂。
我做了 GroAsk 来解决这个问题。按一下 ⌥Space,直接启动 Claude Code,带上你的 prompt,自动定位到正确的项目目录。不用 cd,不用记路径,不用碰终端。
这篇文章讲的是背后的技术实现:4 种终端的自动化方案、PATH 检测的陷阱、CLI 安装的依赖链处理,以及为什么这些看似简单的事情其实很难做对。
痛点:Claude Code 的启动成本
Claude Code 的交互模式决定了它的启动成本不低。
第一步,打开终端。第二步,cd ~/Projects/my-app——前提是你记得住路径。我电脑里有几十个项目,分布在不同目录层级。第三步,输入 claude。第四步,输入 prompt。
一次大概 15 秒。一天 30 次就是 7 分钟。7 分钟不算多,但重复的摩擦会消磨你的专注力。每次打断思路去做这些机械操作,重新进入状态又要花更多时间。
更别提还有其他 CLI AI——Gemini CLI、Codex、CodeBuddy、Kimi Code、Qwen Code。它们的启动流程一模一样:cd,输入命令,输入 prompt。
我想要的很简单:一个快捷键,一句话,直接开始工作。
方案:⌥Space 直达
GroAsk 的解法是把所有中间步骤压缩掉。
按下 ⌥Space,弹出一个输入框。选择 Claude Code,输入 prompt,回车。GroAsk 自动打开终端,cd 到正确的目录,执行 claude "your prompt"。
"正确的目录"怎么确定?三层策略:
- Prompt 里带路径前缀。你可以在设置里配置工作区别名——比如
groask映射到~/Documents/GitHub/gro/GroAsk。输入/groask 帮我修一下这个 bug时,GroAsk 自动解析出路径,把干净的 prompt 传给 Claude Code。支持子路径补全:/groask/app会定位到~/Documents/GitHub/gro/GroAsk/app。 - 默认工作区。设置一个常用项目路径,不带前缀时自动使用。
- Finder 当前目录。如果 Finder 有打开的窗口,自动读取它的路径。
三层兜底,覆盖了我日常 95% 的场景。
最难的部分:4 种终端,4 种实现
macOS 用户的终端选择是分裂的。Terminal.app、iTerm2、Ghostty、Warp——四个终端,没有统一的命令执行接口。这是 GroAsk 实现中最耗时的部分。
Terminal.app:AppleScript do script
最传统的方案。Terminal.app 有完整的 AppleScript 脚本字典,用 do script 可以直接在终端窗口执行命令:
tell application "Terminal"
activate
do script "cd ~/my-project && claude \"fix the bug\""
end tell
但有个细节:如果 Terminal 还没启动,do script 会在默认窗口执行;如果已经在运行,需要新开一个窗口。GroAsk 会检测 Terminal 的运行状态,等待窗口就绪后再执行,避免命令丢失。
NSAppleScript 有时会因为 TCC 权限问题失败,GroAsk 会自动降级到 osascript 子进程兜底。
iTerm2:AppleScript write text
iTerm2 也支持 AppleScript,但接口不同。它用 create window with default profile 建窗口,然后用 write text 输入命令:
tell application id "com.googlecode.iterm2"
activate
create window with default profile
tell current session of current window
write text "cd ~/my-project && claude \"fix the bug\""
end tell
end tell
用 bundle ID com.googlecode.iterm2 引用而不是应用名称,因为有些用户的 iTerm 可能叫 "iTerm" 也可能叫 "iTerm2"。
Ghostty:剪贴板粘贴
Ghostty 没有 AppleScript 脚本字典。最初我尝试了 -e 参数启动,需要用 bash -l -c 包裹才能加载 shell 配置,但实测不够可靠。
最终方案:通过 System Events 的剪贴板粘贴。把命令写入剪贴板,用 ⌘V 粘贴到终端,再按回车执行。
tell application "System Events"
tell (first process whose bundle identifier is "com.mitchellh.ghostty")
keystroke "n" using command down -- 新窗口
delay 0.5
keystroke "v" using command down -- 粘贴命令
delay 0.1
keystroke return -- 执行
end tell
end tell
为什么用剪贴板粘贴而不是 keystroke 模拟输入?因为 keystroke 会经过 macOS 输入法系统。如果用户的中文输入法处于激活状态,命令会变成乱码。⌘V 粘贴直接写入终端,不经过输入法。
粘贴完成后,GroAsk 会延迟 3 秒恢复剪贴板原始内容——确保终端已完成粘贴,同时不污染用户的剪贴板。
这个方案需要辅助功能权限(Accessibility),GroAsk 会在首次使用时弹窗引导用户授权。
Warp:同样是剪贴板粘贴
Warp 的情况和 Ghostty 类似——没有 AppleScript 字典。最初尝试了 YAML Launch Config + URI scheme,但最终也采用了剪贴板粘贴方案,和 Ghostty 共用同一套输入法绕过逻辑。
区别在于:Ghostty 用 ⌘N 新建窗口,Warp 用 ⌘T 新建标签页。
四种终端,两种完全不同的技术路线:AppleScript 原生控制(Terminal.app、iTerm2)和 System Events 剪贴板注入(Ghostty、Warp)。用户在设置里选一次终端,之后无感切换。
PATH 检测:比你想象的复杂
Claude Code 装好了,GroAsk 能找到它吗?
这个问题看起来简单——命令装在哪,PATH 里有就行。但在 macOS 上,PATH 是一团混乱。
不同的安装方式把工具放在不同的地方:
curl安装器(Claude Code、CodeBuddy、Kimi Code)→~/.local/bin- Homebrew(Apple Silicon)→
/opt/homebrew/bin - Homebrew(Intel)→
/usr/local/bin - npm 全局安装 →
~/.npm-global/bin - nvm →
~/.nvm/versions/node/v<version>/bin - fnm →
~/Library/Application Support/fnm/node-versions/v<version>/installation/bin - Volta →
~/.volta/bin - Cargo →
~/.cargo/bin - Bun →
~/.bun/bin - mise →
~/.mise/shims
GroAsk 的检测策略分两层:
第一层:文件系统扫描。启动时扫描上面所有已知路径,纯文件检查,不依赖 shell,100% 可靠。对于 nvm 和 fnm 这种版本管理器,还会遍历已安装的所有 Node.js 版本目录。
第二层:Shell PATH 快照。从用户的登录 shell 读取完整 PATH:
let shell = ProcessInfo.processInfo.environment["SHELL"] ?? "/bin/zsh"
process.arguments = ["-i", "-l", "-c", "printf '\(marker)%s' \"$PATH\""]
这里有个坑:conda、pyenv 等工具会在 shell 启动时输出噪声到 stdout。GroAsk 用一个标记字符串 __GROASK__ 来隔离——只取标记之后的内容作为 PATH 值。
两层结果合并去重后,GroAsk 得到一份完整的搜索路径列表。检测命令是否可用就是遍历这些路径,检查可执行文件是否存在,纯文件操作,零 subprocess 开销。
智能 PATH 注入
找到命令还不够。当 GroAsk 在终端里执行命令时,终端的 shell 环境未必包含那个路径。
GroAsk 的做法:启动时记录一份 shell 原生 PATH 快照。如果命令所在目录已经在原生 PATH 里,说明新终端窗口也一定能找到它,直接执行。如果不在——比如是通过兜底路径扫描发现的——就在命令前注入一行 export PATH="<dir>:$PATH",保证执行环境正确。
多余的 export 无害,缺失的 export 致命。宁可多加,不能漏掉。
一键安装:图形化解决 CLI 门槛
"装一个 CLI 工具"对开发者来说可能就是复制一行命令。但对非命令行用户来说,这是一道墙。
GroAsk 在设置界面为每个 CLI AI 工具提供了一键安装按钮。点击后自动在终端执行安装命令,同时启动轮询检测——每 2 秒通过 shell 子进程检查命令是否已安装,3 分钟超时。
安装过程中,通道标签显示"安装中..."状态。检测到安装完成后自动刷新状态,无需用户手动操作。
依赖链自动处理
最复杂的情况是需要 npm 的工具——Gemini CLI 和 Codex。
三种情况,三种路径:
- npm 可用:直接执行
npm install -g @google/gemini-cli。 - 有 fnm 没有 npm:弹窗提示,确认后执行
fnm install --lts装 Node.js,再安装 CLI 工具。 - fnm 也没有:弹窗提示"一键安装 Node.js 环境",确认后执行完整链条:
curl -fsSL https://fnm.vercel.app/install | bash -s -- --force-no-brew && \
source "${ZDOTDIR:-$HOME}/.zshrc" && \
fnm install --lts && \
eval "$(fnm env)" && \
npm install -g @google/gemini-cli
一个按钮,背后是 fnm 安装 → shell 配置加载 → Node.js LTS 安装 → 环境变量设置 → CLI 工具安装的完整链条。用户只需要看着终端滚动,等按钮变成"已安装"。
为什么选 fnm 而不是 nvm?fnm 是 Rust 写的,安装速度快,不需要 Homebrew,不需要 sudo,--force-no-brew 参数确保纯净安装。
对于使用 curl 安装器的工具(Claude Code、CodeBuddy、Kimi Code),安装完成后 GroAsk 还会自动修复 PATH——检查 ~/.zshrc 是否已包含 ~/.local/bin,没有就追加。避免用户装完工具却发现终端找不到命令。
竞品对比:GroAsk 做了什么不同的事
市面上有几个类似的工具:
Claude Code Now(VS Code 扩展)。在 VS Code 里启动 Claude Code,绑定了编辑器。GroAsk 是系统级的,不依赖任何编辑器,在任何应用里都能唤起。
Raycast 插件。Raycast 是强大的启动器,但它的 Claude Code 插件功能有限。GroAsk 支持带 prompt 启动(不只是打开终端),支持工作区别名自动补全,支持图形化安装。
GroAsk 独有的能力:
- 带 prompt 直接启动:不是打开一个空的 Claude Code 会话,而是带着你的问题直接开始工作。
- 图形化一键安装:从未装过 CLI 工具的用户也能一键搞定,包括 Node.js 依赖链。
- 多 AI 切换:同一个输入框,6 个 CLI AI + 4 个 Web AI,一键切换。Claude Code 不是唯一选择。
- 划词即问:选中文字,快捷键,直接发给 AI。不用复制粘贴。
- PATH 自动检测:不管你用什么方式装的工具,GroAsk 都能找到。
数据
GroAsk 从第一行代码到现在,14 天。5600 行 Swift + 1200 行 Server 端代码。190 次提交,其中 49% 由 Claude Code 完成。
纯 AppKit 实现,没有 SwiftUI,没有 Electron。macOS 原生,内存占用极低。
6 个 CLI AI 通道:Claude Code、Gemini CLI、Codex、CodeBuddy、Kimi Code、Qwen Code。4 个 Web AI 通道:ChatGPT、Claude、Gemini、Monica。一个工具覆盖所有主流 AI。
完全免费,无需注册。
未来
当前的实现已经足够稳定——四种终端的自动化方案经过了大量边界情况测试。但还有很多可以做的事情:
- 会话管理:记住每个项目上次的 AI 对话状态
- Agent 工作流:多步骤任务串联
- 更多 CLI AI 的支持:新工具出来时快速接入
GroAsk 在持续迭代。如果你每天和 Claude Code 打交道,试试用 ⌥Space 替代 cd。
下载 GroAsk: groask.com
反馈与建议: 评论区留言,或通过官网联系我