@cyber-dash-tech/revela 0.7.8 → 0.8.1

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.
package/README.md CHANGED
@@ -2,7 +2,7 @@
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-171%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-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)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="800" />
@@ -112,7 +112,7 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
112
112
  Before the agent writes `decks/humanoid-robotics.html`, it must update `DECKS.json` through the `revela-decks` tool with the active deck, confirmed slide specs, layouts, components, and computed `writeReadiness.status: ready`. You can ask for an explicit readiness check at any time:
113
113
 
114
114
  ```text
115
- /revela review humanoid-robotics
115
+ /revela review
116
116
  ```
117
117
 
118
118
  Export when needed, either manually or by asking the agent to export:
@@ -138,9 +138,9 @@ Disable presentation mode when done:
138
138
  /revela disable disable presentation mode
139
139
 
140
140
  /revela init initialize or refresh workspace DECKS.json
141
- /revela review [slug] review active deck readiness before writing HTML
141
+ /revela review review current deck readiness before writing HTML
142
142
  /revela remember <text> save an explicit user/workflow preference
143
- /revela edit [target] open visual editor for active deck or a specific target
143
+ /revela edit open visual editor for the only deck in decks/
144
144
 
145
145
  /revela designs list installed designs
146
146
  /revela designs <name> activate a design
@@ -185,7 +185,7 @@ Revela uses a workspace-root `DECKS.json` file for cross-session continuity and
185
185
  It has two jobs:
186
186
 
187
187
  - workspace memory: stable project context, source materials, explicit user preferences, deck history, and open questions
188
- - active deck spec: current deck slug, output path, prerequisites, research plan, per-slide content, layouts, components, evidence, visuals, blockers, and write readiness
188
+ - active deck spec: current deck output path, prerequisites, research plan, per-slide content, layouts, components, evidence, visuals, blockers, and write readiness
189
189
 
190
190
  `DECKS.json` is the source of truth for workspace memory and deck readiness.
191
191
 
@@ -198,7 +198,7 @@ Create or refresh it with:
198
198
  Review the current deck state with:
199
199
 
200
200
  ```text
201
- /revela review [slug]
201
+ /revela review
202
202
  ```
203
203
 
204
204
  `/revela review` does not write the final HTML deck. It reads and updates `DECKS.json` through the `revela-decks` tool, checks what is missing, and sets `writeReadiness.status` to `ready` only when the deck is ready to generate.
@@ -351,7 +351,7 @@ You can ask Revela to create a new local design interactively:
351
351
  /revela designs-new my-design
352
352
  ```
353
353
 
354
- The agent will interview you for visual references, summarize a design brief for confirmation, then save `DESIGN.md` and `preview.html` into your local Revela designs directory. The default structural base is an internal neutral `starter` design, which is hidden from the normal design list. Use `--base summit` or `--base monet` only when you want to derive from those specific styles.
354
+ The agent will interview you for visual references, summarize a design brief for confirmation, then save `DESIGN.md` and `preview.html` into your local Revela designs directory. For AI-authored designs, `preview.html` is required: it must include cover and closing slides, and it must showcase every `@component:*` before `revela-designs-author` will accept the package. The default structural base is an internal neutral `starter` design, which is hidden from the normal design list. Use `--base summit` or `--base monet` only when you want to derive from those specific styles.
355
355
 
356
356
  Refine an existing local design:
357
357
 
@@ -374,7 +374,7 @@ Recommended structure:
374
374
  ```text
375
375
  my-design/
376
376
  ├── DESIGN.md
377
- └── preview.html optional, but recommended for humans
377
+ └── preview.html required for AI-authored designs
378
378
  ```
379
379
 
380
380
  `DESIGN.md` starts with frontmatter metadata:
@@ -565,7 +565,9 @@ If a design has no markers, Revela falls back to injecting the full `DESIGN.md`
565
565
  - Put the non-negotiable rules in `foundation` and `rules`; do not hide essential constraints only inside one layout
566
566
  - Keep layout names semantically meaningful; they become the vocabulary the model sees in the layout index
567
567
  - If your design defines a custom CSS class, document that class inside `DESIGN.md`; QA checks can flag classes not present in the design vocabulary
568
- - Add `preview.html` when possible so humans can inspect the design before activating it
568
+ - For AI-authored designs, `preview.html` must include `<section class="slide" data-slide-role="cover">` and `<section class="slide" data-slide-role="closing">`
569
+ - For AI-authored designs, `preview.html` must visibly showcase every `@component:*` and mark each sample with `data-preview-component="<component-name>"`; otherwise `revela-designs-author create/validate` will fail
570
+ - When the design supports chart styling, include a 3x3 ECharts gallery with at least 9 chart examples in `preview.html`; this is a quality requirement for the agent workflow, not a hard validation blocker
569
571
 
570
572
  Install a custom design:
571
573
 
@@ -591,19 +593,17 @@ A custom domain is a folder containing `INDUSTRY.md`.
591
593
 
592
594
  ## Visual Editing
593
595
 
594
- Open the visual editor for the active deck, or pass a slug / workspace-relative HTML path:
596
+ Open the visual editor for the only HTML deck in `decks/`:
595
597
 
596
598
  ```text
597
599
  /revela edit
598
- /revela edit my-deck
599
- /revela edit decks/my-deck.html
600
600
  ```
601
601
 
602
- Without a target, `/revela edit` opens `DECKS.json.activeDeck`. If no active deck is set and there is exactly one deck in `DECKS.json`, it opens that deck.
602
+ `/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.
603
603
 
604
604
  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.
605
605
 
606
- LLM tool equivalent: `revela-edit` with `{ "target": "decks/my-deck.html" }`. This lets the agent open the same editor when you say things like “I want to edit @decks/my-deck.html”.
606
+ 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”.
607
607
 
