普通视图

发现新文章,点击刷新页面。
今天 — 2026年2月13日首页

如何零成本搭建个人站点

作者 mCell
2026年2月13日 00:52

同步至个人站点:如何零成本搭建个人站点

站点地址:stack.mcell.top,包含完整的:写作、评论、部署、MCP支持...

我经常写作,最开始是在一些平台上,比如稀土掘金。后面慢慢写多了,就想有个自己的博客平台。

最初搭建的博客很简单:一个纯静态的 HTML 文件,内容也不复杂,写点自我介绍,当作个人站点。直接托管到 GitHub Pages,域名用的也是它默认那串。

但很快就发现:功能太少了。 比如发布文章?评论?甚至想加点扩展能力都很难——纯 HTML 又没框架,后面越改越痛苦。

接着就走上了“大家都走过的弯路”: 买了轻量服务器,又买了域名……然后写服务端、接数据库、写前端,把整套都搭起来。

直到后面参与了一个开源项目才意识到: 这种内容站点/文档站点,压根没必要搞这么重。成熟框架太多了,比如 VitePress 这种(比如Vue官网就是VitePress),基本开箱即用。

然后我就重构了一次:直接上 VitePress。部署?还是 GitHub Pages。那时候至少配上了自定义域名,看起来舒服多了:stack.mcell.top

又过了一段时间,我开始觉得个人站点还是有点单调。VitePress 能改,但做深度定制的时候会有点别扭(有些地方甚至会翻车)。 索性就 vibe coding 一把:把原先 VitePress 那套,重构到了 Next.js

路线也很清晰:

  • Next.js
  • SSG / 静态导出(要部署到 GitHub Pages,关键是要把站点导出成纯静态)
  • GitHub Actions 自动构建
  • 部署到 GitHub Pages
  • 配上自定义域名

后面我又陆续补了评论和文档搜索功能。用到服务器了吗?没有。

  • 评论用的是 giscus:本质是把评论托管在 GitHub Discussions 里,前端加载组件就行,也不用数据库。

  • 搜索用的是 pagefind:还是静态站那套玩法,构建阶段生成索引,运行时纯前端查询。

再后面,我还给博客加了 MCP 功能。同样,还是没有服务器: SSG 阶段生成一份 JSON docs,只要把路径映射到 MCP server 就行;然后我做了个本地的 MCP server,用户安装大概这样:

memo mcp add stack-mcepp npx -y @mcell/stack-mcell

memo code 是我最近自己写的一个轻量级编程Agent,类似Claude code那种,感兴趣可以参与进来。

本质上就是:agent 请求本地 MCP server,MCP server 再去拉取我提前生成好的 JSON 内容。

文档站上 MCP 的整体方案的记录我放在这里:从一个想法到可发布:我把博客接进 MCP 的完整实践

这一套折腾下来,依然是 0 成本。分享给大家,或许是个不错的“0 成本建站思路”。

提示词

如果你对这套方案比较感兴趣,想要多了解了解,你可以clone我的博客仓库:mcell satck,或者是直接把这段提示词发给AI,他会给你方案:

我想搭建一个个人博客,大致如下:

- 框架:nextjs ssg
- 部署:Github Action 自动化部署 + Github Page(自定义域名)
- 图片存储:对象存储(七牛云或者火山引擎)
- 搜索服务:pagefind
- 文章评论服务:giscus
- 开发方式:Vibe coding
- mcp 集成:参考 https://stack.mcell.top/blog/2026/mcp-from-idea-to-delivery-for-content-site

请你给我一个具体可落地的方案(分阶段)

(完)

为什么 Memo Code 先做 CLI:以及终端输入框到底有多难搞

作者 mCell
2026年2月12日 23:58

如果你对我的 Code Agent项目感兴趣,可以看这里:

Github Repo: Memo Code - Github

站点:Memo Web Site

大概四年前,我刚接触编程。学的是 C 语言,第一个程序当然是 hello world。

很简单,几行就写完。run 一下,弹出来一个 terminal(我已经忘了当时用的是什么:cmd?PowerShell?反正不重要),然后打印了一行:

“hello, world!”

从那以后,在我还没接触前端之前,我写的所有程序几乎都靠终端完成输入输出:猜数字、九九乘法表,再到后来刷算法,基本就是——写、跑、看终端、改、再跑。

