参赛赛道:全链路开发实战 选题方向:存量项目增量开发(内容 → 终端模拟器 → 实战 → 视觉)
#TRAE双端融合
文中截图均来自项目实际运行画面,未使用设计稿或合成图。
这不是一个从零开始的新项目。它原本是一个纯静态的 Git & GitHub 教学站,包含 6 个模块、Git 模拟终端和 17 个实战场景。这次参加 TRAE 征文,我没有推倒重来,而是在原有结构上新增了第 7 个模块:Linux 命令行,以及配套的 Linux 终端模拟器和 6 个排障场景。
换句话说,这是一次真实的「存量项目 + 本次增量」开发。下面记录的是增量部分是怎么做出来的,包括中间踩的坑。

图 1:首页 Hero,324 条命令 / 76 个主题 / 7 大模块,左侧新增 Linux 入口
一、起点:一个纯静态的教学站
项目最初的技术选型很朴素:index.html + 原生 JS/CSS,没有构建工具,没有后端,双击就能打开。
已有的能力包括:
- 6 个 Git / GitHub 章节,命令以卡片形式组织
- Three.js 粒子背景,按模块切换主题色
- 3D 知识图谱,节点可点击跳转章节
- Git 模拟终端,17 个场景,任务按仓库状态校验
这套结构的好处是扩展成本低:加一个模块,本质上就是加一份内容数据、一套渲染配置,再补上对应的交互。
二、为什么是 Linux
Git 和 Linux 经常被放在一起讲,但多数教程只讲命令,不讲它们怎么配合。实际工作里更常见的链路是:在 Linux 服务器上排查问题,改完文件,再用 Git 提交。
所以这次增量没有做「又一个命令大全」,而是围绕一条完整链路:
- 内容:10 个主题、73 条命令
- 交互:一个能真正执行命令的 Linux 终端
- 实战:6 个排障 / 部署场景
- 视觉:青绿主题,和原有暖色 Git 模块区分开