608
608
  `/revela edit` prepares minimal `DECKS.json` state for the existing HTML deck if needed, so the normal deck write gate can still protect `decks/*.html` while allowing targeted edits.
609
609
 
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
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-171%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-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)
6
6
 
7
7
  <p align="center">
8
8
  <img src="assets/img/logo.png" alt="Revela" width="800" />
@@ -111,7 +111,7 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
111
111
  在 agent 写入 `decks/humanoid-robotics.html` 之前,它必须通过 `revela-decks` 工具更新 `DECKS.json`:记录 active deck、已确认的逐页规格、layout、component,并由工具计算出 `writeReadiness.status: ready`。你也可以随时显式触发 readiness 检查:
112
112
 
113
113
  ```text
114
- /revela review humanoid-robotics
114
+ /revela review
115
115
  ```
116
116
 
117
117
  需要导出时,可以手动调用,也可以让 agent 直接导出:
@@ -137,9 +137,9 @@ Create a 6-slide HTML deck on humanoid robotics supply chains. Cite the main mar
137
137
  /revela disable 关闭演示文稿模式
138
138
 
139
139
  /revela init 初始化或刷新工作区 DECKS.json
140
- /revela review [slug] 写 HTML 前检查 active deck readiness
140
+ /revela review 写 HTML 前检查当前 deck readiness
141
141
  /revela remember <text> 保存明确的用户/工作流偏好
142
- /revela edit [target] 打开 active deck 或指定 target 的可视化编辑器
142
+ /revela edit 打开 decks/ 下唯一 deck 的可视化编辑器
143
143
 
144
144
  /revela designs 列出已安装 design
145
145
  /revela designs <name> 激活某个 design
@@ -184,7 +184,7 @@ Revela 使用工作区根目录的 `DECKS.json` 做跨会话记忆和 deck 生
184
184
  它有两个职责:
185
185
 
186
186
  - 工作区记忆:稳定项目背景、源材料、明确用户偏好、历史 deck 和开放问题
187
- - active deck 规格:当前 deck slug、输出路径、前置条件、research plan、逐页内容、layout、component、证据、视觉需求、blocker 和 write readiness
187
+ - active deck 规格:当前 deck 输出路径、前置条件、research plan、逐页内容、layout、component、证据、视觉需求、blocker 和 write readiness
188
188
 
189
189
  `DECKS.json` 是工作区记忆和 deck readiness 的 source of truth。
190
190
 
@@ -197,7 +197,7 @@ Revela 使用工作区根目录的 `DECKS.json` 做跨会话记忆和 deck 生
197
197
  检查当前 deck 状态:
198
198
 
199
199
  ```text
200
- /revela review [slug]
200
+ /revela review
201
201
  ```
202
202
 
203
203
  `/revela review` 不会写最终 HTML deck。它通过 `revela-decks` 工具读取并更新 `DECKS.json`,检查缺失项,并且只有在 deck 真的可以生成时才把 `writeReadiness.status` 设为 `ready`。
@@ -317,7 +317,7 @@ Revela 使用工作区根目录的 `DECKS.json` 做跨会话记忆和 deck 生
317
317
  /revela designs-new my-design
318
318
  ```
319
319
 
320
- Agent 会先询问你的审美参考,整理设计 brief 并等待确认,然后把 `DESIGN.md` 和 `preview.html` 保存到本地 Revela designs 目录。默认结构底座是内部中性 `starter` design,它不会出现在普通 design 列表中。只有当你明确想从 `summit` 或 `monet` 的具体风格派生时,才建议使用 `--base summit` 或 `--base monet`。
320
+ Agent 会先询问你的审美参考,整理设计 brief 并等待确认,然后把 `DESIGN.md` 和 `preview.html` 保存到本地 Revela designs 目录。对 AI 生成的 design,`preview.html` 是必需验收面:它必须包含 cover 和 closing 页,并且必须展示所有 `@component:*`,否则 `revela-designs-author` 不会接受这个包。默认结构底座是内部中性 `starter` design,它不会出现在普通 design 列表中。只有当你明确想从 `summit` 或 `monet` 的具体风格派生时,才建议使用 `--base summit` 或 `--base monet`。
321
321
 
322
322
  调整已有本地 design:
323
323
 
@@ -340,7 +340,7 @@ Agent 会询问你想修改什么,读取当前 design,整理 edit brief 并
340
340
  ```text
341
341
  my-design/
342
342
  ├── DESIGN.md
343
- └── preview.html 可选,但推荐,方便人工预览
343
+ └── preview.html AI 生成 design 必需
344
344
  ```
345
345
 
346
346
  `DESIGN.md` 顶部使用 frontmatter:
@@ -530,7 +530,9 @@ Prompt 注入规则:
530
530
  - 把不可妥协的规则放进 `foundation` 和 `rules`,不要只藏在某个 layout 里
531
531
  - layout 名称尽量语义化,因为模型在 layout index 里首先看到的就是这些名字
532
532
  - 如果定义了自定义 CSS class,记得在 `DESIGN.md` 里写出来;QA 会检查 design 词汇表之外的新 class
533
- - 如果条件允许,最好同时提供 `preview.html`,方便人工预览和验收
533
+ - AI 生成的 design 必须在 `preview.html` 中包含 `<section class="slide" data-slide-role="cover">` 和 `<section class="slide" data-slide-role="closing">`
534
+ - AI 生成的 design 必须在 `preview.html` 中可视化展示每个 `@component:*`,并用 `data-preview-component="<component-name>"` 标记;否则 `revela-designs-author create/validate` 会失败
535
+ - 如果 design 支持图表样式,`preview.html` 应包含 3x3 ECharts 九宫格,至少展示 9 个 chart 示例;这是 agent 工作流的质量要求,不是硬校验 blocker
534
536
 
535
537
  安装自定义 design:
536
538
 
@@ -556,19 +558,17 @@ Prompt 注入规则:
556
558
 
557
559
  ## 可视化编辑
558
560
 
559
- 可以直接打开 active deck,也可以传入 deck slug 或工作区相对 HTML 路径:
561
+ 打开 `decks/` 下唯一 HTML deck 的可视化编辑器:
560
562
 
561
563
  ```text