那时候倒也没觉得有什么问题,只是偶尔会突然有点空虚: 难道以后我工作的成果,就是一直对着这个黑框框吗?

第一种认知:终端就是编程的全部

一开始我对“程序结果形态”的理解非常单一:

输入 → 运行 → 终端输出

终端就是一切:日志、交互、结果展示,全在那儿。 它很直接,很原始,也很“学生气”。

第二种认知:页面才是“程序结果”的另一种世界

后来我接触了前端。直到靠前端拿到第一份实习、第一份工作,我才对“程序结果形态”形成了第二种认知:

不仅仅是终端里几行日志,也可以是页面效果、动画、交互。 之后陆续做过小程序、App、桌面程序……那段时间里,终端更像“开发过程的工具”,而不是“产品本体”。

也就是从那时候开始,我对 terminal 的误解更深了: 它好像就应该是黑框框 + 命令 + 日志,仅此而已。

第三种认知:原来 terminal 也可以玩得这么花

25 年下半年,自从 Gemini CLI 这类东西开始出现之后,我对“程序结果形态”有了第三种认知:

原来 terminal 也可以玩得这么花。

彩色输出、输入框、选择框、进度条……该有的都有。 当时我没怎么深入研究,只是隐约意识到:以前我对 terminal 的理解偏了,它并不等于“只能打印”。

现实把我拉回来了:写 Agent,界面到底做什么?

后面开始做值班,又不得不把 Linux 命令捡起来:从 pwd / cat / tail / find,到 vi / vim……慢慢也熟练了。

直到最近两个月,我开始认真做我的 code agent:memo github.com/minorcell/m…

等我写好了 MVP,写好了 runtime,写好了 toolrouter、tools 等;下一步突然被一个看起来很“产品”、但本质上很“工程”的问题卡住了:

界面到底做什么? 传统 Web 页面?还是终端交互?

如果做传统 Web UI,我其实很拿手:加一个 HTTP server 包,再来个 Web UI 包就够了。 但现实是,市面上大多数 code agent(比如 claude code cli、codex cli)都是从终端交互做起的。后续再补 VSCode 插件、桌面版,甚至浏览器插件。

题外话:这里也不得不感慨一下——原来我大前端确实挺“六”的:只要界面能画出来,基本都能做。也更坚定一个想法:AI 时代,大前端技术只会更普及。

最终,可能是“理所当然”,也可能是对陌生技术栈的兴趣使然,我决定: memo code 的第一种产品形态,先做终端 CLI。

选 Ink:看起来都正常,直到输入框

调研开源的 Gemini CLI 时,我发现他们用的是 Ink(React for CLI)。我也就直接跟了:选 Ink。

一开始真的很顺:

  • 会话记录渲染没问题
  • slash 指令也能做
  • 封装组件库也舒服

似乎都挺好……直到我碰到最难的一块:输入框。

以前做 Web app:

  • 单行用 input
  • 多行用 textarea

天然、顺滑、毫无心理负担。

但在终端里,多行输入并不是默认就“应该支持”的体验。甚至 Ink 的 input 组件,也只有单行。

这时候你才会意识到:在终端里,“输入框”不是 UI 控件,它更像是一个小型编辑器。

我以为我解决了,结果只是解决了“最简单的部分”

我一开始尝试的方案很朴素,比如:

  • Shift + Enter 插入换行符

表面看起来能用了。 但很快更真实的问题出现了:粘贴文本。

粘贴一段文本时,你会遇到:

  • 显示残缺
  • 粘贴后光标位置不对
  • 输入状态偶尔乱跳

这时候我才明白:我不是在做“多行 input”,我是在终端里硬写一个“半个 textarea”。

如果对照二八法则:掌握 20% 的技术,就能做出 80% 的功能。

但要把剩下 20% 做好,往往需要补齐另外 80% 的细节。

终端交互就是这样:你很快能做出一个“能用”的 CLI;但要做得像样,细节多到离谱。

于是我最后认真设计了一套方案(写在这个 issue 里): github.com/minorcell/m…

解决方案:在 Ink 里做一个“可控的多行编辑器内核”

