@cyber-dash-tech/revela 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +54 -9
  2. package/README.zh-CN.md +54 -9
  3. package/designs/monet/DESIGN.md +9 -9
  4. package/designs/starter/DESIGN.md +8 -8
  5. package/designs/summit/DESIGN.md +9 -9
  6. package/lib/commands/help.ts +2 -0
  7. package/lib/commands/inspect.ts +23 -0
  8. package/lib/commands/pdf.ts +33 -5
  9. package/lib/commands/pptx.ts +14 -9
  10. package/lib/commands/refine.ts +26 -0
  11. package/lib/commands/review.ts +8 -2
  12. package/lib/deck-html/contract.ts +252 -0
  13. package/lib/decks-state.ts +574 -31
  14. package/lib/document-materials/extract.ts +20 -0
  15. package/lib/edit/resolve-deck.ts +13 -2
  16. package/lib/inspect/open.ts +63 -0
  17. package/lib/inspect/prompt.ts +32 -0
  18. package/lib/inspect/request.ts +70 -0
  19. package/lib/inspect/requests.ts +86 -0
  20. package/lib/inspect/server.ts +1063 -0
  21. package/lib/inspect/slide-index.ts +12 -0
  22. package/lib/inspection-context/compile.ts +346 -0
  23. package/lib/inspection-context/match.ts +169 -0
  24. package/lib/inspection-context/project.ts +263 -0
  25. package/lib/inspection-context/result.ts +160 -0
  26. package/lib/qa/export-gate.ts +8 -1
  27. package/lib/refine/open.ts +70 -0
  28. package/lib/refine/server.ts +1581 -0
  29. package/lib/workspace-state/actions.ts +71 -0
  30. package/lib/workspace-state/compat.ts +10 -0
  31. package/lib/workspace-state/evidence-status.ts +267 -0
  32. package/lib/workspace-state/graph.ts +426 -0
  33. package/lib/workspace-state/render-targets.ts +182 -0
  34. package/lib/workspace-state/rendered-artifacts.ts +43 -0
  35. package/lib/workspace-state/repository.ts +43 -0
  36. package/lib/workspace-state/research-attachments.ts +130 -0
  37. package/lib/workspace-state/review-snapshots.ts +127 -0
  38. package/lib/workspace-state/types.ts +119 -0
  39. package/package.json +1 -1
  40. package/plugin.ts +48 -1
  41. package/skill/SKILL.md +10 -5
  42. package/tools/decks.ts +61 -2
  43. package/tools/inspection-context.ts +22 -0
  44. package/tools/inspection-result.ts +63 -0
  45. package/tools/pdf.ts +9 -1
  46. package/tools/pptx.ts +10 -0
  47. package/tools/research-save.ts +15 -0
  48. package/tools/workspace-scan.ts +15 -0
