【免费下载链接】open-slide
A slide framework built for agents.
本指南以 open-slide 仓库中的 Agent Skill 文档 current-slide/SKILL.md 为核心,讲解当用户说出"这个页面"、"这张幻灯片"、"我正看的这页"等指代性(deictic)表述时,Agent 应如何通过 dev server 实时写出的node_modules/.open-slide/current.json文件来定位用户当前所处的幻灯片、页码乃至选中元素。读完本文,你将掌握该文件的完整字段语义、读取时机、新鲜度判断规则、失效场景与端到端实现原理(从前端 HMR 消息到 Vite 插件的原子写入),从而在 open-slide 的 Agent 协作流程中避免"改错文件"这一最常见的错误。
背景:Agent 协作中的"当前上下文"难题
open-slide 是一个为 Agent 构建的幻灯片框架(详见仓库根目录 README.md),开发者会直接对着 dev viewer 说"修一下这个页面"、"把这里放大一点"、"我正看的那张图换掉"——他们几乎不会说出slideId、页码或元素名。此时 Agent 面临一个信息缺口:用户指的"这里"到底对应哪个文件、哪一页、哪一行 JSX?
current-slideSkill 的答案非常直接:不要反问,先读文件。open-slide 的 dev server 在用户每一次导航(切换幻灯片、翻页)和每一次 inspector 选中(点击元素)时,都会把最新的位置信息写入node_modules/.open-slide/current.json。这个文件就是"用户现在在哪"的权威实时游标,是解开一切指代性表述的钥匙。
current.json 是什么:一条从浏览器到磁盘的数据链路
从源码可以确认这条链路的两端。写入端是 dev server 注册的 Vite 插件currentPlugin,位于 packages/core/src/vite/current-plugin.ts,它通过server.ws.on('open-slide:current', ...)监听浏览器端通过 HMR WebSocket 发来的消息,并把最新状态写入path.join(userCwd, 'node_modules', '.open-slide')目录下的current.json(current-plugin.ts 第 69-70 行)。该插件在 vite/config.ts 第 85 行 被装配进核心 Vite 插件链,slidesDir默认取'slides'(即用户项目根下存放幻灯片的目录)。
消息的发送端在浏览器渲染层:
- 页面级导航:幻灯片路由 packages/core/src/app/routes/slide.tsx 第 160-167 行 在
slideId / pageIndex / totalPages / slideTitle / view任一变化时,通过import.meta.hot.send('open-slide:current', {...})上报导航状态; - 元素级选中:同文件中的
SelectionReporter组件(slide.tsx 第 1092-1107 行)监听 inspector 的选中结果,把line / column / tagName / text(文本经空白压缩并截断到 120 字符)随{ selection }一并发送。
插件收到消息后做一层防御性校验(非法slideId直接丢弃、pageIndex被钳制到[0, totalPages-1]、selection的字段逐个做类型与范围检查),然后以"先写current.json.tmp再rename"的原子方式落盘,避免 Agent 读到半截文件(current-plugin.ts 第 132-139 行)。文件路径相对于用户项目根目录(即包含slides/与package.json的那个目录),而不是相对于 open-slide 核心包本身。
字段详解:current.json 里每一项的准确语义
一个典型的current.json内容如下(示例取自原 Skill 文档):
{ "slideId": "q2-roadmap", "pageIndex": 2, "pageNumber": 3, "totalPages": 8, "slideTitle": "Q2 Roadmap", "view": "slides", "pagePath": "slides/q2-roadmap/index.tsx", "selection": { "line": 42, "column": 6, "tagName": "h1", "text": "Q2 Roadmap" }, "updatedAt": "2026-05-09T14:32:11.123Z" }各字段语义如下:
| 字段 | 含义 | 使用要点 |
|---|---|---|
slideId | slides/下的文件夹名 | 直接作为/__slides/<id>/...系列 API 的参数或 URL 段使用;写入端会校验其必须匹配SLIDE_ID_RE = /^[a-z0-9_-]+$/i(见 slide-ops.ts 第 5 行),非法 id 会被丢弃 |
pageIndex | 0 起始的页码 | 对应index.tsx中export default [Cover, Body, ...]数组的下标(即index.tsx中的 page 数组位置) |
pageNumber | 1 起始的页码 | 用于向用户表达"第 3 页,共 8 页",也对应 URL 参数?p=N;源码中由pageIndex + 1计算而来(current-plugin.ts 第 117 行) |
pagePath | 幻灯片源文件相对路径 | 直接交给Read/Edit工具使用;由path.join(slidesDir, slideId, 'index.tsx')生成(current-plugin.ts 第 109 行) |
slideTitle | 幻灯片标题 | 来自slide.meta?.title ?? slideId(slide.tsx 第 164 行),即未显式声明meta.title时回退为文件夹名 |
view | "slides"(画布视图)或"assets"(资源管理器) | 为"assets"时,用户是在为该幻灯片浏览资源文件而非查看页面,Agent 应把焦点转向资源而非页面 JSX;浏览器端由 URL 参数?view=决定(slide.tsx 第 155 行) |
selection | 用户在 inspector 覆盖层中选中的 JSX 元素,未选中时为null | 见下方专项说明 |
updatedAt | 最近一次导航或选中变化的 ISO 时间戳 | 用于判断数据是否已过期(staleness) |
selection 子字段的精确语义
line(1 起始)与column(0 起始)指向pagePath内 JSX开标签的位置。这是权威句柄——Agent 必须对照源文件行而不是渲染后的 DOM 去匹配(写入端在 current-plugin.ts 第 59-60 行 把line钳制为不小于 1 的整数、column钳制为不小于 0 的整数);tagName是渲染后的 DOM 标签名,统一小写("h1"、"div"、"img"),并会被截断到 32 字符以内(current-plugin.ts 第 52-53 行);text是元素textContent的空白压缩、去首尾空白后截断到 ≤120 字符的文本片段,用作"确认找对了节点"的 sanity check;- 选中状态会在用户切换到不同幻灯片或页码时自动清空——写入端在检测到
slideId或pageIndex变化时会把selection重置为null(current-plugin.ts 第 111-113 行),因此"旧选中"永远不会跨页残留。
使用时机:何时必须读 current.json
应当使用的场景:
- 用户以指代性方式引用当前幻灯片/页面:"这个"、"这里"、"我正看的这页"、"我正在看的这张幻灯片"、"我在弄的那个";
- 用户引用某个具体元素:"这个标题"、"这张图"、"我刚才点的那个按钮"、"把这个收紧一点"、"改一下这个的颜色"——如果
selection非空,它指向的就是用户所指的元素; - 在反问"哪张幻灯片?"或"哪个元素?"之前,先读这个文件;
- 在依据
git log、最近编辑过的文件或最近创建的幻灯片文件夹去猜测之前,先读这个文件。
不应当使用的场景:
- 用户已显式说出幻灯片名(如"改一下
q2-roadmap")——直接用这个名字即可,无需查文件; apply-comments工作流已通过源码内的@slide-comment标记定位文件,它不需要这个 skill(相关流程见 apply-comments/SKILL.md);- 需要列出或发现幻灯片时——直接读
slides/目录即可。
核心纪律:每一轮指代性对话都必须重新读取
current.json是一个实时游标(live cursor),而不是关于对话的事实。用户会在你的两轮思考之间自由地切换幻灯片、页码和元素——包括在你做其他工作期间。因此 Skill 文档强调:在每一轮使用指代性引用的新回合开始时,都要重新读取该文件,即使:
- 你在同一段对话中已经读过它;
- 你刚刚编辑完它指向的幻灯片;
- 用户的新消息听起来像是承接上一轮("现在把它再调大一点"、"顺便把这个也修一下"、"继续")。
"继续编辑"恰恰是最容易踩坑的情况:用户很可能刚刚导航到了另一张幻灯片,或选中了另一个元素。若还信任上一次读取的值,就会静默地改错文件。正确做法是:重新读取后,把这次的slideId/pageIndex/selection与上次用过的值做比对,然后基于新值行动。经验法则:如果updatedAt比你上一轮看到的更"新",那就是用户已经移动位置的正常信号——无需追问,直接切到新的slideId/pageIndex/selection。
新鲜度判断:把 updatedAt 当缓存看待
updatedAt是用户最后一次导航的时间。Skill 文档给出的分级策略:
- 新鲜(约 5 分钟以内):直接信任它。打开
pagePath,开始干活; - 超过约 5 分钟:编辑前先与用户确认。dev server 可能已不在运行,用户也可能已切换了上下文;
- 数小时乃至数天前:忽略它,直接询问用户指的是哪张幻灯片。
文件缺失时的处理
以下两种情况会导致current.json不存在:
- dev server 从未在任一幻灯片上被打开过;
- dev server 从未运行过。
此时不要自行创建该文件,也不要凭空猜测。正确做法是询问用户指的是哪张幻灯片,或建议用户先在 dev server 中打开该幻灯片。
实战示例
示例一:页面级指代——"收紧这个页面的间距"
- 读取
node_modules/.open-slide/current.json; - 检查
updatedAt是否足够新; - 读取
pagePath(如slides/q2-roadmap/index.tsx); - 定位 default 导出数组中
pageIndex对应的那个页面组件; - 参考
slide-authoringskill 中的间距规则(见 slide-authoring/SKILL.md),就地编辑该页面。
如果current.json缺失或已过期,可以这样回应:"您想收紧哪张幻灯片、哪一页的间距?dev server 最近没有发布当前页信息。"
示例二:元素级指代——"把这个再放大一点"
- 读取
node_modules/.open-slide/current.json; - 若
selection非空,用户指的就是该元素。读取pagePath,跳到selection.line,在附近找到对应的 JSX 开标签,并用selection.text片段和tagName确认无误; - 编辑前先查阅
slide-authoring中的字号阶梯与布局规则; - 就地编辑该 JSX 节点。
如果selection为null,则回退到上面的页面级流程——并考虑询问"您指的是哪个元素?"(用户用了指代性表述,但还没有在 inspector 中选中具体元素)。
源码级深入:写入端如何保证数据可信
理解了读取契约后,再看写入端的实现(current-plugin.ts 全文仅 143 行),可以发现几处为"Agent 读取安全"服务的细节:
- 消息即最新状态:插件每次收到
open-slide:current消息时,都以cached为基底合并新值并整体覆盖写盘,天然保证"每次导航/选中都产生一次完整的最新快照"; - 无状态兜底:若收到的是仅含
selection的消息(如 inspector 点击而页面未变化),会沿用缓存中的slideId / pageIndex等字段,只更新选中与时间戳,避免状态回退; - 防御性校验:非法
slideId(不匹配SLIDE_ID_RE)直接 return;pageIndex会被Math.max(0, Math.min(totalPages - 1, rawIndex))钳制,杜绝越界值污染文件; - 原子写盘:先写
current.json.tmp再rename为current.json,保证 Agent 在任何时刻读取到的都是完整 JSON,而非写入中途的半截内容;写盘失败被 catch 掉(best-effort),不会因此崩溃 dev server。
这些实现细节意味着:只要 dev server 在运行且用户与界面发生过交互,current.json就始终是一个结构完整、经过校验、语义一致的位置快照——这正是 Agent 敢直接依赖它的前提。
与其余 Skill 的分工协作
在 open-slide 的 Agent 技能体系中,current-slide的职责被刻意收窄为"解析指代性引用",具体如何编辑则由其他 Skill 承接:
current-slide负责把"这个页面/这个元素"解析为具体的slideId + pageIndex + selection;- slide-authoring/SKILL.md 是页面编辑的"技术参考",规定了
slides/<id>/index.tsx的文件契约(default 导出为按页顺序排列的零参数组件数组、1920×1080 画布、类型阶梯、布局与调色板规则等),current-slide的示例流程中"编辑前查阅间距/字号规则"指向的就是它; - apply-comments/SKILL.md 通过
@slide-comment标记自带定位能力,因此明确声明"不需要 current-slide"; - create-slide/SKILL.md 负责"起草新幻灯片"的完整工作流,同样会把具体的"怎么写"委托给
slide-authoring。
这套分工意味着:Agent 在收到指代性编辑指令时,应先读current.json定位,再进入slide-authoring的规则体系执行编辑,两者缺一不可。掌握current.json的读取纪律,是 open-slide 上所有 Agent 安全编辑的前提——它把"用户在哪儿"从模糊的对话推断,变成了一个可读、可校验、可失效判定的文件事实。
【免费下载链接】open-slide
A slide framework built for agents.
相关推荐
Pearcleaner:你的终极macOS清理管家,告别应用残留轻松释放磁盘空间
Pearcleaner:你的终极macOS清理管家,告别应用残留轻松释放磁盘空间 你是否曾经卸载过macOS应用,却发现系统里还残留着各种缓存、偏好设置和支持文
Pandoc Beamer 幻灯片实战:用 --slide-level 与 columns 分栏精准控制帧结构
Pandoc Beamer 幻灯片实战:用 slide level 与 columns 分栏精准控制帧结构 导读 本文以 pandoc 官方测试用例 test/
文档开发工具CLIopen-slide 项目模板完全指南:从零开始创作 AI Agent 驱动的 React 幻灯片
open slide 项目模板完全指南:从零开始创作 AI Agent 驱动的 React 幻灯片 open slide 是一个面向 Agent(如 Claud
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考