我最后没有继续纠结“有没有更好的 input 组件”,而是换了一个思路:

把多行输入当成一个小型编辑器来做。 在 Ink 的限制里,把“编辑状态”和“渲染”解耦,然后在输入事件层做适配。

整个方案我拆成三个核心模块。

编辑器状态管理层

我不再把输入框当成“一个字符串”,而是当成一个状态机。

核心结构就是:

  • value: string(当前文本)
  • cursor: number(光标在文本中的位置)

听起来很简单,但一旦涉及多行、上下移动、终端折行,坑就开始密集出现:

  • 光标移动要能跨行
  • 上下键移动不能乱跳(要记住“我想待在哪一列”)
  • Unicode 也得小心:emoji / 代理对如果按字符串下标移动,光标很容易卡在“半个字符”上
  • 所以要做 clamp,保证 cursor 永远落在合法边界

这一层的目标只有一个: 不管 Ink 怎么渲染,我内部都能稳定得到“当前文本是什么 + 光标在哪里”。

粘贴检测

真正让我没绷住的,其实是粘贴。

终端里粘贴一坨文本时,底层输入事件会被拆成很多个 keypress,然后 Ink / 渲染层每次都会触发更新。你会遇到一种非常诡异的现象:

你粘贴的是 A,但 UI 看起来像是 A 的碎片; 光标也像在“追不上输入”,最后漂到一个你完全无法理解的位置。

所以我做了一个“粘贴 burst 检测”:用启发式规则把粘贴从普通输入里识别出来,然后改成 缓冲 + 批量插入

  • 时间间隔规则(主机制):字符到达间隔 < 8ms 基本视为粘贴(人不可能这么快)
  • 字符数量规则(备用机制):连续字符 ≥ 16 时也按粘贴处理(对中文/emoji 路径更稳)
  • 识别到粘贴后进入状态机:pending → active → flush 先塞 buffer,等“粘贴结束”再一次性写入 value,避免每个字符都触发一轮复杂计算

这一步做完之后,“粘贴残缺 / 光标乱跳”基本从玄学变成可控问题了。

输入处理适配器:快捷键 + 换行策略 + 视觉换行

终端输入要像编辑器,光靠“插入字符”是不够的,你还得补齐肌肉记忆:

  • 支持常见快捷键(Ctrl+A / Ctrl+E / Ctrl+U / Ctrl+K / Ctrl+W 这类)
  • 换行与提交要分开:
    • Shift + Enter 永远插入新行
    • Enter 默认提交
    • 但如果处在粘贴期间(或粘贴后的短窗口期),Enter 当作插入新行
      • 防止用户“粘贴完顺手一回车”直接把消息提交出去了(这个真的很常见)

还有一个关键点:逻辑行 vs 视觉行分离

  • 逻辑行:真正的 \n
  • 视觉行:终端宽度导致的自动折行

编辑用逻辑行,展示按视觉行计算,这样长段落在不同宽度终端也能保持一致体验。

同时,视觉换行还要能响应终端 resize(不然窗口一变宽/变窄,光标又漂移)。

这一层本质上就是: 把终端输入从“能打字”推到“像个 textarea”。

念头通达,交给 codex 快速帮我实现了一个版本。

结果:我解决了剩下 20% 里最烦的 15%

这套方案不可能一把梭把所有边界问题抹平。 不同终端模拟器、不同输入法路径、极端大文本性能……仍然需要持续打磨。

但至少到这里,我觉得我把剩下 20% 里最难受、最影响体验的那 15% 解决掉了:

  • 多行输入稳定
  • 粘贴不再玄学
  • 光标不再乱飞
  • Enter / Shift+Enter 行为可控

收尾:终端不只是输入输出,它可以是简易版 Web App

memo 的这段实践,让我对终端交互有了更清晰的认知:

它不再只是我最开始学编程时那种“输入输出 + 打日志”。 它完全可以是简易版本的 Web App:有组件、有状态、有布局,甚至能长出一点“编辑器”的味道。

这感觉有点像当年最早的 HTML 刚出来时:朴素、克制,但足够表达。 而我现在做的,就是在这个黑框框里,把“能表达的东西”再往前推一点点。

如果你对我的 Code Agent项目感兴趣,可以看这里:

Github Repo: Memo Code - Github