562
564
  /revela edit
563
- /revela edit my-deck
564
- /revela edit decks/my-deck.html
565
565
  ```
566
566
 
567
- 不传 target 时,`/revela edit` 会打开 `DECKS.json.activeDeck`。如果没有 active deck,但 `DECKS.json` 里只有一个 deck,则打开这个唯一 deck。
567
+ Revela 0.8 中 `/revela edit` 不接受 target。如果 `decks/` 下正好有一个 `.html` 文件,Revela 会打开它。如果 `decks/` 下没有 HTML 或有多个 HTML,Revela 会提示先生成 deck,或把多余 deck 移到独立 workspace
568
568
 
569
569
  编辑器会在浏览器中打开。使用 `Ctrl`/`Cmd` + 点击 deck 元素来引用它们,写一段自然语言评论,然后发送回 OpenCode。Revela 会把 deck 文件、slide 上下文、选中元素 metadata 和你的评论整理成结构化 edit prompt。
570
570
 
571
- 对应的 LLM tool:`revela-edit`,参数为 `{ "target": "decks/my-deck.html" }`。因此当你说“我要编辑 @decks/my-deck.html”时,agent 也可以主动打开同一个编辑器。
571
+ 对应的 LLM tool:`revela-edit`,不需要 target。因此当你说“我要编辑这个 deck”时,agent 也可以主动打开同一个编辑器。
572
572
 
573
573
  如果已有 HTML deck 缺少 `DECKS.json` 状态,`/revela edit` 会自动准备最小 deck state,让正常的 `decks/*.html` 写入门禁仍然生效,同时允许后续精准修改。
574
574
 
@@ -692,35 +692,139 @@ Small page number utility.
692
692
  <!-- @component:timeline-journey-horizontal:start -->
693
693
  #### Timeline Journey Horizontal (.timeline-journey-horizontal)
694
694
 
695
- Horizontal timeline for milestones.
695
+ Horizontal milestone journey with a central axis line. Nodes sit on the axis; a dashed vertical stem leads to a tip dot, with date, title, and description text alongside. Alternate nodes above and below the axis for rhythm. Suitable for 4-8 milestones across a chronological arc, transformation story, roadmap, or multi-year programme recap.
696
696
 
697
697
  ```html
698
- <div class="timeline-journey-horizontal"><div class="timeline-node"><span>01</span><h4>Milestone</h4><p>Short note.</p></div></div>
698
+ <div class="timeline-journey-horizontal" data-preview-component="timeline-journey-horizontal">
699
+ <div class="tjh-axis"></div>
700
+
701
+ <!-- Up node: label, tip-dot, stem, axis-dot. Content grows upward. -->
702
+ <div class="tjh-item tjh-item--up" style="left:12%; --tjh-item-color:var(--accent-primary);">
703
+ <div class="tjh-label">
704
+ <span class="tjh-date">Q1</span>
705
+ <span class="tjh-title">Baseline</span>
706
+ <span class="tjh-text">Map current signals and establish the reference state.</span>
707
+ </div>
708
+ <div class="tjh-tip-dot"></div>
709
+ <div class="tjh-stem"></div>
710
+ <div class="tjh-axis-dot"></div>
711
+ </div>
712
+
713
+ <!-- Down node: axis-dot, stem, tip-dot, label. Content grows downward. -->
714
+ <div class="tjh-item tjh-item--down" style="left:34%; --tjh-item-color:var(--accent-secondary);">
715
+ <div class="tjh-axis-dot"></div>
716
+ <div class="tjh-stem"></div>
717
+ <div class="tjh-tip-dot"></div>
718
+ <div class="tjh-label">
719
+ <span class="tjh-date">Q2</span>
720
+ <span class="tjh-title">Prototype</span>
721
+ <span class="tjh-text">Convert the plan into visible experiments.</span>
722
+ </div>
723
+ </div>
724
+ </div>
699
725
  ```
700
726
 
701
727
  ```css
702
- .timeline-journey-horizontal { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 28px; }
703
- .timeline-journey-horizontal::before { content: ''; position: absolute; left: 0; right: 0; top: 18px; height: 1px; background: var(--line-strong); }
704
- .timeline-node { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 12px; padding-right: 18px; }
705
- .timeline-node span { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: var(--surface); border: 1px solid var(--line-strong); color: var(--accent-primary); font-size: 12px; font-weight: 800; }
706
- ```
728
+ .timeline-journey-horizontal {
729
+ --tjh-node: 12px;
730
+ --tjh-stem-h: 76px;
731
+ --tjh-col: calc(100% / 6);
732
+ position: relative;
733
+ width: 100%;
734
+ height: 340px;
735
+ }
736
+ .tjh-axis { position: absolute; top: 50%; left: 0; right: 0; height: 1px; background: var(--line-strong); transform: translateY(-50%); }
737
+ .tjh-item { position: absolute; display: flex; flex-direction: column; align-items: center; width: var(--tjh-col); transform: translateX(-50%); }
738
+ .tjh-item--up { bottom: 50%; }
739
+ .tjh-item--down { top: 50%; }
740
+ .tjh-axis-dot, .tjh-tip-dot { width: var(--tjh-node); height: var(--tjh-node); border-radius: 999px; background: var(--tjh-item-color, var(--accent-primary)); flex-shrink: 0; }
741
+ .tjh-item--up .tjh-axis-dot { margin-bottom: calc(-1 * var(--tjh-node) / 2); }
742
+ .tjh-item--down .tjh-axis-dot { margin-top: calc(-1 * var(--tjh-node) / 2); }
743
+ .tjh-stem { width: 1px; height: var(--tjh-stem-h); background-image: repeating-linear-gradient(to bottom, var(--line-strong) 0 4px, transparent 4px 8px); flex-shrink: 0; }
744
+ .tjh-label { display: flex; flex-direction: column; gap: 4px; width: 100%; padding: 0 6px; }
745
+ .tjh-item--up .tjh-label { margin-bottom: 8px; }
746
+ .tjh-item--down .tjh-label { margin-top: 8px; }
747
+ .tjh-date { font-size: var(--font-size-meta); font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tjh-item-color, var(--accent-primary)); line-height: 1.3; white-space: nowrap; }
748
+ .tjh-title { font-size: 18px; font-weight: 700; line-height: 1.15; color: var(--text-primary); }
749
+ .tjh-text { font-size: 15px; line-height: 1.45; color: var(--text-secondary); }
750
+ ```
751
+
752
+ Rules:
753
+ - Position nodes with `left: X%` inline style. For N nodes, space them at `(100 / (N + 1)) * k %` or manually distribute to show real time gaps.
754
+ - Each node may set `--tjh-item-color` inline. Prefer existing neutral theme tokens such as `--accent-primary`, `--accent-secondary`, `--accent-danger`, or a derived local accent.
755
+ - Up node DOM order is `label -> tip-dot -> stem -> axis-dot`; down node DOM order is `axis-dot -> stem -> tip-dot -> label`.
756
+ - Keep `.tjh-text` short, usually 1-2 lines. The column width limits wrapping naturally.
757
+ - Alternate up/down nodes for visual rhythm unless clustering intentionally communicates a phase.
758
+ - Adjust `--tjh-col`, `--tjh-stem-h`, and component `height` for fewer or longer milestones.
707
759
  <!-- @component:timeline-journey-horizontal:end -->
708
760
 
709
761
  <!-- @component:timeline-journey-vertical:start -->
710
762
  #### Timeline Journey Vertical (.timeline-journey-vertical)
711
763
 
712
- Vertical timeline for narrow slots.
764
+ Vertical milestone journey with a central axis line. Nodes sit on the axis; a horizontal dashed stem leads to a tip dot, with date, title, and description text alongside. Alternate nodes left and right of the axis for rhythm. Suitable for 3-8 milestones in a full-height slot.
713
765
 
714
766
  ```html
715
- <div class="timeline-journey-vertical"><div class="timeline-v-node"><span>01</span><div><h4>Milestone</h4><p>Short note.</p></div></div></div>
767
+ <div class="timeline-journey-vertical" data-preview-component="timeline-journey-vertical">
768
+ <div class="tjv-axis"></div>
769
+
770
+ <!-- Left node: DOM order stays axis-dot, stem, tip-dot, label. CSS reverses the row. -->
771
+ <div class="tjv-item tjv-item--left" style="top:18%; --tjv-item-color:var(--accent-primary);">
772
+ <div class="tjv-axis-dot"></div>
773
+ <div class="tjv-stem"></div>
774
+ <div class="tjv-tip-dot"></div>
775
+ <div class="tjv-label">
776
+ <span class="tjv-date">Discover</span>
777
+ <span class="tjv-title">Signal scan</span>
778
+ <span class="tjv-text">Collect inputs and identify the high-confidence path.</span>
779
+ </div>
780
+ </div>
781
+
782
+ <!-- Right node: same DOM order, standard row direction. -->
783
+ <div class="tjv-item tjv-item--right" style="top:42%; --tjv-item-color:var(--accent-secondary);">
784
+ <div class="tjv-axis-dot"></div>
785
+ <div class="tjv-stem"></div>
786
+ <div class="tjv-tip-dot"></div>
787
+ <div class="tjv-label">
788
+ <span class="tjv-date">Build</span>
789
+ <span class="tjv-title">Visible proof</span>
790
+ <span class="tjv-text">Create the first proof points and refine the operating model.</span>
791
+ </div>
792
+ </div>
793
+ </div>
716
794
  ```
717
795
 
718
796
  ```css
719
- .timeline-journey-vertical { display: flex; flex-direction: column; gap: 0; }
720
- .timeline-v-node { display: grid; grid-template-columns: 42px 1fr; gap: 18px; padding-bottom: 26px; position: relative; }
721
- .timeline-v-node::before { content: ''; position: absolute; left: 17px; top: 42px; bottom: 4px; width: 1px; background: var(--line-strong); }
722
- .timeline-v-node span { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: var(--surface); border: 1px solid var(--line-strong); color: var(--accent-primary); font-size: 12px; font-weight: 800; }
723
- ```
797
+ .timeline-journey-vertical {
798
+ --tjv-node: 12px;
799
+ --tjv-stem-w: 76px;
800
+ position: relative;
801
+ width: 100%;
802
+ height: 100%;
803
+ }
804
+ .tjv-axis { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: var(--line-strong); transform: translateX(-50%); }
805
+ .tjv-item { position: absolute; display: flex; align-items: center; height: 78px; transform: translateY(-50%); }
806
+ .tjv-item--left { right: 50%; flex-direction: row-reverse; }
807
+ .tjv-item--right { left: 50%; flex-direction: row; }
808
+ .tjv-axis-dot { width: var(--tjv-node); height: var(--tjv-node); border-radius: 999px; background: var(--tjv-item-color, var(--accent-primary)); flex-shrink: 0; position: relative; z-index: 1; }
809
+ .tjv-item--left .tjv-axis-dot { margin-right: calc(-1 * var(--tjv-node) / 2); }
810
+ .tjv-item--right .tjv-axis-dot { margin-left: calc(-1 * var(--tjv-node) / 2); }
811
+ .tjv-tip-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--tjv-item-color, var(--accent-primary)); flex-shrink: 0; }
812
+ .tjv-stem { width: var(--tjv-stem-w); height: 1px; background-image: repeating-linear-gradient(to right, var(--line-strong) 0 4px, transparent 4px 8px); flex-shrink: 0; }
813
+ .tjv-label { display: flex; flex-direction: column; gap: 4px; }
814
+ .tjv-item--left .tjv-label { text-align: right; align-items: flex-end; padding-right: 18px; max-width: 440px; }
815
+ .tjv-item--right .tjv-label { text-align: left; align-items: flex-start; padding-left: 18px; max-width: 440px; }
816
+ .tjv-date { font-size: var(--font-size-meta); font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tjv-item-color, var(--accent-primary)); line-height: 1.3; white-space: nowrap; }
817
+ .tjv-title { font-size: 18px; font-weight: 700; line-height: 1.15; color: var(--text-primary); }
818
+ .tjv-text { font-size: 15px; line-height: 1.45; color: var(--text-secondary); max-width: 360px; }
819
+ ```
820
+
821
+ Rules:
822
+ - DOM order is identical for left and right nodes: `axis-dot -> stem -> tip-dot -> label`. Direction is controlled by CSS (`row-reverse` for left, `row` for right).
823
+ - Position each node with `top: Y%` inline style. For N nodes, distribute evenly with `(100 / (N + 1)) * k %` or manually to reflect time proportions.
824
+ - Each node may set `--tjv-item-color` inline. Prefer current theme tokens rather than hard-coded project colors.
825
+ - Alternate left and right nodes for rhythm. Avoid consecutive same-side nodes unless the story needs clustering.
826
+ - The parent container must have a defined height. Use `height: 100%` inside a layout slot, or set an explicit height when standalone.
827
+ - Keep `.tjv-text` to 2-3 lines. Longer labels shift the perceived center away from the axis dot.
724
828
  <!-- @component:timeline-journey-vertical:end -->
725
829
 
726
830
  <!-- @component:svg-motif:start -->
@@ -140,13 +140,37 @@
140
140
  .brand-watermark strong { font-weight: 800; color: var(--text-secondary); }
141
141
  .page-number { position: absolute; right: 34px; bottom: 26px; z-index: 10; font-size: 12px; letter-spacing: 0.14em; color: var(--text-muted); }
142
142
  .page-number--light { color: rgba(248,250,252,0.72); }
143
- .timeline-journey-horizontal { position: relative; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 28px; }
144
- .timeline-journey-horizontal::before { content: ''; position: absolute; left: 0; right: 0; top: 18px; height: 1px; background: var(--line-strong); }
145
- .timeline-node { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 12px; padding-right: 18px; }
146
- .timeline-node span, .timeline-v-node span { width: 36px; height: 36px; display: flex; align-items: center; justify-content: center; background: var(--surface); border: 1px solid var(--line-strong); color: var(--accent-primary); font-size: 12px; font-weight: 800; }
147
- .timeline-journey-vertical { display: flex; flex-direction: column; gap: 0; }
148
- .timeline-v-node { display: grid; grid-template-columns: 42px 1fr; gap: 18px; padding-bottom: 26px; position: relative; }
149
- .timeline-v-node::before { content: ''; position: absolute; left: 17px; top: 42px; bottom: 4px; width: 1px; background: var(--line-strong); }
143
+ .timeline-journey-horizontal { --tjh-node: 12px; --tjh-stem-h: 62px; --tjh-col: 180px; position: relative; width: 100%; height: 245px; }
144
+ .tjh-axis { position: absolute; top: 50%; left: 0; right: 0; height: 1px; background: var(--line-strong); transform: translateY(-50%); }
145
+ .tjh-item { position: absolute; display: flex; flex-direction: column; align-items: center; width: var(--tjh-col); transform: translateX(-50%); }
146
+ .tjh-item--up { bottom: 50%; }
147
+ .tjh-item--down { top: 50%; }
148
+ .tjh-axis-dot, .tjh-tip-dot { width: var(--tjh-node); height: var(--tjh-node); border-radius: 999px; background: var(--tjh-item-color, var(--accent-primary)); flex-shrink: 0; }
149
+ .tjh-item--up .tjh-axis-dot { margin-bottom: calc(-1 * var(--tjh-node) / 2); }
150
+ .tjh-item--down .tjh-axis-dot { margin-top: calc(-1 * var(--tjh-node) / 2); }
151
+ .tjh-stem { width: 1px; height: var(--tjh-stem-h); background-image: repeating-linear-gradient(to bottom, var(--line-strong) 0 4px, transparent 4px 8px); flex-shrink: 0; }
152
+ .tjh-label { display: flex; flex-direction: column; gap: 3px; width: 100%; padding: 0 6px; }
153
+ .tjh-item--up .tjh-label { margin-bottom: 8px; }
154
+ .tjh-item--down .tjh-label { margin-top: 8px; }
155
+ .tjh-date { font-size: 11px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tjh-item-color, var(--accent-primary)); line-height: 1.3; white-space: nowrap; }
156
+ .tjh-title { font-size: 17px; font-weight: 700; line-height: 1.15; color: var(--text-primary); }
157
+ .tjh-text { font-size: 13px; line-height: 1.4; color: var(--text-secondary); }
158
+ .timeline-journey-vertical { --tjv-node: 12px; --tjv-stem-w: 46px; position: relative; width: 100%; height: 100%; min-height: 260px; }
159
+ .tjv-axis { position: absolute; left: 50%; top: 0; bottom: 0; width: 1px; background: var(--line-strong); transform: translateX(-50%); }
160
+ .tjv-item { position: absolute; display: flex; align-items: center; height: 72px; transform: translateY(-50%); }
161
+ .tjv-item--left { right: 50%; flex-direction: row-reverse; }
162
+ .tjv-item--right { left: 50%; flex-direction: row; }
163
+ .tjv-axis-dot { width: var(--tjv-node); height: var(--tjv-node); border-radius: 999px; background: var(--tjv-item-color, var(--accent-primary)); flex-shrink: 0; position: relative; z-index: 1; }
164
+ .tjv-item--left .tjv-axis-dot { margin-right: calc(-1 * var(--tjv-node) / 2); }
165
+ .tjv-item--right .tjv-axis-dot { margin-left: calc(-1 * var(--tjv-node) / 2); }
166
+ .tjv-tip-dot { width: 8px; height: 8px; border-radius: 999px; background: var(--tjv-item-color, var(--accent-primary)); flex-shrink: 0; }
167
+ .tjv-stem { width: var(--tjv-stem-w); height: 1px; background-image: repeating-linear-gradient(to right, var(--line-strong) 0 4px, transparent 4px 8px); flex-shrink: 0; }
168
+ .tjv-label { display: flex; flex-direction: column; gap: 3px; }
169
+ .tjv-item--left .tjv-label { text-align: right; align-items: flex-end; padding-right: 14px; max-width: 220px; }
170
+ .tjv-item--right .tjv-label { text-align: left; align-items: flex-start; padding-left: 14px; max-width: 220px; }
171
+ .tjv-date { font-size: 11px; font-weight: 800; letter-spacing: 0.14em; text-transform: uppercase; color: var(--tjv-item-color, var(--accent-primary)); line-height: 1.3; white-space: nowrap; }
172
+ .tjv-title { font-size: 17px; font-weight: 700; line-height: 1.15; color: var(--text-primary); }
173
+ .tjv-text { font-size: 13px; line-height: 1.4; color: var(--text-secondary); max-width: 210px; }
150
174
  .svg-motif { position: relative; pointer-events: none; color: var(--text-primary); }
151
175
  .svg-motif svg { display: block; width: 100%; height: 100%; overflow: visible; }
152
176
  .svg-motif--bottom { position: absolute; left: 0; right: 0; bottom: 0; height: 30%; }
@@ -156,7 +180,7 @@
156
180
  </style>
157
181
  </head>
158
182
  <body>
159
- <section class="slide" slide-qa="false" data-index="0">
183
+ <section class="slide" slide-qa="false" data-index="0" data-slide-role="cover">
160
184
  <div class="slide-canvas">
161
185
  <div class="page" style="padding:0;">
162
186
  <div class="image-title image-title--left">
@@ -229,10 +253,22 @@
229
253
  <div class="slide-canvas">
230
254
  <div class="page" style="padding:0;">
231
255
  <div class="stacked-grid">
232
- <div class="stacked-top text-panel reveal" style="padding:48px 56px 30px;"><div class="text-panel-body"><p class="eyebrow">Data and process</p><h2>Evidence components stay structural</h2><p>Charts, tables, and flows inherit the active theme while keeping predictable geometry.</p></div></div>
233
- <div class="stacked-bottom" style="display:grid;grid-template-columns:1.2fr .8fr;gap:40px;padding:0 56px 56px;">
256
+ <div class="stacked-top text-panel reveal" style="padding:42px 56px 20px;"><div class="text-panel-body"><p class="eyebrow">Data and process</p><h2>Evidence components stay structural</h2><p>Charts, tables, and journey timelines inherit the active theme while keeping predictable geometry.</p></div></div>
257
+ <div class="stacked-bottom" style="display:grid;grid-template-columns:1fr 1fr;grid-template-rows:minmax(0,1fr) 250px;gap:26px;padding:0 56px 56px;">
234
258
  <div class="echart-panel reveal"><div class="echart-panel-header"><p class="eyebrow">Example chart</p><h3>Signal distribution</h3><p class="chart-subtitle">Neutral chart defaults with restrained labels.</p></div><div class="echart-container" id="starter-chart"></div><p class="chart-caption">Source: demo data</p></div>
235
- <div class="data-table-wrap reveal"><div class="data-table-label">Component matrix</div><table class="data-table"><thead><tr><th>Primitive</th><th>Count</th><th>Role</th></tr></thead><tbody><tr><td>Layouts</td><td>6</td><td>Structure</td></tr><tr><td>Components</td><td>16</td><td>Coverage</td></tr><tr><td>SVG motif</td><td>1</td><td>Vector</td></tr></tbody></table><p class="table-caption">Starter remains visually neutral.</p></div>
259
+ <div class="timeline-journey-vertical reveal" data-preview-component="timeline-journey-vertical">
260
+ <div class="tjv-axis"></div>
261
+ <div class="tjv-item tjv-item--left" style="top:18%; --tjv-item-color:var(--accent-primary);"><div class="tjv-axis-dot"></div><div class="tjv-stem"></div><div class="tjv-tip-dot"></div><div class="tjv-label"><span class="tjv-date">Discover</span><span class="tjv-title">Signal scan</span><span class="tjv-text">Map inputs and identify the base pattern.</span></div></div>
262
+ <div class="tjv-item tjv-item--right" style="top:50%; --tjv-item-color:var(--accent-secondary);"><div class="tjv-axis-dot"></div><div class="tjv-stem"></div><div class="tjv-tip-dot"></div><div class="tjv-label"><span class="tjv-date">Build</span><span class="tjv-title">Theme draft</span><span class="tjv-text">Apply visual schema without changing structure.</span></div></div>
263
+ <div class="tjv-item tjv-item--left" style="top:82%; --tjv-item-color:var(--accent-danger);"><div class="tjv-axis-dot"></div><div class="tjv-stem"></div><div class="tjv-tip-dot"></div><div class="tjv-label"><span class="tjv-date">Verify</span><span class="tjv-title">Preview pass</span><span class="tjv-text">Check roles, components, and slide geometry.</span></div></div>
264
+ </div>
265
+ <div class="timeline-journey-horizontal reveal" data-preview-component="timeline-journey-horizontal" style="grid-column:1 / -1;">
266
+ <div class="tjh-axis"></div>
267
+ <div class="tjh-item tjh-item--up" style="left:14%; --tjh-item-color:var(--accent-primary);"><div class="tjh-label"><span class="tjh-date">01</span><span class="tjh-title">Brief</span><span class="tjh-text">Clarify source style.</span></div><div class="tjh-tip-dot"></div><div class="tjh-stem"></div><div class="tjh-axis-dot"></div></div>
268
+ <div class="tjh-item tjh-item--down" style="left:38%; --tjh-item-color:var(--accent-secondary);"><div class="tjh-axis-dot"></div><div class="tjh-stem"></div><div class="tjh-tip-dot"></div><div class="tjh-label"><span class="tjh-date">02</span><span class="tjh-title">Tokens</span><span class="tjh-text">Set color and type.</span></div></div>
269
+ <div class="tjh-item tjh-item--up" style="left:62%; --tjh-item-color:var(--accent-danger);"><div class="tjh-label"><span class="tjh-date">03</span><span class="tjh-title">Modules</span><span class="tjh-text">Skin components.</span></div><div class="tjh-tip-dot"></div><div class="tjh-stem"></div><div class="tjh-axis-dot"></div></div>
270
+ <div class="tjh-item tjh-item--down" style="left:86%; --tjh-item-color:var(--text-muted);"><div class="tjh-axis-dot"></div><div class="tjh-stem"></div><div class="tjh-tip-dot"></div><div class="tjh-label"><span class="tjh-date">04</span><span class="tjh-title">Validate</span><span class="tjh-text">Inspect preview.</span></div></div>
271
+ </div>
236
272
  </div>
237
273
  </div>
238
274
  <div class="page-number">05</div>
@@ -240,7 +276,7 @@
240
276
  </div>
241
277
  </section>
242
278
 
243
- <section class="slide" slide-qa="false" data-index="5">
279
+ <section class="slide" slide-qa="false" data-index="5" data-slide-role="closing">
244
280
  <div class="slide-canvas">
245
281
  <div class="page">
246
282
  <div class="svg-motif svg-motif--corner" aria-hidden="true"><svg viewBox="0 0 600 360"><rect x="80" y="190" width="360" height="34" fill="#dbeafe"/><circle cx="190" cy="150" r="82" fill="#3b82f6" opacity=".82"/><path d="M286 230 C330 120 474 122 516 226 C458 274 348 276 286 230 Z" fill="#64748b" opacity=".68"/><path d="M112 70 l22 -22 l22 22 l-22 22 Z" fill="none" stroke="#17191c" stroke-width="8"/><path d="M470 72 C508 38 548 46 566 88" fill="none" stroke="#17191c" stroke-width="9" stroke-linecap="round"/></svg></div>
@@ -29,7 +29,7 @@ Given a research brief specifying your topic and axis, you will:
29
29
  2. Use \`DECKS.json\` through \`revela-decks\` as the workspace material index when it exists
30
30
  3. Run a lightweight workspace freshness check when needed
31
31
  4. Search the web for current data, reports, and case studies when the brief requires it
32
- 5. Write all findings to ONE structured file: \`researches/{topic-slug}/{axis-name}.md\`
32
+ 5. Write all findings to ONE structured file: \`researches/{topic-key}/{axis-name}.md\`
33
33
  6. Return a brief summary of what you found
34
34
 
35
35
  ---
@@ -37,7 +37,7 @@ Given a research brief specifying your topic and axis, you will:
37
37
  ## Step 1 — Research brief and workspace memory
38
38
 
39
39
  Start from the research brief supplied by the primary agent. It should include:
40
- - shared topic slug
40
+ - shared topic key
41
41
  - your axis filename
42
42
  - the specific question for this axis
43
43
  - time period, geography, and evidence standard
@@ -100,7 +100,7 @@ Search strategy:
100
100
 
101
101
  Use **\`revela-research-save\`** to write ONE file with all your findings.
102
102
 
103
- - \`topic\`: kebab-case slug shared across all agents for this presentation
103
+ - \`topic\`: kebab-case topic key shared across all agents for this presentation
104
104
  - \`filename\`: your axis name (e.g. \`market-data\`, \`catl-profile\`, \`tech-trends\`)
105
105
  - \`content\`: structured findings using the four sections below
106
106
  - \`sources\`: list of all URLs and filenames used
@@ -140,7 +140,7 @@ Content rules:
140
140
  After writing the file, return this summary (do NOT include the raw data):
141
141
 
142
142
  \`\`\`
143
- Research complete: {axis-name} → researches/{topic-slug}/{axis-name}.md
143
+ Research complete: {axis-name} → researches/{topic-key}/{axis-name}.md
144
144
 
145
145
  Key findings (3–5, most argument-worthy only):
146
146
  - {1–2 sentence highlight with source}
@@ -79,6 +79,12 @@ const VISUAL_QUALITY_RULES = `Visual extraction and CSS quality rules:
79
79
  - For SVG motifs: set a viewBox, keep all eyes/mouths/decorations inside that coordinate system, and document intended placement/scale in the component notes.
80
80
  - Before saving, review the preview for text overlap, scale drift, lost anchoring, overflow, and whether the preview preserves the reference composition.`
81
81
 
82
+ const PREVIEW_REQUIREMENTS = `Preview requirements:
83
+ - \`preview.html\` must include a cover slide and a closing slide. Mark their \`<section class="slide">\` elements with \`data-slide-role="cover"\` and \`data-slide-role="closing"\`.
84
+ - \`preview.html\` must showcase every \`@component:*\` defined in \`DESIGN.md\`. Mark each showcased component with \`data-preview-component="<component-name>"\`.
85
+ - Do not save with \`revela-designs-author\` until every component has a corresponding preview marker. If a component is decorative or abstract, include a visible labeled sample state.
86
+ - When the design supports chart styling, \`preview.html\` should include a 3x3 ECharts gallery with at least 9 chart examples. This is a preview quality requirement, not a validation blocker.`
87
+
82
88
  export function buildDesignsNewPrompt({ name, base }: DesignsNewArgs): string {
83
89
  return `You are creating a new Revela visual design package.
84
90
 
@@ -107,6 +113,8 @@ You must replace unless the user explicitly requests otherwise:
107
113
 
108
114
  ${VISUAL_QUALITY_RULES}
109
115
 
116
+ ${PREVIEW_REQUIREMENTS}
117
+
110
118
  Workflow:
111
119
  1. Do not generate or save files immediately.
112
120
  2. Interview the user first. Ask for visual references such as screenshots/images, webpage URLs, text descriptions, brands, or decks they like.
@@ -126,6 +134,8 @@ Hard requirements:
126
134
  - \`DESIGN.md\` must include at least \`@design:foundation\`, \`@design:rules\`, one layout, and one component.
127
135
  - \`preview.html\` must be self-contained and directly openable in a browser.
128
136
  - Every preview slide must include \`slide-qa="true"\` or \`slide-qa="false"\`.
137
+ - \`preview.html\` must include \`data-slide-role="cover"\` and \`data-slide-role="closing"\` on slide sections.
138
+ - \`preview.html\` must showcase every \`@component:*\` with \`data-preview-component="<component-name>"\` before saving.
129
139
  - Do not save anything until the user confirms the brief.
130
140
 
131
141
  Start now by interviewing the user. Keep the first question concise.`
@@ -144,6 +154,8 @@ Goal:
144
154
 
145
155
  ${VISUAL_QUALITY_RULES}
146
156
 
157
+ ${PREVIEW_REQUIREMENTS}
158
+
147
159
  Workflow:
148
160
  1. Do not save files immediately.
149
161
  2. Ask the user what they want to change. Accept text descriptions, screenshots/images, webpage URLs, or specific complaints about the current preview.
@@ -161,6 +173,8 @@ Hard requirements:
161
173
  - Preserve at least \`@design:foundation\`, \`@design:rules\`, one layout, and one component.
162
174
  - \`preview.html\` must be self-contained and directly openable in a browser.
163
175
  - Every preview slide must include \`slide-qa="true"\` or \`slide-qa="false"\`.
176
+ - \`preview.html\` must include \`data-slide-role="cover"\` and \`data-slide-role="closing"\` on slide sections.
177
+ - \`preview.html\` must showcase every \`@component:*\` with \`data-preview-component="<component-name>"\` before saving.
164
178
  - Do not save anything until the user confirms the edit brief.
165
179
 
166
180
  Start now by asking what the user wants to change in \`${name}\`.`
@@ -1,22 +1,19 @@
1
1
  import { openEditableDeck } from "../edit/open"
2
2
 
3
3
  export async function handleEdit(
4
- input: string,
5
4
  options: { client: any; sessionID: string; workspaceRoot: string },
6
5
  send: (text: string) => Promise<void>,
7
6
  ): Promise<void> {
8
- const target = input.trim()
9
-
10
7
  try {
11
- const result = openEditableDeck(target, {
8
+ const result = openEditableDeck("", {
12
9
  client: options.client,
13
10
  sessionID: options.sessionID,
14
11
  workspaceRoot: options.workspaceRoot,
15
12
  })
16
13
 
17
14
  await send(
18
- `Opened visual editor for deck \`${result.deck.slug}\`.\n` +
19
- `File: \`${result.deck.file}\` (${result.source})\n` +
15
+ `Opened visual editor for the only deck in \`decks/\`.\n` +
16
+ `File: \`${result.deck.file}\`\n` +
20
17
  `${result.stateNote}\n` +
21
18
  `URL: ${result.url}\n\n` +
22
19
  `Use Ctrl/Cmd + click in the browser to reference elements, write a comment, then send comments. Revela mode has been enabled for the edit prompt.`
@@ -27,8 +27,8 @@ export async function handleHelp(
27
27
  `\`/revela enable\` — enable slide generation mode\n` +
28
28
  `\`/revela disable\` — disable slide generation mode\n` +
29
29
  `\`/revela init\` — initialize or refresh workspace DECKS.json\n` +
30
- `\`/revela review [slug]\` — review active deck readiness before writing HTML\n` +
31
- `\`/revela edit [target]\` — open visual editor for active deck or a specific target\n` +
30
+ `\`/revela review\` — review current deck readiness before writing HTML\n` +
31
+ `\`/revela edit\` — open visual editor for the only deck in decks/\n` +
32
32
  `\`/revela remember <text>\` — save an explicit preference to DECKS.json\n` +
33
33
  `\`/revela designs\` — list installed designs\n` +
34
34
  `\`/revela designs <name>\` — activate a design\n` +