package/README.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  **English** | [中文](README.zh-CN.md)
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-178%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
5
+ [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-302%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="800" />
9
9
  </p>
10
10
 
11
- Revela is an [OpenCode](https://opencode.ai) plugin that turns your current agent into an HTML slide deck generator.
12
- Enable it for the current session, assign a presentation task, and the agent can research, structure, write, QA, and export a deck.
11
+ Revela is an [OpenCode](https://opencode.ai) plugin for building trusted narrative artifacts from workspace sources, research, evidence, and user intent.
12
+ Its first render target is still the HTML slide deck: enable Revela for the current session, assign a presentation task, and the agent can research, structure, write, QA, inspect, refine, and export a deck.
13
13
 
14
14
  **[Live Demo — The AI Power Shift](https://cyber-dash-tech.github.io/revela/assets/html/ai-power-shift.html)**
15
15
 
@@ -20,8 +20,10 @@ Enable it for the current session, assign a presentation task, and the agent can
20
20
  - injects a presentation-specific system prompt into your current agent with `/revela enable`
21
21
  - builds that prompt from 3 layers: core skill, active domain, active design
22
22
  - supports workspace document discovery, transparent text extraction for `.pdf`, `.docx`, `.pptx`, and `.xlsx`, and cached embedded-material extraction for those formats
23
- - keeps track of deck context, slide structure, sources, and readiness across the current workspace
23
+ - keeps `DECKS.json` as the current workspace state engine for sources, research actions, findings, claims, evidence, narrative intent, render targets, and readiness
24
24
  - checks for missing context, weak evidence, and incomplete structure before writing `decks/*.html`
25
+ - records review snapshots so stale readiness cannot silently authorize new deck HTML after important state changes
26
+ - treats HTML decks, PDF, and PPTX as render targets from shared workspace state rather than isolated output files
25
27
  - runs fast design compliance checks whenever the agent writes, patches, or edits `decks/*.html`
26
28
  - opens a visual comment editor for existing decks so users can Ctrl/Cmd-click elements and send precise edit requests back to OpenCode
27
29
  - exports finished decks to PDF and editable PPTX
@@ -140,7 +142,9 @@ Disable presentation mode when done:
140
142
  /revela init prepare the workspace for a deck project
141
143
  /revela review check whether context, structure, and evidence are ready
142
144
  /revela remember <text> save an explicit user/workflow preference
145
+ /revela refine open unified Edit/Inspect refinement workspace
143
146
  /revela edit open visual editor for the only deck in decks/
147
+ /revela inspect open Evidence Inspector for Cmd/Ctrl-click review
144
148
 
145
149
  /revela designs list installed designs
146
150
  /revela designs <name> activate a design
@@ -159,7 +163,7 @@ Disable presentation mode when done:
159
163
  /revela pptx <file> export an HTML deck to editable PPTX in the same directory
160
164
  ```
161
165
 
162
- Most `/revela` commands run locally with zero LLM cost. `/revela init`, `/revela review`, `/revela remember`, `/revela designs-new`, and `/revela designs-edit` start AI-assisted workflows because they need to read or update project files. `/revela edit` opens a local visual editor and then sends user comments back into the current OpenCode session when the user submits them.
166
+ Most `/revela` commands run locally with zero LLM cost. `/revela init`, `/revela review`, `/revela remember`, `/revela designs-new`, and `/revela designs-edit` start AI-assisted workflows because they need to read or update project files. `/revela refine` opens a local browser workspace with Edit and Inspect tabs that share the same Cmd/Ctrl-click element references. Edit sends targeted comments back into the current OpenCode session; Inspect renders deterministic Source/Purpose preprocessing first before lazy LLM-generated cards arrive, has no chat box, and does not edit the deck.
163
167
 
164
168
  ---
165
169
 
@@ -176,6 +180,22 @@ That prompt is built from 3 layers:
176
180
  Persistent preferences live in `~/.config/revela/config.json`.
177
181
  The enabled or disabled state is session-level only.
178
182
 
183
+ ### Workspace State
184
+
185
+ `DECKS.json` is Revela's workspace state engine and compatibility file. It is still stored at the workspace root and remains readable as the current deck project state, but internally Revela now treats it as a lightweight persistence layer for more than a deck checklist.
186
+
187
+ The state records:
188
+
189
+ - workspace source materials and reusable extraction cache paths
190
+ - research plans, saved findings, and compact action provenance
191
+ - narrative intent, objections, risks, slide specs, claim candidates, and slide-level evidence trace
192
+ - render targets such as the active HTML deck plus derived PDF and PPTX artifacts
193
+ - review snapshots with input hashes so old readiness results become stale after meaningful state changes
194
+
195
+ 0.11 keeps backward compatibility with existing root `DECKS.json` workspaces. Running `/revela init` or `/revela review` on an older project can normalize and refresh the new projection fields without requiring a manual migration, moving files, or replacing `DECKS.json` with a database.
196
+
197
+ Decks remain the primary authored artifact, but they are now treated as render targets from the same workspace state that can later support briefs, appendix material, Evidence Inspector views, Q&A, and interactive reading layers without duplicating source/evidence logic.
198
+
179
199
  ---
180
200
 
181
201
  ## Recommended Workflow
@@ -188,12 +208,13 @@ Use Revela as a guided deck-production mode:
188
208
  4. Give the agent a clear deck task: audience, goal, language, number of slides, source requirements, and output path.
189
209
  5. Use `/revela review` before writing if the deck needs research, citations, or a confirmed slide plan.
190
210
  6. Let the agent write the HTML deck under `decks/`.
191
- 7. Use `/revela edit` for visual comments and targeted revisions.
192
- 8. Export with `/revela pdf <file>` or `/revela pptx <file>`.
211
+ 7. Use `/revela refine` for visual comments, targeted revisions, and optional Source/Purpose inspection of selected deck elements.
212
+ 8. Use `/revela edit` or `/revela inspect` directly only if you need the older single-purpose shells.
213
+ 9. Export with `/revela pdf <file>` or `/revela pptx <file>`.
193
214
 
194
215
  `/revela review` checks for practical readiness problems: unclear audience, missing source material, unfinished research, unsupported claims, weak source trace, incomplete slide structure, missing design/layout information, or lightweight narrative issues such as weak so-what, missing risk/assumption handling, and abrupt transitions. It does not write the final deck.
195
216
 
196
- If Revela blocks a deck write, ask the agent to run `/revela review`, resolve the reported gaps, and try again. This protects the deck file from being overwritten before the plan, evidence, and structure are ready.
217
+ If Revela blocks a deck write, ask the agent to run `/revela review`, resolve the reported gaps, and try again. This protects the deck file from being overwritten before the plan, evidence, and structure are ready. In 0.11, review results are also saved as input-hashed snapshots; if sources, slide specs, evidence, narrative state, or the active render target changes afterward, the old review can no longer silently authorize a write.
197
218
 
198
219
  To remember long-term preferences, use:
199
220
 
@@ -558,6 +579,14 @@ A custom domain is a folder containing `INDUSTRY.md`.
558
579
 
559
580
  ## Visual Editing
560
581
 
582
+ Use the unified refinement workspace for normal post-write review and revision:
583
+
584
+ ```text
585
+ /revela refine
586
+ ```
587
+
588
+ `/revela refine` opens the only HTML deck in `decks/` with two tabs. Use `Ctrl`/`Cmd` + click once to reference deck elements, then choose Edit for fast natural-language change comments or Inspect for read-only Source and Purpose review. Inspect does not mutate the deck; Edit remains the mutation path.
589
+
561
590
  Open the visual editor for the only HTML deck in `decks/`:
562
591
 
563
592
  ```text
@@ -566,7 +595,7 @@ Open the visual editor for the only HTML deck in `decks/`:
566
595
 
567
596
  `/revela edit` does not accept a target in Revela 0.8. If `decks/` contains exactly one `.html` file, Revela opens it. If `decks/` contains zero or multiple `.html` files, Revela asks you to generate a deck first or move extra decks to separate workspaces.
568
597
 
569
- The editor opens in your browser. Use `Ctrl`/`Cmd` + click to reference deck elements, write a natural-language comment, then send it back to OpenCode. Revela sends a structured edit prompt that includes the deck file, slide context, selected element metadata, and your comment.
598
+ The older edit-only shell opens in your browser. Use `Ctrl`/`Cmd` + click to reference deck elements, write a natural-language comment, then send it back to OpenCode. Revela sends a structured edit prompt that includes the deck file, slide context, selected element metadata, and your comment.
570
599
 
571
600
  LLM tool equivalent: `revela-edit` with no target. This lets the agent open the same editor when you say things like “I want to edit the deck”.
572
601
 
@@ -574,6 +603,22 @@ For existing decks, `/revela edit` prepares whatever minimal project context is
574
603
 
575
604
  ---
576
605
 
606
+ ## Evidence Inspector
607
+
608
+ Open the Evidence Inspector for the only HTML deck in `decks/`, or use the Inspect tab in `/revela refine`:
609
+
610
+ ```text
611
+ /revela inspect
612
+ ```
613
+
614
+ The inspector opens in your browser with the deck on the left and fixed cards on the right: Source and Purpose. Use `Ctrl`/`Cmd` + click to reference deck elements exactly like `/revela edit`, then click `Inspect Selection`. Selection is locked while the request is being processed.
615
+
616
+ The inspector is not chat and has no freeform prompt. It does not mutate `DECKS.json` or the deck HTML. It uses recorded slide specs, narrative state, and slide-level evidence trace as grounded context. Deterministic preprocessing appears immediately; lazy LLM judgment then refines the Source and Purpose cards without inventing edits.
617
+
618
+ Inspection and refinement use the active HTML deck render target recorded in workspace state. The deck HTML must satisfy Revela's slide identity contract: every `<section class="slide">` in the active artifact needs a positive 1-based `data-slide-index` matching the current slide specs. Invalid active artifacts are refused or reported before inspect/refine/export workflows trust them.
619
+
620
+ ---
621
+
577
622
  ## Export
578
623
 
579
624
  PDF export:
package/README.zh-CN.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  [English](README.md) | **中文**
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-178%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
5
+ [![npm version](https://img.shields.io/npm/v/@cyber-dash-tech/revela)](https://www.npmjs.com/package/@cyber-dash-tech/revela) [![license](https://img.shields.io/npm/l/@cyber-dash-tech/revela)](LICENSE) [![tests](https://img.shields.io/badge/tests-302%20passing-brightgreen)](tests/) [![OpenCode plugin](https://img.shields.io/badge/OpenCode-plugin-blue)](https://opencode.ai) [![Bun](https://img.shields.io/badge/Bun-%E2%89%A51.0-orange)](https://bun.sh)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="800" />
9
9
  </p>
10
10
 
11
- Revela 是一个 [OpenCode](https://opencode.ai) 插件,可以把你当前使用的 agent 变成 HTML 幻灯片生成器。
12
- 在当前会话中启用之后,agent 可以完成调研、结构设计、HTML 写作、QA 和导出。
11
+ Revela 是一个 [OpenCode](https://opencode.ai) 插件,用来把工作区来源材料、调研、证据和用户意图转成可信的叙事型沟通 artifact。
12
+ 它的第一个 render target 仍然是 HTML slide deck:在当前会话中启用之后,agent 可以完成调研、结构设计、HTML 写作、QA、检查、refine 和导出。
13
13
 
14
14
  **[在线演示 — AI 权力转移](https://cyber-dash-tech.github.io/revela/assets/html/ai-power-shift.html)**
15
15
 
@@ -20,8 +20,10 @@ Revela 是一个 [OpenCode](https://opencode.ai) 插件,可以把你当前使
20
20
  - 通过 `/revela enable` 向当前 agent 注入演示文稿专用 system prompt
21
21
  - prompt 由 3 层组成:核心 skill、当前 domain、当前 design
22
22
  - 支持工作区文档扫描,以及 `.pdf`、`.docx`、`.pptx`、`.xlsx` 的透明文本提取和嵌入素材缓存提取
23
- - 在当前工作区持续跟踪 deck 背景、页面结构、来源材料和 readiness
23
+ - `DECKS.json` 作为当前 workspace state engine,持续记录来源材料、调研动作、findings、claims、证据、叙事意图、render targets 和 readiness
24
24
  - 写入 `decks/*.html` 前检查是否缺上下文、证据或结构
25
+ - 记录 review snapshots,避免重要状态变化后旧的 ready 结果继续默默授权写入 deck HTML
26
+ - 把 HTML deck、PDF 和 PPTX 视为来自同一 workspace state 的 render targets,而不是互相孤立的输出文件
25
27
  - agent 每次写入、patch 或 edit `decks/*.html` 时自动执行快速 design compliance 检查
26
28
  - 为已有 deck 打开可视化评论编辑器,用户可以 Ctrl/Cmd + 点击元素,并把精确修改意见发回 OpenCode
27
29
  - 支持导出成 PDF 和可编辑 PPTX
@@ -139,7 +141,9 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
139
141
  /revela init 为当前 deck 项目准备工作区
140
142
  /revela review 检查上下文、结构和证据是否 ready
141
143
  /revela remember <text> 保存明确的用户/工作流偏好
144
+ /revela refine 打开统一的 Edit/Inspect refinement workspace
142
145
  /revela edit 打开 decks/ 下唯一 deck 的可视化编辑器
146
+ /revela inspect 打开 Cmd/Ctrl-click 式 Evidence Inspector
143
147
 
144
148
  /revela designs 列出已安装 design
145
149
  /revela designs <name> 激活某个 design
@@ -158,7 +162,7 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
158
162
  /revela pptx <file> 将 HTML deck 导出为同目录可编辑 PPTX
159
163
  ```
160
164
 
161
- 大多数 `/revela` 命令都在本地执行,不消耗 LLM token。`/revela init`、`/revela review`、`/revela remember`、`/revela designs-new` 和 `/revela designs-edit` 会启动 AI 辅助流程,因为它们需要读取或更新项目状态。`/revela edit` 会打开本地可视化编辑器,并在用户提交评论后把修改请求发回当前 OpenCode 会话。
165
+ 大多数 `/revela` 命令都在本地执行,不消耗 LLM token。`/revela init`、`/revela review`、`/revela remember`、`/revela designs-new` 和 `/revela designs-edit` 会启动 AI 辅助流程,因为它们需要读取或更新项目状态。`/revela refine` 会打开一个本地浏览器 workspace,里面有 Edit 和 Inspect 两个 tab,并共享同一套 Cmd/Ctrl-click 元素引用。Edit 会把精准修改评论发回当前 OpenCode 会话;Inspect 会先渲染确定性 Source/Purpose 预处理结果,再 lazy 显示 LLM 生成的卡片。它没有聊天框,也不会修改 deck。
162
166
 
163
167
  ---
164
168
 
@@ -175,6 +179,22 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
175
179
  持久化配置保存在 `~/.config/revela/config.json`。
176
180
  是否启用 Revela 则只在当前会话生效。
177
181
 
182
+ ### Workspace State
183
+
184
+ `DECKS.json` 是 Revela 当前的 workspace state engine,也是兼容旧工作流的状态文件。它仍然保存在工作区根目录,也仍然可以理解为当前 deck 项目的状态入口,但 Revela 内部已经不再把它当成单纯的 deck checklist。
185
+
186
+ 状态中会记录:
187
+
188
+ - 工作区来源材料和可复用的 extraction cache 路径
189
+ - 调研计划、已保存 findings,以及精简的 action provenance
190
+ - narrative intent、objections、risks、slide specs、claim candidates 和 slide-level evidence trace
191
+ - active HTML deck 以及派生 PDF、PPTX 等 render targets
192
+ - 带 input hash 的 review snapshots,使重要状态变化后旧的 readiness 自动变 stale
193
+
194
+ 0.11 继续兼容已有的根目录 `DECKS.json` 工作区。对旧项目运行 `/revela init` 或 `/revela review` 时,可以安全 normalize 并刷新新的 projection 字段;用户不需要手动迁移、不需要移动文件,也不需要把 `DECKS.json` 换成数据库。
195
+
196
+ Deck 仍然是主要 authored artifact,但现在它是从同一份 workspace state 渲染出来的目标之一。后续 briefs、appendix material、Evidence Inspector views、Q&A 和 interactive reading layers 都可以复用同一套来源/证据逻辑,而不是各自生成孤立内容。
197
+
178
198
  ---
179
199
 
180
200
  ## 推荐使用流程
@@ -187,12 +207,13 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
187
207
  4. 给 agent 一个清楚的 deck 任务:受众、目标、语言、页数、来源要求和输出路径。
188
208
  5. 如果 deck 需要调研、引用或已确认的 slide plan,写作前先运行 `/revela review`。
189
209
  6. 让 agent 把 HTML deck 写到 `decks/` 下。
190
- 7. 用 `/revela edit` 做可视化评论和精准修改。
191
- 8. `/revela pdf <file>` 或 `/revela pptx <file>` 导出。
210
+ 7. 用 `/revela refine` 对选中 deck 元素做可视化评论、精准修改,以及可选的 Source/Purpose 检查。
211
+ 8. 只有在需要旧的单一功能 shell 时,才单独使用 `/revela edit` 或 `/revela inspect`。
212
+ 9. 用 `/revela pdf <file>` 或 `/revela pptx <file>` 导出。
192
213
 
193
214
  `/revela review` 检查的是实际生产问题:受众是否清楚、是否缺来源材料、调研是否完成、关键 claim 是否有证据、source trace 是否太弱、页面结构是否完整、design/layout 信息是否齐全,以及轻量叙事问题,例如 so-what 不清晰、缺少风险/假设处理或转场突兀。它不会写最终 deck。
194
215
 
195
- 如果 Revela 阻止写入 deck,直接让 agent 运行 `/revela review`,根据报告补齐缺口后再写。这样可以避免在计划、证据或结构还不完整时覆盖真实 deck 文件。
216
+ 如果 Revela 阻止写入 deck,直接让 agent 运行 `/revela review`,根据报告补齐缺口后再写。这样可以避免在计划、证据或结构还不完整时覆盖真实 deck 文件。0.11 还会把 review 结果保存为带 input hash 的 snapshot;如果之后来源材料、slide specs、证据、叙事状态或 active render target 发生变化,旧 review 不能继续默默授权写入。
196
217
 
197
218
  记住长期偏好请使用:
198
219
 
@@ -523,6 +544,14 @@ Prompt 注入规则:
523
544
 
524
545
  ## 可视化编辑
525
546
 
547
+ 正常的写后 review 和修改建议使用统一 refinement workspace:
548
+
549
+ ```text
550
+ /revela refine
551
+ ```
552
+
553
+ `/revela refine` 会打开 `decks/` 下唯一的 HTML deck,并提供两个 tab。使用 `Ctrl`/`Cmd` + click 先引用 deck 元素,然后在 Edit 里快速写自然语言修改评论,或在 Inspect 里做只读 Source 和 Purpose 检查。Inspect 不会修改 deck;真正的 mutation 仍然只走 Edit。
554
+
526
555
  打开 `decks/` 下唯一 HTML deck 的可视化编辑器:
527
556
 
528
557
  ```text
@@ -531,7 +560,7 @@ Prompt 注入规则:
531
560
 
532
561
  Revela 0.8 中 `/revela edit` 不接受 target。如果 `decks/` 下正好有一个 `.html` 文件,Revela 会打开它。如果 `decks/` 下没有 HTML 或有多个 HTML,Revela 会提示先生成 deck,或把多余 deck 移到独立 workspace。
533
562
 
534
- 编辑器会在浏览器中打开。使用 `Ctrl`/`Cmd` + 点击 deck 元素来引用它们,写一段自然语言评论,然后发送回 OpenCode。Revela 会把 deck 文件、slide 上下文、选中元素 metadata 和你的评论整理成结构化 edit prompt。
563
+ 旧的 edit-only shell 会在浏览器中打开。使用 `Ctrl`/`Cmd` + 点击 deck 元素来引用它们,写一段自然语言评论,然后发送回 OpenCode。Revela 会把 deck 文件、slide 上下文、选中元素 metadata 和你的评论整理成结构化 edit prompt。
535
564
 
536
565
  对应的 LLM tool:`revela-edit`,不需要 target。因此当你说“我要编辑这个 deck”时,agent 也可以主动打开同一个编辑器。
537
566
 
@@ -539,6 +568,22 @@ Revela 0.8 中 `/revela edit` 不接受 target。如果 `decks/` 下正好有一
539
568
 
540
569
  ---
541
570
 
571
+ ## Evidence Inspector
572
+
573
+ 打开 `decks/` 下唯一 HTML deck 的 Evidence Inspector,或直接使用 `/revela refine` 里的 Inspect tab:
574
+
575
+ ```text
576
+ /revela inspect
577
+ ```
578
+
579
+ Inspector 会在浏览器中打开,左侧是 deck,右侧是固定卡片:Source 和 Purpose。使用 `Ctrl`/`Cmd` + click 像 `/revela edit` 一样引用 deck 元素,然后点击 `Inspect Selection`。请求处理期间,deck 选择会被锁定。
580
+
581
+ Inspector 不是聊天,也没有自由输入框。它不会修改 `DECKS.json` 或 deck HTML。它使用已记录的 slide spec、narrative state 和 slide-level evidence trace 作为 grounded context。确定性预处理会立即显示;LLM judgment 随后 lazy 更新 Source 和 Purpose 卡片,不会强行生成编辑动作。
582
+
583
+ Inspect 和 refine 会使用 workspace state 中记录的 active HTML deck render target。Deck HTML 必须满足 Revela 的 slide identity contract:active artifact 中每个 `<section class="slide">` 都需要有正数、1-based 的 `data-slide-index`,并且要匹配当前 slide specs。无效的 active artifact 会在 inspect/refine/export 工作流信任它之前被拒绝或报告。
584
+
585
+ ---
586
+
542
587
  ## 导出
543
588
 
544
589
  PDF 导出:
@@ -193,10 +193,10 @@ Every generated presentation must use this exact HTML skeleton:
193
193
  <style>/* all CSS here */</style>
194
194
  </head>
195
195
  <body>
196
- <section class="slide cover-slide" slide-qa="false" data-index="0">
196
+ <section class="slide cover-slide" slide-qa="false" data-slide-index="1">
197
197
  <div class="slide-canvas"> ... </div>
198
198
  </section>
199
- <section class="slide" slide-qa="true" data-index="1">
199
+ <section class="slide" slide-qa="true" data-slide-index="2">
200
200
  <div class="slide-canvas"> ... </div>
201
201
  </section>
202
202
  <script>/* all JS here */</script>
@@ -507,7 +507,7 @@ These rules are mandatory for Monet.
507
507
 
508
508
  ### Layout Types
509
509
 
510
- Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. Use the QA column to decide which value to write. Fetch any layout with the `revela-designs` tool (`action: "read"`, `layout: "<name>"`).
510
+ Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. It must also set `data-slide-index="N"`, where `N` is the 1-based `DECKS.json` `slides[].index` value. Use the QA column to decide which value to write. Fetch any layout with the `revela-designs` tool (`action: "read"`, `layout: "<name>"`).
511
511
 
512
512
  <!-- @layout:fullbleed:start qa=false -->
513
513
  #### Fullbleed
@@ -518,7 +518,7 @@ Structural intent:
518
518
  - Single slot: place one `image-title` component directly inside `.page`. The component is self-contained — it manages its own image, blur, overlay, and text layers internally.
519
519
 
520
520
  ```html
521
- <section class="slide" slide-qa="false" data-index="N">
521
+ <section class="slide" slide-qa="false" data-slide-index="N">
522
522
  <div class="slide-canvas">
523
523
  <div class="page" style="padding:0;">
524
524
 
@@ -550,7 +550,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
550
550
 
551
551
 
552
552
  ```html
553
- <section class="slide" slide-qa="true" data-index="N">
553
+ <section class="slide" slide-qa="true" data-slide-index="N">
554
554
  <div class="slide-canvas">
555
555
  <div class="page" style="padding:0;overflow:hidden;">
556
556
  <div class="narrative-grid">
@@ -610,7 +610,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
610
610
 
611
611
 
612
612
  ```html
613
- <section class="slide" slide-qa="true" data-index="N">
613
+ <section class="slide" slide-qa="true" data-slide-index="N">
614
614
  <div class="slide-canvas">
615
615
  <div class="page" style="padding:0;overflow:hidden;">
616
616
  <div class="narrative-grid narrative-grid--reverse">
@@ -649,7 +649,7 @@ Structural intent:
649
649
  Every slot accepts 1 or more components. Add or remove child divs to control column count — 3 is the default, but 4 or 5 columns work equally well.
650
650
 
651
651
  ```html
652
- <section class="slide" slide-qa="true" data-index="N">
652
+ <section class="slide" slide-qa="true" data-slide-index="N">
653
653
  <div class="slide-canvas">
654
654
  <div class="page">
655
655
  <div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:520px;">
@@ -714,7 +714,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
714
714
 
715
715
 
716
716
  ```html
717
- <section class="slide" slide-qa="true" data-index="N">
717
+ <section class="slide" slide-qa="true" data-slide-index="N">
718
718
  <div class="slide-canvas">
719
719
  <div class="page" style="overflow:hidden;">
720
720
  <div class="halves-grid" style="flex:1;min-height:0;">
@@ -768,7 +768,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
768
768
 
769
769
 
770
770
  ```html
771
- <section class="slide" slide-qa="true" data-index="N">
771
+ <section class="slide" slide-qa="true" data-slide-index="N">
772
772
  <div class="slide-canvas">
773
773
  <div class="page" style="padding:0;">
774
774
  <div class="stacked-grid">
@@ -117,7 +117,7 @@ Every generated presentation must use this exact HTML skeleton:
117
117
  <style>/* all CSS here */</style>
118
118
  </head>
119
119
  <body>
120
- <section class="slide" slide-qa="false" data-index="0">
120
+ <section class="slide" slide-qa="false" data-slide-index="1">
121
121
  <div class="slide-canvas"><div class="page">...</div></div>
122
122
  </section>
123
123
  <script>/* all JS here */</script>
@@ -246,7 +246,7 @@ new SlidePresentation();
246
246
 
247
247
  ### Layout Types
248
248
 
249
- Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. Use the QA flag on each layout marker.
249
+ Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. Use the QA flag on each layout marker. It must also set `data-slide-index="N"`, where `N` is the 1-based `DECKS.json` `slides[].index` value.
250
250
 
251
251
  <!-- @layout:fullbleed:start qa=false -->
252
252
  #### Fullbleed
@@ -254,7 +254,7 @@ Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`.
254
254
  Full-page layout for a single dominant component such as `image-title`, a large `svg-motif`, or a sparse title field.
255
255
 
256
256
  ```html
257
- <section class="slide" slide-qa="false" data-index="N">
257
+ <section class="slide" slide-qa="false" data-slide-index="N">
258
258
  <div class="slide-canvas">
259
259
  <div class="page" style="padding:0;">
260
260
  <!-- [slot: content] — usually image-title, svg-motif, or a custom hero component -->
@@ -270,7 +270,7 @@ Full-page layout for a single dominant component such as `image-title`, a large
270
270
  Asymmetric two-column layout. Use when one side needs more visual or reading weight.
271
271
 
272
272
  ```html
273
- <section class="slide" slide-qa="true" data-index="N">
273
+ <section class="slide" slide-qa="true" data-slide-index="N">
274
274
  <div class="slide-canvas">
275
275
  <div class="page" style="padding:0;">
276
276
  <div class="narrative-grid">
@@ -295,7 +295,7 @@ Asymmetric two-column layout. Use when one side needs more visual or reading wei
295
295
  Mirrored asymmetric two-column layout. Same structure as `narrative`, with the wider column on the right.
296
296
 
297
297
  ```html
298
- <section class="slide" slide-qa="true" data-index="N">
298
+ <section class="slide" slide-qa="true" data-slide-index="N">
299
299
  <div class="slide-canvas">
300
300
  <div class="page" style="padding:0;">
301
301
  <div class="narrative-grid narrative-grid--reverse">
@@ -314,7 +314,7 @@ Mirrored asymmetric two-column layout. Same structure as `narrative`, with the w
314
314
  Equal-column layout for parallel ideas, feature groups, proof points, or compact component showcases.
315
315
 
316
316
  ```html
317
- <section class="slide" slide-qa="true" data-index="N">
317
+ <section class="slide" slide-qa="true" data-slide-index="N">
318
318
  <div class="slide-canvas">
319
319
  <div class="page">
320
320
  <div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:620px;">
@@ -343,7 +343,7 @@ Equal-column layout for parallel ideas, feature groups, proof points, or compact
343
343
  Symmetric two-column layout for direct comparison, paired evidence, or split workflows.
344
344
 
345
345
  ```html
346
- <section class="slide" slide-qa="true" data-index="N">
346
+ <section class="slide" slide-qa="true" data-slide-index="N">
347
347
  <div class="slide-canvas">
348
348
  <div class="page" style="padding:0;">
349
349
  <div class="halves-grid">
@@ -367,7 +367,7 @@ Symmetric two-column layout for direct comparison, paired evidence, or split wor
367
367
  Two-row layout for a compact header/summary above a larger evidence, chart, or flow area.
368
368
 
369
369
  ```html
370
- <section class="slide" slide-qa="true" data-index="N">
370
+ <section class="slide" slide-qa="true" data-slide-index="N">
371
371
  <div class="slide-canvas">
372
372
  <div class="page" style="padding:0;">
373
373
  <div class="stacked-grid">
@@ -131,10 +131,10 @@ Every generated presentation must use this exact HTML skeleton:
131
131
  <style>/* all CSS here */</style>
132
132
  </head>
133
133
  <body>
134
- <section class="slide cover-slide" slide-qa="false" data-index="0">
134
+ <section class="slide cover-slide" slide-qa="false" data-slide-index="1">
135
135
  <div class="slide-canvas"> ... </div>
136
136
  </section>
137
- <section class="slide" slide-qa="true" data-index="1">
137
+ <section class="slide" slide-qa="true" data-slide-index="2">
138
138
  <div class="slide-canvas"> ... </div>
139
139
  </section>
140
140
  <script>/* all JS here */</script>
@@ -445,7 +445,7 @@ These rules are mandatory for Summit.
445
445
 
446
446
  ### Layout Types
447
447
 
448
- Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. Use the QA column to decide which value to write. Fetch any layout with the `revela-designs` tool (`action: "read"`, `layout: "<name>"`).
448
+ Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. It must also set `data-slide-index="N"`, where `N` is the 1-based `DECKS.json` `slides[].index` value. Use the QA column to decide which value to write. Fetch any layout with the `revela-designs` tool (`action: "read"`, `layout: "<name>"`).
449
449
 
450
450
  <!-- @layout:fullbleed:start qa=false -->
451
451
  #### Fullbleed
@@ -456,7 +456,7 @@ Structural intent:
456
456
  - Single slot: place one `image-title` component directly inside `.page`. The component is self-contained — it manages its own image, blur, overlay, and text layers internally.
457
457
 
458
458
  ```html
459
- <section class="slide" slide-qa="false" data-index="N">
459
+ <section class="slide" slide-qa="false" data-slide-index="N">
460
460
  <div class="slide-canvas">
461
461
  <div class="page" style="padding:0;">
462
462
 
@@ -488,7 +488,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
488
488
 
489
489
 
490
490
  ```html
491
- <section class="slide" slide-qa="true" data-index="N">
491
+ <section class="slide" slide-qa="true" data-slide-index="N">
492
492
  <div class="slide-canvas">
493
493
  <div class="page" style="padding:0;overflow:hidden;">
494
494
  <div class="narrative-grid">
@@ -548,7 +548,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
548
548
 
549
549
 
550
550
  ```html
551
- <section class="slide" slide-qa="true" data-index="N">
551
+ <section class="slide" slide-qa="true" data-slide-index="N">
552
552
  <div class="slide-canvas">
553
553
  <div class="page" style="padding:0;overflow:hidden;">
554
554
  <div class="narrative-grid narrative-grid--reverse">
@@ -587,7 +587,7 @@ Structural intent:
587
587
  Every slot accepts 1 or more components. Add or remove child divs to control column count — 3 is the default, but 4 or 5 columns work equally well.
588
588
 
589
589
  ```html
590
- <section class="slide" slide-qa="true" data-index="N">
590
+ <section class="slide" slide-qa="true" data-slide-index="N">
591
591
  <div class="slide-canvas">
592
592
  <div class="page">
593
593
  <div style="display:flex;flex-direction:column;gap:10px;margin-bottom:28px;max-width:520px;">
@@ -652,7 +652,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
652
652
 
653
653
 
654
654
  ```html
655
- <section class="slide" slide-qa="true" data-index="N">
655
+ <section class="slide" slide-qa="true" data-slide-index="N">
656
656
  <div class="slide-canvas">
657
657
  <div class="page" style="overflow:hidden;">
658
658
  <div class="halves-grid" style="flex:1;min-height:0;">
@@ -706,7 +706,7 @@ Every slot accepts 1 or more components. The LLM decides what each slot contains
706
706
 
707
707
 
708
708
  ```html
709
- <section class="slide" slide-qa="true" data-index="N">
709
+ <section class="slide" slide-qa="true" data-slide-index="N">
710
710
  <div class="slide-canvas">
711
711
  <div class="page" style="padding:0;">
712
712
  <div class="stacked-grid">
@@ -28,7 +28,9 @@ export async function handleHelp(
28
28
  `\`/revela disable\` — disable slide generation mode\n` +
29
29
  `\`/revela init\` — initialize or refresh workspace DECKS.json\n` +
30
30
  `\`/revela review\` — review current deck readiness before writing HTML\n` +
31
+ `\`/revela refine\` — open unified Edit/Inspect refinement workspace\n` +
31
32
  `\`/revela edit\` — open visual editor for the only deck in decks/\n` +
33
+ `\`/revela inspect\` — open Evidence Inspector for click-to-inspect review\n` +
32
34
  `\`/revela remember <text>\` — save an explicit preference to DECKS.json\n` +
33
35
  `\`/revela designs\` — list installed designs\n` +
34
36
  `\`/revela designs <name>\` — activate a design\n` +
@@ -0,0 +1,23 @@
1
+ import { openInspectDeck } from "../inspect/open"
2
+
3
+ export async function handleInspect(
4
+ options: { client: any; sessionID: string; workspaceRoot: string },
5
+ send: (text: string) => Promise<void>,
6
+ ): Promise<void> {
7
+ try {
8
+ const result = openInspectDeck("", {
9
+ client: options.client,
10
+ sessionID: options.sessionID,
11
+ workspaceRoot: options.workspaceRoot,
12
+ })
13
+ await send(
14
+ `Opened Evidence Inspector for the active HTML deck.\n` +
15
+ `File: \`${result.deck.file}\`\n` +
16
+ `${result.stateNote}\n` +
17
+ `URL: ${result.url}\n\n` +
18
+ `Use Ctrl/Cmd-click in the browser to reference deck elements exactly like /revela edit, then click Inspect Selection. Deterministic Source/Purpose preprocessing appears first, followed by lazy LLM-generated cards. Selection is locked while the request is processed. There is no chat box or freeform prompt.`
19
+ )
20
+ } catch (e: any) {
21
+ await send(`**Inspect failed:** ${e.message || String(e)}`)
22
+ }
23
+ }
@@ -8,28 +8,41 @@
8
8
  */
9
9
 
10
10
  import { resolve } from "path"
11
+ import { hasDecksState, readDecksState } from "../decks-state"
11
12
  import { exportToPdf } from "../pdf/export"
12
13
  import { assertExportQAPassed } from "../qa/export-gate"
14
+ import { recordRenderedArtifact, workspaceRelative } from "../workspace-state/rendered-artifacts"
15
+ import { resolveActiveHtmlDeckPath } from "../workspace-state/render-targets"
13
16
 
14
17
  export async function handlePdf(
15
18
  filePath: string,
16
19
  send: (text: string) => Promise<void>,
20
+ workspaceRoot = process.cwd(),
17
21
  ): Promise<void> {
18
- if (!filePath) {
22
+ const root = resolve(workspaceRoot)
23
+ const resolvedFile = resolvePdfDeckFile(root, filePath)
24
+
25
+ if (!resolvedFile) {
19
26
  await send(
20
- "**Usage:** `/revela pdf <file_path>`\n\n" +
27
+ "**Usage:** `/revela pdf [file_path]`\n\n" +
21
28
  "Example: `/revela pdf decks/my-deck.html`"
22
29
  )
23
30
  return
24
31
  }
25
32
 
26
- const abs = resolve(filePath)
33
+ const abs = resolvedFile.absoluteFile
27
34
  await send(`Running pre-export QA for \`${abs}\`...`)
28
35
 
29
36
  try {
30
- await assertExportQAPassed(abs)
37
+ await assertExportQAPassed(abs, { workspaceRoot: root })
31
38
  await send(`Exporting \`${abs}\` to PDF...`)
32
- const result = await exportToPdf(filePath)
39
+ const result = await exportToPdf(abs)
40
+ recordRenderedArtifact(root, {
41
+ sourceHtmlPath: resolvedFile.file,
42
+ outputPath: result.outputPath,
43
+ type: "pdf",
44
+ actor: "revela-pdf",
45
+ })
33
46
  const secs = (result.durationMs / 1000).toFixed(1)
34
47
  await send(
35
48
  `**PDF exported successfully**\n\n` +
@@ -42,3 +55,18 @@ export async function handlePdf(
42
55
  await send(`**PDF export failed**\n\n\`\`\`\n${msg}\n\`\`\``)
43
56
  }
44
57
  }
58
+
59
+ function resolvePdfDeckFile(workspaceRoot: string, filePath: string): { file: string; absoluteFile: string } | undefined {
60
+ const explicit = filePath.trim()
61
+ if (explicit) {
62
+ const absoluteFile = resolve(workspaceRoot, explicit)
63
+ return { file: workspaceRelative(workspaceRoot, absoluteFile), absoluteFile }
64
+ }
65
+
66
+ if (!hasDecksState(workspaceRoot)) return undefined
67
+ const state = readDecksState(workspaceRoot)
68
+ const activePath = resolveActiveHtmlDeckPath(state)
69
+ if (!activePath) return undefined
70
+ const absoluteFile = resolve(workspaceRoot, activePath)
71
+ return { file: workspaceRelative(workspaceRoot, absoluteFile), absoluteFile }
72
+ }