新站首版记录

摘要 · Agent Fox

yiming-next 的工程全景:从 WordPress 迁出、以文件驱动的个人站点。Astro SSR + 单一 entries 内容仓、Agent Fox AI 助手(含主人长期记忆)、全局音乐播放器、登录与隐私遮罩、评论与站内搜索。

yiming-next 是这个站点从 WordPress 迁出后的新工程。技术栈是 Astro 5 + Node.js SSR standalone,内容全部以文件形式存储,没有数据库。内容仓如今是一个独立的 git 仓库,与应用代码分离:应用通过 CONTENT_ROOT 读取它,本地检出里 content 只是一个指向它的符号链接,src/lib/paths.tscontentPath() 是访问内容的唯一入口。

这篇是工程全景的活文档,会随站点演进更新。下面写的是当前(2026-06)的真实状态,和首版相比改动不少。

内容层

文章和页面已经合一:所有条目都是 content/entries/*.md,不再分 posts/pages/。每条 frontmatter 里有一个数字 id 作为唯一真相,规范 URL 由它派生为 /?p=${id};其余字段含标题、摘要、可见性(public / private / password_protected)、分类、标签、封面等。

  • 音乐content/music/playlist.json):全局播放器的曲目元数据。正文里的 [music_player] 短代码现在自描述、直接渲染,不再维护单独的注册表。
  • 分类 / 标签content/taxonomy/):支撑分类和标签归档。
  • 评论content/interaction/comments/):每篇文章一个 JSON 文件,含嵌套回复树。
  • 主人长期记忆content/interaction/agent-memory/):每条记忆一个 Markdown 文件,仅 Agent Fox 在主人模式下使用(见下文)。
  • 图片:不再使用独立的画廊 JSON,统一为正文内的纯 Markdown 图片;连续多图自动成组并套用通用 lightbox。

内容加载走 src/lib/content/load.ts,按可见性分公开和认证两条路径。Markdown 渲染管线(src/lib/content/render.ts)依次处理:WordPress 残留 HTML 区块转原生 Markdown、GFM 渲染、目录生成、HTML 清洗、LaTeX 数学公式、Mermaid 图、Shiki 代码高亮(nord 主题)、隐私遮罩展开、旧信纸体日记卡片。

页面路由

URL 方案保留了 WordPress 的查询参数习惯,但规范 URL 现在统一收敛为 /?p=N(不再用 /?page_id=)。其余入口(/?cat=/?tag=/?m=/?s=)都在 index.astro 分发。同时也有语义路径:

  • /posts/ 文章列表,/posts/[slug]/ 文章单页
  • /archive//archive/[year]/ 年份归档
  • /categories/[slug]//tags/[slug]/ 分类/标签归档
  • /search/ 站内搜索,/about/ 关于页面
  • /feed.xml/sitemap.xml/search-index.json 公开数据接口

[...legacy].astro 作为兜底路由处理未知路径。早期那套基于 url-inventory.yaml 迁移清单的重定向已退役,改由 src/lib/url-contract/ 的解析器收敛到规范 /?p=N

全局运行时

前端运行时(src/components/runtime/SiteRuntime.astro + site-runtime.ts)如今精简为挂载 Agent Fox 与一组常驻交互:

  • 全局音乐播放器Audio 元素在页面导航中保持不中断,状态通过 localStorage 持久化,支持进度、音量、播放模式控制。
  • 阅读进度条 + 文章目录:目录自动从标题生成、可折叠,滚动时高亮当前章节。
  • 主题切换:亮色/暗色模式由 CSS 变量驱动;强调色统一为 Rosé Pine 的 pine 色系。

Agent Fox AI 助手

Agent Fox(src/components/agent/AgentFox.astro)通过 /api/agent/stream 提供 SSE 流式 AI 对话。关键设计点:

  • 双模式:访客只检索公开内容;登录主人(密码 + TOTP 二次验证)获得完整站点上下文与「主人」人格。
  • 工具集(13 个)keyword_searchsemantic_searchhybrid_searchget_post_chunkcomment_querylist_archiveslist_taxonomy_termsanalyze_imagesite_insightrecommend_contentmanage_post(新建/编辑文章,仅主人)、manage_memory(长期记忆,仅主人)、agent_self_knowledge
  • 持久化陪伴:会话 id 与对话记录存 localStorage,跨刷新续聊;当前页面、浏览/点击轨迹与时间戳随消息尾部注入(稳定前缀不变,对 KV 缓存友好)。
  • 主人长期记忆:仿 Claude Code 的「索引 + 渐进式披露」——平时只把每条记忆的简短钩子注入对话,完整正文按需展开;每条记忆是内容仓里的独立文件,owner-only,不进向量、访客不可见。它让小狐能跨会话记住主人的长期约定(如日常打卡提醒)并主动跟进。
  • 两种停靠态:悬浮弹窗(Cmd/Ctrl+K 唤起)与侧栏「页边批注」之间可互切,共享同一份对话。
  • 数据回调/api/agent/data/[kind]/api/agent/data/[...path] 提供文章、批量内容、分类、评论、记忆等 JSON 接口;私密数据需同时满足服务端 api-key 与已登录主人两个条件。
  • 语义检索:走独立的向量服务(正文、摘要、评论分别建向量),站点侧负责生成与同步。

评论系统

评论提交端点为 /api/comments,提交时需通过算术验证码(HMAC 签名)。评论存储在 content/interaction/comments/posts/ 下,支持嵌套回复和树形渲染。旧的 WordPress REST 评论路由已退役。

登录与隐私

  • 登录:密码 + TOTP 动态码二次验证(src/lib/auth/);登录态用签名 cookie 维持,是判定「主人」身份的唯一可信来源——在服务端校验,浏览器无法伪造。
  • 可见性public / private / password_protected;私密内容既不进向量,也不对访客和未登录者渲染。
  • 遮罩:行内与区块统一的 <span class="ink-mask" role="img" aria-label="此处有隐藏内容" title="登录后可见">█</span> 机制——访客看到墨条或「🔒 此处隐藏 N 字」占位,登录主人看到原文;公开面只暴露长度、不泄露内容。隐私过滤(src/lib/privacy/policy.ts)对公开渲染与 AI 数据回调一致生效。

其他模块

  • OSS 图片代理/api/media/oss-image 代理阿里云 OSS 图片,设置防盗链 referer 并附加长期缓存头;体积较大的静态资源都走 OSS,不塞进仓库。
  • 健康检查/api/health,供外部监控和部署验证。
  • 旧站兼容收敛:仍保留少量 /wp-json/agent-fox/*/api/wp-ajax 兼容动作,其余 WordPress 路由(评论、插件资源等)一律返回 410。整体方向是持续摆脱 WordPress 的迁移间接层。

部署

npm run build(typecheck + astro build)产出 dist/,由 systemd 服务 fanyiming.life 跑 Node standalone 入口;内容仓与应用仓彼此独立,文章改动只要在内容仓提交即可生效。

有话这里说 ↓