图 2:终端窗口式 Hero,右侧是实时终端预览,下方是主题 / 命令 / 场景 / 系统版本信息条
三、把需求拆成四层
动手前先拆了一层,避免一上来就写代码:
| 层 | 目标 | 产出 |
|---|---|---|
| 内容层 | 命令能被查、能被搜 | content-linux.js |
| 交互层 | 命令能被执行 | linux-simulator.js |
| 实战层 | 场景能通关、能校验 | linux-scenarios.js |
| 视觉层 | 模块有辨识度 | 主题变量 + 卡片样式 |
这四层对应四个文件,彼此不耦合。后来调试时这一点帮了大忙:模拟器出问题不用动内容,样式出问题不用动逻辑。
四、和 TRAE 的实际协作过程
4.1 先读代码,再定接口
第一步不是让 TRAE 直接写 Linux 模块,而是让它先读现有的 Git 模拟器,弄清楚命令是怎么执行的、输出是什么格式。
原有接口是:
lua
GitSimulator.execute(repo, cmd); // => [{ type, text }]
新增的 Linux 模拟器沿用了同一套输出协议:
lua
LinuxSimulator.execute(fs, cmd);
// type: stdout | stderr | command | clear
这样实战页只需要按赛道切换调用对象,渲染层完全不用改。接口对齐之后,后面的工作才真正开始。
4.2 分文件生成
内容、模拟器、场景三份文件是分开生成的,每份都有明确的验收标准:
- 内容文件:能被现有渲染函数直接消费,不需要改渲染逻辑
- 模拟器:场景里用到的命令必须全部支持
- 场景文件:每个任务都有 validator,能自动跑通
4.3 四个真实的 bug
这部分是整篇文章里最值得写的,因为它们都不是「生成出来就能用」。
第一个:通配符不展开
cp -r ~/dist/* /var/www/site 报 cannot stat ~/dist/*。查下来是 tokenize 把所有以空格结尾的 token 都标成了 quoted,导致通配符被当成普通字符。修法是引入 hadQuote 标记,只有真正带引号的 token 才跳过展开。
第二个:权限位全错
最初 mode 存的是十进制 644,计算时却按八进制做幂运算,ls -l 输出的权限位完全不对。后来统一用 parseInt('644', 8) 存储,并补了 modeDigits(),符号模式(+x)则通过字符串位替换实现。
第三个:复制文件后时间报错
cp / mv 用 JSON.parse(JSON.stringify(node)) 深拷贝,mtime 从 Date 变成了字符串,ls -l 直接抛 d.getMonth is not a function。修法是在 cloneNode() 里把 mtime 还原成 Date。
第四个:快照显示 0 目录 0 文件
场景的 cwd 设在 /home/dev,日志文件却在 /var/log,快照自然什么都看不到。这不是代码 bug,是场景数据设计错了,调整 cwd 之后才恢复正常。
这四个问题有一个共同点:都能「跑」,但结果不对。只靠看代码很难发现,必须实际执行、实际截图。
4.4 验证方式
- 6 个场景、18 个任务,validator 全部通过
- 浏览器实测:无 JS 报错,1440 与 390 宽度下无横向溢出
- Git 赛道回归:
git status/add/commit和仓库快照正常

图 3:Linux 500 排障场景,任务条、终端输出与文件系统快照
五、几个关键实现
5.1 虚拟文件系统
节点模型很简单:
matlab
{ type: 'file' | 'dir' | 'link', content, size, mode, owner, group, mtime }
目录和文件共用一套结构,路径归一化、.. 和 ~ 的处理都集中在一个 normalize() 里。权限统一存八进制数值,展示时再转成 -rw-r--r--。
5.2 管道与重定向
一条命令先按 | 切段,每段单独解析、单独执行,上一段的 stdout 作为下一段的 stdin:
ini
var segments = splitPipeline(raw);
var stdinLines = null;
for (var i = 0; i < segments.length; i++) {
var res = runSingle(fs, argv, stdinLines);
stdinLines = res.stdout;
}
重定向 > >> < 在 runSingle 里处理,通配符在解析后展开。这样 ps aux | grep node、grep 500 access.log | wc -l 这类组合才能正常工作。
5.3 场景校验看状态,不看命令
validator 不匹配用户敲了什么,而是检查环境状态:
javascript
validator: function (fs) {
return fs.history.some(function (h) {
return /grep\s+.*500/.test(h.cmd) && /access.log/.test(h.cmd);
});
}
有的任务检查文件权限,有的检查服务是否重启,有的检查归档文件是否存在。这样用户可以用不同命令达到同一结果,不会因为「没按标准答案敲」而卡住。
5.4 双赛道
Git 和 Linux 的进度分开记录:
ini
var completedByTrack = { git: [], linux: [] };
切换赛道时重置当前环境,但各自的完成记录保留。终端标题、提示符、欢迎语、徽标都会跟着切换。

图 4:Linux 命令卡片,图标头、行号槽、命令 / 参数 / 注释分色,危险命令单独标红
六、视觉:从「能用」到「像产品」
功能跑通之后,第一版界面其实很粗糙:Linux 章节沿用了 Git 的琥珀色,文件快照像调试输出,权限位挤在文件名前面。
这一轮改了三件事:
- 给模块建立身份:青绿主题变量、终端窗口式 Hero、四个信息条,右侧再加一个实时终端预览。
- 给代码块加编辑器质感:左侧行号槽、行首命令高亮、参数与字符串分色、悬停时行号变亮。
- 给快照面板加信息层级:路径、目录 / 文件 / 进程三项计数、服务状态圆点、带表头的文件列表。

图 5:文件系统快照,路径、三项计数、服务状态与「名称 / 权限 / 大小」表头
窄屏也顺手修了两处:汉堡按钮不再压住面包屑,实战页网格从 1fr 改成 minmax(0, 1fr),390px 下页面宽度不再溢出。

图 6:390px 下的 Linux 章节,信息条收敛为三项,卡片改为单列

图 7:390px 下的实战页,终端与文件快照纵向排列
七、踩坑与反思
- 纯静态站有边界:没有后端,就接不了需要密钥的 AI 接口。这也是这次没做「AI 问答助手」的原因,硬接只会把 Key 暴露在前端。
- 模拟器不必追求全覆盖:支持 50 多条常用命令,足够跑通 6 个场景即可。追求「什么都能执行」会迅速失控。
- AI 生成的代码必须逐段验证:解析、权限、时间这类隐蔽逻辑,看代码看不出问题,必须实际跑。
- 场景数据也是代码 :
cwd设错导致快照为空,这类问题提醒我,场景配置同样需要测试。
八、结果
- 324 条命令、76 个主题、7 大模块
- 知识图谱 47 个节点,其中新增 11 个 Linux 节点
- 23 个实战场景(Git 17 + Linux 6)
- Linux 18/18 任务校验通过
- 页面无 JS 报错,1440 / 390 两档宽度无横向溢出

图 8:3D 知识图谱中的 Linux 节点簇

图 9:Git 赛道回归,原有 git status 与仓库快照保持正常
九、下一步
- 给 Linux 场景补更多真实故障,比如端口占用、DNS 解析失败
- 在不引入后端的前提下,用 Serverless 函数接一个命令解释助手
- 把双赛道的进度做成可分享的学习记录
项目运行方式很简单:
yaml
python -m http.server 8973