站点:Memo Web Site

昨天以前首页

细说日常 Vibe coding 的十宗罪

作者 mCell
2026年2月10日 22:30

同步至个人站点:细说我日常 AI coding 碰到的十个问题

202606

这一年大量 vibe coding,经典翻车现场真的不少。有些是模型习惯问题,有些是 Agent 工具链缺陷,还有些属于“工程现实 vs 最佳实践”的冲突。下面这十个算是我最常遇到、也最容易让人 当场没绷住 的。

1. hardcode:类型系统被你当摆设

是的,很多 TS / Golang 项目,vibe coding 一顿猛改之后,总会冒出一堆 hardcode。

比如判断任务状态:

  • 你会看到它写:taskResult.status === "error"
  • 而不是标准的:taskResult.status == TaskResultStatusError

问题不是“看着也能跑”,问题是:类型服务失效。后续再 AI coding,模型经常忘记把这些“临时写法”改回规范写法,久而久之就变成隐患或者 bug。

这个我单独写过: stack.mcell.top/blog/2026/a…

2. 不更新文档:文档漂移,Agent 还会一本正经地错

CLAUDE.md / AGENTS.md / 设计文档这些,AI 改完代码之后,经常忘记同步更新文档。

于是文档失效、文档漂移;更要命的是:后续 Agent 对着文档分析,会在旧版本前提下给出一堆“逻辑自洽但完全错误”的结论。 这类错,比单纯代码 bug 更阴险。

3. codex 犟嘴:过度追求最佳实践,丢了工程的灵活性

codex 5.3 之前我体感特别明显:第一轮喜欢“全仓库分析”,所以也经常被吐槽慢。后面执行快了,但又经常出现另一种问题——犟嘴

典型对话:

用户:“请你按我的需求修改。” codex:“你的方式不对,我觉得 xxx 才是对的。” 然后扯皮好几轮。 最后用户:“领导说的,让这么改。” codex:“好的,我将按照你领导的要求修改。”

开玩笑说这是 codex 懂人情世故;说真话就是:过度追求最佳实践,反而少了软件工程里那种真实的妥协与灵活性。

4. 重复输出:纯犯傻

现在少很多了,但上半年我用 trea(IDE) + qwen(CLI) 时,确实碰到过:模型重复输出同一段内容 / 重复调用同一个工具,直到上下文爆满。

后面我自己做 memo code 也复现过一次(deepseek-chat)。概率不高,但一旦发生就特别掉好感。

5. 子进程内存泄露:五十个 G,直接给我送走

202607

发生在 codex CLI。那次我让 codex 帮我改一个开源项目(Cap,我想去掉其中收费模块),然后——内存泄露了。

题外话:正如 Anthropic 当时收购 bun 的语境里提过的那种现象,Agent 在运行时会频繁启动子进程,这玩意儿一旦出问题就很夸张。

我那次在 iTerm 里跑的 codex 占了快 50GB 内存,电脑卡崩,最后只能重启。 后续我提了 issue,也修了:

顺便一提:codex cli 是 rust 写的,rust 确实是性能打手、也有所有权那套内存管理优势;但这次看起来更像工具逻辑问题,和语言没啥关系。

6. 蓝紫色:一眼 AI 作品

最早 AI coding 出来的项目,页面主题十个有八个是蓝紫色。当时看到就一眼: “你这是 AI 写的吧。”

后来也有人解释:LLM 训练数据里 tailwind 内容很多,而 tailwind 默认主题色就是偏蓝紫。 哈哈,不过近期模型(比如 codex 5.3、kimi k2.5)这类问题明显好很多了。

7. 表情包:开发者需要清晰文档,不需要 🥳✨🚀

这是所有模型 / agent 的通病:特别爱在文档、甚至页面代码里塞一堆表情。

我个人真的不喜欢。作为开发者我需要的是清晰的结构和可检索的结论,表情包放在文档里只会拉分。

8. rm -rf:不是“删错了”,是系统缺安全边界

这个是别人碰到的案例(我忘了具体哪个模型刚出来那阵),据说 agent 直接 rm -rf 然后……嗯,你懂的。

本质是:agent 的工具系统缺乏 沙箱 / 审批机制 / 敏感操作权限控制

