我与 Codex 的一周:从一份设计文档到一个桌面应用

4238 字
21 分钟
我与 Codex 的一周:从一份设计文档到一个桌面应用

WingsBlogManager 是一个 Electron + Svelte 5 桌面应用,用于可视化管理个人博客的 21 个配置文件、文章、媒体资源和部署流程。从 7 月 3 日的第一条消息到 7 月 10 日的 Release 打包,我和 Codex 一起把它从零做到了交付,来做一个小小的复盘。


展示图:#

首页
首页

一、项目缘起#

痛点#

我当前的博客 WingsBlog,部署在 Cloudflare Pages 上,采用 TypeScript 配置驱动架构——所有站点设置分散在 21 个 .ts 配置文件中:

src/config/
├── siteConfig.ts (220+ 行,最复杂)
├── profileConfig.ts (个人资料)
├── navBarConfig.ts (导航栏,含动态函数)
├── sidebarConfig.ts (双侧边栏 widget 布局)
├── fontConfig.ts (自定义字体)
├── pioConfig.ts (Live2D + Spine 看板娘)
├── friendsConfig.ts (友链,含筛选函数)
├── footerConfig.ts (页脚 HTML)
├── musicConfig.ts (音乐播放器)
├── commentConfig.ts (评论系统,5 种后端)
├── ... 还有 11 个
└── i18n/languages/*.ts (5 种语言,385 个翻译 key)

每次改配置都要:打开 .ts 文件 → 修改代码 → Git 提交推送 → 等 Cloudflare 重新部署。写一篇文章要在编辑器里手写 frontmatter YAML,管理图片要手动往 public 目录里丢文件。

这不是博客管理,这是代码维护。

想法#

我需要一个桌面应用,把所有这些”改代码”的操作变成可视化的表单、开关、拖拽和预览。7 月 3 日,我写了一份 DESIGN.md 设计文档,然后打开 Codex,说了第一句话:

“根据设计计划内容开始开发(用户界面等设计部分可以根据你的分析做调整,做到界面对用户使用友好)”

这句话开启了一场为期一周、跨越 70+ 轮对话的密集协作。


二、开发全貌#

数字概览#

📅 开发周期 2026.07.03 — 2026.07.10(8 天)
🗂️ 主会话 2 个(3430 行 + 2173 行 JSONL)
🔀 子 Agent 会话 8 个独立子线程并行勘察
📝 用户消息 71 条
📦 完成阶段 P0 → P8,全部交付
🧪 测试用例 298 个(Vitest)
✅ TypeCheck 0 errors
🔨 Build 通过
📦 Release 已生成 NSIS 安装包

技术栈#

层级选型理由
桌面框架Electron 34需要直接读写本地文件系统、执行 git、启动 astro dev
构建electron-viteVite 驱动,支持 HMR
前端Svelte 5 (runes)运行时代码量小,与 WingsBlog 同技术栈
样式Tailwind CSS 4与 WingsBlog 保持一致
MarkdownMilkdown 7 (ProseMirror)所见即所得,插件可扩展
配置解析ts-morphTypeScript AST 级别读写
Gitsimple-gitNode.js Git 封装
测试Vitest服务层 + 前端 + 集成 + 组件冒烟

三、协作实录:从 P0 到 P8 的全过程#

3.1 开局:一份设计文档 + 一个指令#

我的第一条消息很简单:“根据 DESIGN.md 开始开发”。Codex 做的第一件事不是写代码,而是——派出一个子 Agent(Lorentz,explorer 角色)做只读勘察

这个子 Agent 发现了关键问题:

  • npm run typecheck 因为缺少 node_modules 无法执行

  • .git 目录不是有效仓库

  • Svelte 模板中有潜在的运行时错误风险

这恰恰是 AI 协作中最容易被忽略的环节——代码可以写,但环境和前提条件不对,写了也跑不起来。

在第一个会话中,我明确提出了协作原则:

“当前正在开发一个较复杂的项目,对话上下文可能会逐渐变长。每次任务尽量只处理一个明确功能点。修改代码前先阅读相关文件并给出简短计划。优先做最小必要修改。重要设计决策需要沉淀到项目文档中。”

这些原则后来被写入 AGENTS.md,成为后续所有协作的基础。

3.2 P0—P2:打地基(7/3 — 7/4)#

前三个阶段解决的是”能不能安全地读写配置”这个根本问题。

P0:安全补丁。Codex 发现 fontConfig.tsfriendsConfig.tsnavBarConfig.tspioConfig.ts 这 4 个文件包含多个导出或动态函数,用通用的”读第一个导出、重写整个文件”的方式会破坏数据。于是将这些标记为 safeToWrite: false,禁用通用编辑器的 Save 按钮。

P1:精确写入 + 表单编辑器。将 ConfigService 改为”只替换目标导出变量的初始化器文本”,而不是重写整个文件。同时为上述 4 个复杂配置文件开发了专用的多导出编辑器。

这里有一个让我印象深刻的细节:Codex 在开发配置写回功能时,又派出了一个子 Agent(Euler,explorer 角色)分析风险。子 Agent 给出的结论是:

“单导出纯配置文件基本可用,多导出/动态文件不适合直接写回。fontConfig.tsfriendsConfig.ts 等文件有多个导出,getDynamicNavBarConfig() 是函数返回动态数据,当前工具无法安全处理。”

这种”先勘察、再开发”的模式让 Codex 的每一次改动都有理有据。

P2:Git + Cloudflare + 首次运行引导。三天时间,应用有了 Git 面板(status/diff/commit/push)、Cloudflare Pages 部署状态面板(触发/重试/监控)和首次运行的 Setup 向导。

3.3 P3—P4:打磨与扩展(7/4 — 7/5)#

P3 最核心的工作是”配置编辑器去 JSON 化”。原来的实现是:每个配置文件打开就是一个 JSON 编辑器,用户看到的是裸数据。Codex 逐一为每个配置开发了专用表单编辑器

配置编辑器形态
friendsConfig.ts页面设置 + 友链表格,支持新增/编辑/删除
navBarConfig.ts搜索配置 + 链接预设表单 + 动态菜单结构可视化编辑
sidebarConfig.ts左/右/移动端 widget 布局拖拽
fontConfig.ts字体库定义 + 字体选择器
pioConfig.tsSpine 模型 + Live2D widget 配置

最难的是 navBarConfig.ts 的动态菜单编辑器——因为导航菜单不是固定数据,而是通过 getDynamicNavBarConfig() 函数动态生成的。Codex 再次派出子 Agent(Fermat,explorer)勘察后,设计了”直接读写函数体内的 links 数组”的方案,而不是试图解析整个函数逻辑。

P4 加上了许多”让应用像正经产品”的东西

  • 键盘快捷键(Ctrl+S 保存、Ctrl+N 新建文章、Ctrl+Shift+R 刷新预览)

  • 暗色模式(localStorage 持久化 + CSS 全局覆盖)

  • 配置备份/导出和恢复/导入

  • 全局错误边界 + 操作历史面板

  • Cloudflare Token 改用 Electron safeStorage 加密存储(之前是明文存在 settings 里)

3.4 关键一战:Ctrl+S 的脏状态管理#

在开发 P3 的多导出编辑器时,出现了一个经典的状态管理 Bug:

问题FriendsConfigEditor 同时管理”页面设置”和”友链列表”两个区块。用户改了友链后按 Ctrl+S,结果页面设置的未保存修改也被清除了

Codex 的诊断是——只有一个全局 dirty 标记。解决方案是将脏状态按区块粒度拆分

FriendsConfigEditor: dirty → dirtyPage + dirtyLinks
FontConfigEditor: dirty → dirtyFonts + dirtySelection
NavBarConfigEditor: dirty → dirtySearch + dirtyPresets + dirtyMenu

并且 Ctrl+S 的行为改为:只在恰好一个目标为脏时才自动保存;多个区块都脏时,用户必须点击对应区块的保存按钮。

我让 Codex 用子 Agent 审查这个修复。子 Agent 精准地确认了修复的正确性:

“保存一个 section 不能清除无关的未保存更改——当前实现通过分 section 的 dirty 标记正确解决了这个问题。”

这种 “主 Agent 开发 + 子 Agent 审查” 的模式在后续开发中反复使用,效果很好。

3.5 P5—P8:从”能跑”到”能用”(7/5 — 7/10)#

这是一次方向性的转折

在第二个会话中,我提出了核心诉求:

“当前项目其实并没有很好地解决原来修改配置文件需要打开 JSON 文件修改代码的复杂度。我的核心诉求是,需要以直观的方式让用户能够修改博客的各项配置,不要展现这些底层的配置文件代码和修改。”

Codex 的响应是:暂停开发,先做设计调研。它调研了 Figma 和 GitHub 上类似项目的界面设计,然后产出了一份 CONFIG_CENTER_DESIGN.md——配置中心信息架构和字段控件 Schema 设计方案。

核心设计思路:用 Schema 驱动的表单替代 JSON 编辑器

实现了一个通用的 SchemaConfigEditor.svelte 组件,支持:

  • 文本/文本域/数字/布尔/下拉/标签/数组等控件

  • 条件显示(如:选择某评论后端时才显示对应配置项)

  • 媒体选择器(图片/音频直接从 WingsBlog public 目录选择)

  • 排序数组(拖拽排序友链、音乐列表等)

  • 高级 JSON 模式(给开发者留的后门)

基于这个 Schema 系统,一口气覆盖了 profileannouncementlicenseplantumlcommentmusicwallpaperanalyticscover-imagegallerysponsoreffectsexpressive-code13 个配置——全部变成了可视化表单。

P5—P7 还完成了

  • Milkdown WYSIWYG 编辑器:安装 Milkdown 7.21.2,实现所见即所得编辑、源码切换、预览模式

  • Markdown 工具栏:标题/列表/引用/代码块/表格/链接/图片,带状态高亮和键盘操作

  • 表格尺寸选择器:6×6 网格 hover 选择,与 Typora 体验一致

  • 表单验证增强:URL/范围/必填/长度/正则,保存前逐字段验证

  • 性能优化:搜索 150ms 去抖、JSON 延迟序列化

  • 297 个 Vitest 单元测试(PostService 61 + ConfigService 65 + SettingsService 44 + I18nService 22 + MediaService 25 + 集成测试 + 前端测试)

P8 及后续完善

  • 壁纸/音乐本地资源导入(文件→public/assets 自动复制)

  • 音乐元数据解析(music-metadata 读取标题/歌手/内嵌封面)

  • 预览流程重做(一键启动 WingsBlog 开发服务器,iPad/iPhone 设备预设)

  • i18n 误写保护:检测到会清空 20+ 个已有翻译时拒绝保存

  • 缩放 Bug 修复(从 WebFrame zoom 改为 CSS transform 缩放)

  • UI 清理(隐藏默认菜单栏、侧边栏滚动条、页脚缩放控件)

  • Windows Release 打包(NSIS 安装程序 + 应用图标)

3.6 踩坑实录#

坑 1:npm 权限地狱

Windows 下的 npm install 在 Electron 项目中频繁爆 EPERM: Access denied。经过排查,是之前的 npm 缓存和 node_modules 残留导致。清理后重新安装解决。

坑 2:structuredClone 无法克隆 Svelte Proxy

保存配置时报 Failed to execute 'structuredClone' on 'Window': #<Object> could not be cloned.。原因是 Svelte 5 的 $state 创建的 Proxy 对象无法被 structuredClone 处理。Codex 编写了专用的 cloneConfigValue() 方法来安全地深拷贝配置值。

坑 3:预览停止按钮无效

点击停止预览,页面还在显示。排查后发现是 PreviewService.stop() 用了 taskkill 但没等待进程真正退出就返回了状态。修复方案:taskkill /t /f 后轮询直到 127.0.0.1:4321 不再可达。

坑 4:i18n 配置被意外清空

切换到英文界面后,中文翻译文件 zh_CN.ts 的所有翻译被清成了空字符串。通过从 WingsBlog 的 origin/master 分支恢复了原始中文翻译,并添加了破坏性写入守卫——如果一次保存会清空 20+ 个已有翻译且超过当前非空翻译的 50%,则拒绝写入。

坑 5:Git CRLF/LF 行尾问题

Windows 环境下,Git 频繁警告 CRLF 将被替换为 LF。不影响功能,但每次提交都有噪音。后续配置了 .gitattributes 缓解。


四、Codex 协作模式复盘#

4.1 子 Agent 体系#

Codex 最让我惊讶的特性是它会自主派出子 Agent 做勘察和审查。在 WingsBlogManager 开发中,至少派出了 8 个子 Agent:

子 Agent角色任务
Lorentzexplorer初次勘察 Electron/Svelte 编译风险
Pasteurworker添加媒体管理模块
Eulerexplorer分析配置写回风险
Gaussexplorer梳理配置编辑器与 diff 预览
Fermatexplorer勘察动态菜单编辑器实现
Laplaceexplorer评估 Cloudflare Pages 部署可行性
Lagrangeworker勘察 PIO 表单和多导出编辑器
Hamiltonworker评估 P3 各项的实现影响面

这些子 Agent 都是只读的——它们勘察代码、分析风险、给出建议,但不直接修改文件。这让每次修改都有充分的事实基础,大大降低了”改错了再回滚”的概率。

4.2 文档驱动的上下文管理#

在第一个会话中我要求 Codex 遵循的一条核心原则是:

“重要设计决策、当前进度、未解决问题和后续任务,需要沉淀到项目文档中。”

Codex 严格执行了这一点。项目最终有 6 个维护文档:

  • README.md — 项目介绍与快速开始

  • PROJECT_CONTEXT.md — 当前实现状态、风险与验证记录(最长,361 行)

  • ARCHITECTURE.md — 运行时架构与模块边界

  • DECISIONS.md — 关键技术决策

  • TODO.md — 已完成与后续工作的完整追踪

  • CONFIG_CENTER_DESIGN.md — 配置中心交互与 Schema 设计

这些文档让第二个会话(跨天开启)无缝衔接——Codex 读完文档后就能准确理解当前状态,不需要我重新解释。

4.3 每个阶段的验证闭环#

Codex 在每个阶段的结尾都执行了同样的验证命令:

Terminal window
npm run typecheck # TypeScript + Svelte 检查
npm run build # Electron/Vite 生产构建
npm test # Vitest 测试(最终 298 个用例)

PROJECT_CONTEXT.md 中记录了 30+ 次验证通过记录,每一次都有具体的命令输出证明。


五、效率提升的真实感受#

从”改配置”到”用工具”#

以前改博客头像的流程:

  1. 打开 profileConfig.ts
  2. 找到 avatar 字段
  3. 把新图片放到 public 目录
  4. 手动写路径字符串
  5. Git add → commit → push
  6. 等 Cloudflare 构建

现在的流程:

  1. 在 WingsBlogManager 中打开”个人资料”
  2. 点击头像旁边的媒体选择器,选择图片
  3. 点击”预览并保存”

从 6 步变成 2 步。 而且不用碰一行代码。

从”手写 frontmatter”到”WYSIWYG”#

以前写一篇博客文章:

  1. 手动创建 .md 文件
  2. 手写 YAML frontmatter(title、date、tags、category、description…)
  3. 用 VSCode 写 Markdown

现在:

  1. 点击”新建文章”
  2. 在表单中填写标题、标签(支持自动补全)
  3. 在 Milkdown 编辑器中所见即所得写作
  4. 点击保存 + Git 推送

最大的价值:降低了”维护门槛”#

WingsBlogManager 最核心的价值不是技术上的,而是让一个非技术人员也能管理自己的博客。配置不再是代码文件里的神秘 JSON,而是直观的表单和开关。这正是 Codex 帮我完成的”最后一公里”——从能跑,到能用。


六、一些反思#

Codex 擅长什么#

  • 理解设计文档并转化为实现:从 DESIGN.md 的 9 页文档到完整的 Electron 应用

  • 自主勘察和风险评估:子 Agent 体系在开始编码前先做功课

  • 状态管理的细粒度处理:分 section 的脏标记、i18n 破坏性写入守卫

  • 技术选型和架构决策:ts-morph、Milkdown、safeStorage,每次选型都有理有据

  • 持续的验证和文档同步:30+ 次验证记录 + 6 份维护文档

还需要注意什么#

  • ⚠️ Windows 特定问题:npm 权限、Electron 二进制下载、CRLF 行尾——这些都是 Codex 需要在真实 Windows 环境下一一解决的

  • ⚠️ Svelte 5 runes 的边界情况:Proxy 对象的 structuredClone 问题说明新框架的坑需要实际踩

  • ⚠️ 子进程管理:预览启动/停止、taskkill 等待——进程生命周期管理比想象的更复杂

  • ⚠️ 长会话需要 /compact:第一个会话(3430 行 JSONL)接近上下文上限时,会主动提示或自动压缩

给我自己的建议#

  1. 先写好 DESIGN.md:越详细的设计文档,Codex 的理解越准确
  2. 用否定句澄清偏好:“不需要 X”比”做 Y”更清晰
  3. 善用子 Agent:明确说”可以采用子 Agent 协作模式”,Codex 会并行勘察
  4. 要求文档同步:让 Codex 在每次行为变更后更新 PROJECT_CONTEXT.md,跨会话才不会丢失上下文
  5. 小步快跑:P0→P1→P2… 每个阶段独立验证,出问题也容易定位

七、结语#

8 天,71 条消息,298 个测试用例,一个从零到交付的 Electron 桌面应用。

Codex 不是魔法——它不会自动知道你要什么,也不会一次就把复杂的状态管理做对。但它是一个极有耐心、从不偷懒、做事有理有据的协作者。它会在动手前派子 Agent 勘察代码,会在发现风险时主动报告,会在每个阶段结束时自动跑 typecheck + build + test 来验证。它不会跳过文档,不会忽略边界情况,不会为了图快而降低质量。

如果你在犹豫要不要让 AI 帮你做开发,我的建议是:先写一份好的设计文档,然后给它一个机会。

这篇文章就是用这个管理器发布的,还不错吧!当然目前还有许多需要修复的小bug,需要经过不断的迭代才能达到理想的效果.

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

我与 Codex 的一周:从一份设计文档到一个桌面应用
https://blog.wingsapp.top/posts/codex-blogmanager/
作者
Wings
发布于
2026-07-14
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
Wings
You only get one shot, do not miss your chance to blow.
公告
🎉 Wings Blog 正式上线!欢迎来踩~
音乐
封面

音乐

暂未播放

0:000:00
暂无歌词
分类
标签
站点统计
文章
2
分类
2
标签
3
总字数
5,428
运行时长
0
最后活动
0 天前
站点信息
构建平台
Cloudflare Pages
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录