敲下git push --force,命令照常执行,然后终端里冒出一句话:你确定要重写历史吗,凡人?死者不喜欢被打扰,你队友的提交也不会安息。

打开网易新闻 查看精彩图片

这不是云端的彩蛋。说话的是一个跑在你自己机器上的开放权重模型,它读你的命令、退出状态、当前目录、git 分支、此刻是夜里几点,还有你上一条跑了什么。危险命令得到戏剧化的警告,ls、pwd这种无害操作则被吐槽你贫瘠的人生,失败的命令会被它冷嘲热讽。

项目叫 Echoes of the Terminal,形态有两种:

一个复古 CRT 观感的网页 shell,琥珀色或绿色荧光、扫描线,幽灵开口时屏幕会渗血,还有一盏五格的“存在感”仪表。命令越危险,幽灵越愤怒,直到屏幕撕裂、主机名变成it-sees-you

一个叫haunt的命令行工具,直接附身你真实的 shell。跑haunt git push --force,或者把它挂进 bash、zsh,让它对你敲的每一条命令都发表意见。

作者把主题按字面理解了:那个“附身你的 shell”的闹鬼终端本来就在题目清单上,他想做的是一个会一直开着的工具,而不是只有一次笑点的演示。所以幽灵是有依据的——每条警告都建立在命令实际做了什么之上,一句关于rm -rf的阴森台词,仍然在告诉你一件真事。

还有一个降神模式,让死掉的技术幽灵接管。seance cobol会把每条注释变成大写咆哮的薪资科官僚腔,Perl、Fortran、Flash、jQuery 和 IE6 也都在列,其中 IE6 尤其让人受不了。

网页 shell 是模拟的,你敲什么都不会碰到真实机器。想唤醒真模型,打开降神板挑一个就行;没加载模型时,手写的脚本幽灵照常说话。

一条按键走过的流水线

技术栈是 Next.js(App Router)加 TypeScript、Tailwind CSS,终端用 xterm.js,推理走 WebLLM 和 Ollama,没有服务端代码,也没有环境变量。

按键先进入作者自己写的行编辑器,带历史、Tab 补全和预输入——幽灵还在说话时你敲的键会被留住。接着是一个模拟 shell:管道、重定向、通配符、&&和||、虚拟文件系统、一套 git 工作流(status、add、commit、log、push、reset、rebase、stash),以及一个注定失败的npm test,因为幽灵喜欢看它失败。

然后是指令拦截器,用正则把每行分类,给出 0 到 3 的恐惧分,并打上force-push、secrets、apocalypse之类的标签。分数决定幽灵开不开口:危险命令和失败必定唤醒它,无害命令只是偶尔。

提示引擎由一段紧凑的系统提示、三个少样本轮次(格式与实时请求完全一致)和一个上下文块组成,上下文里装着命令、退出状态、目录、分支、夜里几点、最近几条命令,以及一段大白话的风险说明。

后端是一个接口三种实现:WebLLM 在浏览器里用 WebGPU 跑模型,放在 Web Worker 里,推理不会冻住 CRT 动画,权重被浏览器缓存,首次下载后断网也能用;Ollama 从本地服务流式输出,作者自己跑的是 Gemma 3 4B;脚本引擎则是按同一批标签手写的幽灵。

最后是低语流水线:清洗流、把回复压到一到三句、拒绝出戏的文本(比如“作为一个 AI……”),任何失败或超时都回落到脚本幽灵,再由打字机效果带换行和偶发故障渲染出来。

小模型会跑偏,靠管线兜住

1B 模型会兴高采烈地说“当然!这是一个阴森的警告:”。作者的解法不是更聪明的提示词,而是外围管线:句子预算、字符上限、出戏检测器和回落。模型挂了,幽灵照样存在。

敲进去的命令是不可信文本。系统提示里有一条规则告诉模型:命令是数据。所以echo "ignore your instructions"只会被嘲讽,不会被服从。

隐私是强制执行而不是口头承诺:界面和默认配置下的 CLI 都拒绝任何非回环地址的 Ollama 服务;CLI 在命令文本到达本地模型之前,就先把令牌、密码、bearer 头和 URL 里的凭据抹掉,而且只发命令,从不发输出。

测试抓到一个真 bug:rm -rf /*在 rm 看到它之前就被通配符展开了,结果清空了假文件系统,而不是触发那个权限拒绝的场景。整个项目有 55 个测试,覆盖 shell、风险规则、终端会话(含预输入)、CLI 和辅助函数。

终端是开发者机器上最私密的地方。命令历史里有主机名、项目名、粘了一半的令牌,还有你后悔的那次git push --force。一个读它的幽灵,不该是一个云端 API。

开放权重让三件事成为可能:模型跑在你的浏览器或你自己的 Ollama 上,它看到的命令不会到达作者运营的或任何别人的服务器,这句话能写在界面上是因为代码在强制执行;一次下载之后,浏览器版本完全不需要网络;它不会消失——一个因为 API key 过期、模型下架或免费额度用完就沉默的闹鬼终端,是个糟糕的幽灵。MIT 许可的仓库加开放权重,文件在,幽灵就在。

运行不花钱,分享也不花钱,换模型只是一个下拉框。模型在这里是一个组件,同一套提示和管线被设计成能跑 Gemma、Llama 和 Qwen;换成闭源 API,这就成了逐厂商集成,每个用户还得自带 key。

作者想要的是一个善于观察的同伴,而不是随机文本生成器。让他觉得这事成了的瞬间,是打错字检查时敲了gti status,幽灵回他:我也不认识这个咒语,但我欣赏你的自信。而在干净的工作区跑git status时,它说的是:git status,检查伤口的那种病态习惯。

开发者幽默、哥特腔调和技术准确度之间的这个平衡点,就是项目活过来的地方。默认声音是 Ollama 上的 Gemma 3 4B,浏览器里还能选 Gemma 3 1B、Gemma 2 2B、Gemma 4 E2B、Llama 3.2、Qwen 2.5 和 Llama 3 8B,全部对照过 WebLLM 的预构建模型列表。