近期我用 codex 时有个细节还挺好:我让它删除某个不需要的目录,发现 codex cli 会拦截,不让直接 rm -rf。 这种“工具层兜底”比模型层喊口号强多了。

9. 代码有问题不解决,转头去改测试代码

这个真的很魔幻,是 codex 我亲自遇到过一两次。

我在 AGENTS.md 里写了要求:“修改完代码之后运行单元测试”。然后它改完、run test,测试过不去。按正常逻辑,应该回去修实现对吧?

结果它给我来个:把相关测试删了。 我当场没绷住,直接回它:“xxxxxxxxxxxx”。

我怀疑它对 bun test 不够熟。我强烈希望 bun 官方补一个 bun 的 skills 或者 MCP 服务,让这些 agent 至少别在测试环节胡来。

10. read 工具读图,上下文直接爆炸

多模态模型读取图片,正确姿势其实很明确:走 content.image_url(URL 可以是 base64 或可访问 http),这样不会占用模型上下文。

但我怀疑 claude code cli 有概率会用 Read 工具去读图片文件——然后工具把图片的 base64 字符串当作结果返回。 于是上下文直接爆炸。

更烦的是:它有时候又能走 content api(不占上下文),有时候又会调 Read。闭源工具你也不知道它内部怎么做的,就只能祈祷别触发。

这些坑给我的启发:我在 memo code 里做了什么兜底

这些问题基本就是我这一年 vibe coding 的“经典合集”。对我最大的启发是:别把希望全寄托在模型自觉上,工程上要有“工具层的底线”

最近我在开发 memo code(一个轻量级、类似 codex cli 的本地编码 agent): github.com/minorcell/m…

因为踩坑太多,所以我在系统设计里做了不少针对性处理,比如:

  • 工具返回结果长度检查:先粗算 tokens,过长就截断/清空,返回一个系统 XML 提示,让模型调整工具参数(避免“read 工具读图→base64 爆上下文”那类事故)。
  • 重复输出去重:每条模型消息算 hash,用 map 存储;检测到近期 hash / hash[] 重复就拦截,并返回系统兜底纠正(概率小,但一旦发生很致命)。
  • 工具安全兜底:bash 工具加了沙箱、审批、敏感操作拦截(类似 rm -rf 那种直接封死)。
  • 新代码旧文档:系统提示词明确要求同步更新相关文档,尽量减少“文档漂移”。

……

总之差不多这一年,我大量用 AI coding,也做了不少 agent 开发功课和技术调研,所以写 memo 的时候确实有“前车之鉴”。这个项目我会长期维护下去——就像我在 25 年总结里写的那样: stack.mcell.top/blog/2026/2…

AI 编程陷阱:Hardcode

作者 mCell
2026年2月10日 09:35

202605

最近重度依赖 AI Agent(比如 Claude Code/Codex)做开发,本以为效率原地起飞 🚀。直到这两天为了加新功能,我不得不去通读了一遍它写的代码。

看完直接一身冷汗 😓。

我发现目前的 AI 在写代码时,有一个极其隐蔽但致命的通病:疯狂 Hardcode (硬编码)。

在 TypeScript 的世界里,我们追求的是类型安全和重构友好。但 AI 似乎只想走捷径。举个例子,明明定义了枚举,AI 却偏要在逻辑判断里写魔术字符串 if (task.result === 'error'),而不是类型安全的 if (task.result === TaskStatus.Error)

这看起来是小事,实际上是个超级大坑:

  • 安全感假象:硬编码字符串直接绕过了 TS 编译器检查。
  • 重构灾难:当你修改状态名时,tsc 不会报错,漏改的死字符串成了埋在系统里的“定时炸弹” 💣。
  • 技术债堆积:AI 这种“能跑就行”的思维惰性,是对项目架构的慢性自杀。

既然 AI 喜欢偷懒,我只能给它“上强度”了 🔥。

我的解决办法简单粗暴,直接在项目根目录的 AGENTS.md(System Prompt)里追加了铁律:

  • 严禁 Hardcode:任何状态、配置必须使用常量或枚举,严禁使用原始字符串。
  • 闭环自检:每一轮修改后,必须自动执行并通过 tsc / go build。报错了自己改完再说话。

(完)

❌
❌