@cyber-dash-tech/revela 0.18.2 → 0.18.3

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
@@ -34,7 +34,7 @@ To install globally, add the same entry to `~/.config/opencode/opencode.json`.
34
34
  Requirements:
35
35
 
36
36
  - The Codex CLI must be installed and the `codex` command must be available in your shell.
37
- - Your environment must be able to run `npx`; Revela uses `npx -y @cyber-dash-tech/revela@0.18.2 mcp` to start the MCP server.
37
+ - Your environment must be able to run `npx`; Revela uses `npx -y @cyber-dash-tech/revela@0.18.3 mcp` to start the MCP server.
38
38
  - For interactive Review actions, `codex exec` must also work because the Review UI uses it for Comment/Apply Fix requests.
39
39
 
40
40
  Optional preflight:
@@ -55,11 +55,11 @@ npm_config_cache=/tmp/revela-npm-cache bun run smoke:mcp-pack
55
55
  Install Revela through the Codex Git marketplace:
56
56
 
57
57
  ```bash
58
- codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.2
58
+ codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.3
59
59
  codex plugin add revela@revela
60
60
  ```
61
61
 
62
- The Git marketplace install provides the Codex plugin shell, skills, hooks, and MCP configuration. When Codex starts the Revela MCP server for the first time, it runs `npx -y @cyber-dash-tech/revela@0.18.2 mcp` so npm can fetch the published package and its dependencies.
62
+ The Git marketplace install provides the Codex plugin shell, skills, hooks, and MCP configuration. When Codex starts the Revela MCP server for the first time, it runs `npx -y @cyber-dash-tech/revela@0.18.3 mcp` so npm can fetch the published package and its dependencies.
63
63
 
64
64
  You do not need to run `bun install` inside the Codex marketplace clone.
65
65
 
@@ -169,7 +169,7 @@ revela, help me init this workspace from the local materials.
169
169
  revela, research the public evidence and examples needed for this deck.
170
170
  ```
171
171
 
172
- 6. Create or update the deck plan before generating HTML so slide order, chapter structure, source links, caveats, and visual intent are explicit.
172
+ 6. Create or update the deck plan before generating HTML so slide order, chapter structure, source links, unresolved inputs, source limitations, and visual intent are explicit.
173
173
 
174
174
  ```text
175
175
  revela, create or update the deck plan before generating HTML.
package/README.zh-CN.md CHANGED
@@ -34,7 +34,7 @@ Revela 可在 [OpenCode](https://opencode.ai) 和 Codex 中使用,把来源材
34
34
  环境要求:
35
35
 
36
36
  - 需要已安装 Codex CLI,并且 shell 中可以执行 `codex`。
37
- - 环境中需要可以执行 `npx`;Revela 会用 `npx -y @cyber-dash-tech/revela@0.18.2 mcp` 启动 MCP server。
37
+ - 环境中需要可以执行 `npx`;Revela 会用 `npx -y @cyber-dash-tech/revela@0.18.3 mcp` 启动 MCP server。
38
38
  - 如果使用 Review UI 的 Comment 或 Apply Fix,需要 `codex exec` 可用。
39
39
 
40
40
  可选的安装前检查:
@@ -55,11 +55,11 @@ npm_config_cache=/tmp/revela-npm-cache bun run smoke:mcp-pack
55
55
  通过 Codex Git marketplace 安装 Revela:
56
56
 
57
57
  ```bash
58
- codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.2
58
+ codex plugin marketplace add https://github.com/cyber-dash-tech/revela --ref v0.18.3
59
59
  codex plugin add revela@revela
60
60
  ```
61
61
 
62
- Git marketplace 安装的是 Codex plugin 壳、skills、hooks 和 MCP 配置。Codex 第一次启动 Revela MCP server 时,会运行 `npx -y @cyber-dash-tech/revela@0.18.2 mcp`,由 npm 获取已发布 package 及其 dependencies。
62
+ Git marketplace 安装的是 Codex plugin 壳、skills、hooks 和 MCP 配置。Codex 第一次启动 Revela MCP server 时,会运行 `npx -y @cyber-dash-tech/revela@0.18.3 mcp`,由 npm 获取已发布 package 及其 dependencies。
63
63
 
64
64
  不需要在 Codex marketplace clone 里运行 `bun install`。
65
65
 
@@ -169,7 +169,7 @@ revela,帮我 init 这个 workspace,先读本地材料。
169
169
  revela,research 这个 deck 需要的公开证据、案例和 source。
170
170
  ```
171
171
 
172
- 6. 先创建或更新 deck plan,明确 slide 顺序、章节结构、source links、caveats 和 visual intent,再生成 HTML。
172
+ 6. 先创建或更新 deck plan,明确 slide 顺序、章节结构、source links、unresolved inputs、source limitations 和 visual intent,再生成 HTML。
173
173
 
174
174
  ```text
175
175
  revela,生成 HTML 前先 create or update deck plan。
@@ -45,7 +45,7 @@ Report format:
45
45
  - Start with \`Narrative readiness: <status>\`.
46
46
  - Include \`Narrative hash: <hash>\` when returned.
47
47
  - List diagnostics with issue type, claim text when available, and suggested next action. Keep Markdown QA repair cards separate from compiler diagnostics.
48
- - If warnings exist, list them after blockers as residual risks.
48
+ - If warnings exist, list them after blockers as residual diagnostics.
49
49
  - Keep deck/artifact readiness separate. If the user wants to write or review deck artifacts, tell them to run \`/revela make --deck\`.
50
50
 
51
51
  Rules:
@@ -74,8 +74,8 @@ export function buildDeckPlanPrompt({
74
74
  Goal:
75
75
  - Build canonical deck-plan.md directly from the user's goal, reviewed local materials, saved research findings, and active design vocabulary.
76
76
  - Do not create, read, repair, or require revela-narrative/.
77
- - Use sourceLinks in deck-plan.md to reference material paths, material review files, research findings, asset paths, URLs, and caveats. These are source links, not narrative graph links.
78
- - Use "unresolved inputs", "research tasks", "source limitations", or "caveats"; do not use the product concept of research gaps.
77
+ - Use sourceLinks in deck-plan.md to reference material paths, material review files, research findings, asset paths, and URLs. These are source links, not narrative graph links.
78
+ - Use "unresolved inputs", "research tasks", "source limitations", or "user review notes"; do not use the product concept of research gaps.
79
79
  - Do not write HTML during planning.
80
80
 
81
81
  Current state:
@@ -88,7 +88,7 @@ Workflow:
88
88
  3. Ask only for missing high-impact intent: audience, objective, decision/action, language, rough slide count, or source priority.
89
89
  4. Read active design inventory/rules before selecting layouts/components.
90
90
  5. Write deck-plan.md with deck objective, audience, output format, chapter outline, source authority, unresolved inputs, and an ordered slide plan.
91
- 6. For every slide block, include positive 1-based slideIndex, title, chapter, purpose, layout, component plan, visual intent, sourceLinks, caveats, and speaker/content notes.
91
+ 6. For every slide block, use a \`---\` slide separator with slide-local metadata, then include \`#### Content Plan\`, \`#### Source Links\`, and \`#### Design Plan\`.
92
92
  7. Include Cover, Table of Contents, and Closing slides unless the user explicitly asks for a non-standard artifact.
93
93
  8. Run/read deck-plan diagnostics after writing and report technical issues separately from source limitations.
94
94
 
@@ -115,7 +115,7 @@ Goal:
115
115
  - Read the current deck-plan.md projection and generate or update decks/*.html.
116
116
  - Do not create, compile, or require revela-narrative/.
117
117
  - Use the deck-render prompt mode for design, layout, components, HTML, QA, and export preflight.
118
- - Preserve source links and caveats from deck-plan in slide source notes or speaker notes where appropriate.
118
+ - Preserve source links, unresolved inputs, source limitations, and user review notes from deck-plan in slide source notes or speaker notes where appropriate.
119
119
 
120
120
  Current state:
121
121
  - ${state}
@@ -126,7 +126,7 @@ Workflow:
126
126
  2. If deck-plan.md is missing or structurally invalid, stop and tell the user to run /revela plan --deck.
127
127
  3. For a new deck, call revela-deck-foundation before adding slide content.
128
128
  4. Read active design rules and needed layouts/components before patching HTML.
129
- 5. Generate chapter by chapter. Keep the HTML valid after every write and preserve existing completed slides.
129
+ 5. Generate one \`htmlWritingBatches\` entry at a time. Each HTML write/edit/apply_patch may add or rewrite at most 5 slide sections. Keep the HTML valid after every write and preserve existing completed slides.
130
130
  6. Each slide must have unique increasing 1-based data-slide-index, a 1920x1080 .slide-canvas, no text overflow, and no unsafe remote asset references.
131
131
  7. Run Artifact QA after writes and fix hard errors before reporting ready.
132
132
 
@@ -152,7 +152,7 @@ export function buildDeckPrompt({
152
152
  Goal:
153
153
  - Treat this as the explicit transition from canonical narrative state to user-directed deck planning.
154
154
  - Use the deck-render prompt mode for design, layout, component, HTML, QA, and deck artifact rules.
155
- - Default behavior is two-stage: first generate or update \`deck-plan.md\` with ordered slide blocks, low-fidelity layout notes, sourceLinks, and caveats, then proceed only when the user chooses to continue.
155
+ - Default behavior is two-stage: first generate or update \`deck-plan.md\` with ordered \`---\` slide blocks, low-fidelity layout notes, sourceLinks, unresolved inputs, source limitations, and user review notes, then proceed only when the user chooses to continue.
156
156
  - Every deck plan must include Cover, Table of Contents, and Closing slides. The TOC must show 3-5 chapter headings that match the deck's slide groups.
157
157
  - Do not write or overwrite \`decks/*.html\` until the user chooses to proceed from the current deck-plan projection.
158
158
  - Do not treat legacy \`writeReadiness.status\`, old review snapshots, approval fields, or existing HTML decks as workflow permission.
@@ -169,7 +169,7 @@ Workflow:
169
169
  4. Call \`revela-decks\` action \`compileDeckPlan\`. This returns a claim/evidence planning packet plus deck-plan authoring requirements; it must not write HTML and does not generate the final slide list. Do not infer render structure from \`DECKS.json.slides[]\`.
170
170
  5. If \`compileDeckPlan\` returns \`skipped\`, report the reason and ask the user whether to continue manually, repair narrative files, or provide missing intent.
171
171
  6. If target slide count, audience, language, output purpose, or visual style is unclear, ask the user for the smallest needed confirmation before writing the plan.
172
- 7. Write \`deck-plan.md\` directly from the planning packet and requirements. Do not use structured upsert tools for normal plan authoring. It must identify the chapter structure first: 3-5 chapter headings, each chapter's slide range, and which non-structural slides belong to each chapter. Each slide block must include positive 1-based \`slideIndex\`, layout, component plan, \`sourceLinks\` for materials/findings/assets/URLs/caveats, and low-fidelity render notes. Do not generate visual images or HTML mockups during planning.
172
+ 7. Write \`deck-plan.md\` directly from the planning packet and requirements. Do not use structured upsert tools for normal plan authoring. It must identify the chapter structure first: 3-5 chapter headings, each chapter's slide range, and which non-structural slides belong to each chapter. Each slide block must use a \`---\` separator with positive 1-based \`slideIndex\`, layout, components, and then \`#### Content Plan\`, \`#### Source Links\` for materials/findings/assets/URLs, and \`#### Design Plan\` with low-fidelity render notes. Do not generate visual images or HTML mockups during planning.
173
173
  8. Stop after presenting the plan unless the user already asked to proceed. Ask whether to continue, revise the plan, or run more research. Do not require an Approval block or \`confirmDeckPlan\` gate; \`confirmDeckPlan\` is compatibility/provenance only.
174
174
  9. Ask for or confirm visual design only after the narrative deck plan exists. For a new deck HTML file, call \`revela-deck-foundation\` first to create the active-design foundation shell; it must not create narrative slide content, choose layouts/components, or read/write \`${DECKS_STATE_FILE}\`.
175
175
  10. Fetch active design rules plus required layouts/components with \`revela-designs read\` as needed before patching slides into the foundation shell. Fetch chart rules before ECharts.
@@ -178,6 +178,7 @@ Workflow:
178
178
  13. Run artifact diagnostics when useful, but do not treat \`writeReadiness\`, cached slide specs, unconfirmed plans, missing research, or stale coverage as workflow blockers.
179
179
  14. Write \`decks/*.html\` when the user chooses to proceed and all deck HTML contract requirements can be satisfied. For new files, patch slide sections between the \`revela-slides\` markers created by \`revela-deck-foundation\`. Generate the artifact chapter by chapter instead of drafting all content slides in one broad pass. Partial decks are allowed during chapter-by-chapter authoring when written slide sections have unique, increasing 1-based \`data-slide-index\` values and valid canvases; do not pad missing planned chapters with filler to match cached \`DECKS.json.slides[]\` length. Keep the HTML file valid after every write, preserve already-written slides, and update one chapter's slide sections at a time.
180
180
  15. For each chapter, make every content slide carry a distinct claim, evidence item, comparison, risk, or action. If a chapter lacks enough substance for its allocated slides, merge weak slides or reduce the slide count instead of creating sparse filler.
181
+ 15a. Use the current \`htmlWritingBatches\` entry as the HTML write boundary. Each HTML write/edit/apply_patch may add or rewrite at most 5 slide sections.
181
182
  16. After each HTML write, the system automatically runs artifact QA before opening Review. If post-write artifact QA reports hard errors, fix them and let QA run again. Review opens only after hard errors pass. Density warnings about thin claim/evidence substance should be reported and improved when useful, but they do not block Review.
182
183
 
183
184
  Deck plan report format:
@@ -189,7 +190,7 @@ Deck plan report format:
189
190
  - Include the required Source Authority and remind that \`DECKS.json.slides[]\` is cache/compatibility data, not the render contract.
190
191
  - Include \`Required structure: Cover + Table of Contents + Closing\` and do not omit any of those slides.
191
192
  - Include a \`Chapters\` section before the slide list. It must list 3-5 TOC headings, their slide ranges, and the non-structural slides assigned to each chapter.
192
- - For every slide block, include: slide index, title, purpose, narrative role, low-fidelity layout note, layout, components, sourceLinks, visual intent, visual brief, caveats/unsupported scope, and render notes.
193
+ - For every slide block, include: slide index, title, purpose, narrative role, low-fidelity layout note, layout, components, sourceLinks, visual intent, visual brief, unresolved inputs, source limitations, user review notes, and render notes.
193
194
  - Use this sketch style or similarly simple ASCII boxes:
194
195
 
195
196
  \`\`\`text
@@ -213,7 +214,7 @@ Supporting claims:
213
214
  Evidence bindings:
214
215
  Visual intent:
215
216
  Visual brief:
216
- Caveats / unsupported scope:
217
+ Unresolved inputs / source limitations / user review notes:
217
218
  \`\`\`
218
219
  - End by asking the user whether to proceed to HTML, revise the plan, or run more research.
219
220
 
@@ -222,7 +223,7 @@ Report format before any HTML write:
222
223
  - Include which deck-plan projection and narrative hash are guiding artifact work.
223
224
  - State that \`revela-decks readDeckPlan\` was called and the current \`deck-plan.md\` slide order/chapter groups are being followed.
224
225
  - For new HTML files, state that \`revela-deck-foundation\` created the foundation shell and identify the output path/design before slide content is patched.
225
- - Include the chapter currently being generated and confirm already-written slides are being preserved.
226
+ - Include the current \`htmlWritingBatches\` entry, its slide indexes, and confirm already-written slides are being preserved.
226
227
  - If technical artifact checks cannot be satisfied, list those blockers separately from narrative/deck-plan diagnostics.
227
228
  - After writing HTML, read the appended \`Artifact QA\` report from the tool output. If it failed, fix hard errors before considering the deck ready for Review.
228
229
 
@@ -233,7 +234,7 @@ Rules:
233
234
  - Visual intent is part of the deck-plan projection. During HTML generation, satisfy the planned component/visual brief using fetched design components; do not collapse planned visuals into prose-only bullets.
234
235
  - Cached deck slide specs in \`DECKS.json\` are legacy projections only. Canonical narrative remains the authority for audience, decision, claims, evidence boundaries, objections, and risks.
235
236
  - Cover, Table of Contents, and Closing are mandatory deck structure. TOC chapter headings must match the chapter grouping used for generation.
236
- - Do not generate the complete deck content in one broad pass. Work chapter by chapter while keeping the artifact valid after each write.
237
+ - Do not generate the complete deck content in one broad pass. Work one \`htmlWritingBatches\` entry at a time while keeping the artifact valid after each write.
237
238
  - Applying evidence candidates or rewriting canonical claims requires explicit user instruction.
238
239
  - If the user requests slide order, layout, component, or visual-intent changes that do not alter meaning, update only \`deck-plan.md\` or artifact-level plan content.
239
240
  - If the user requests claim, evidence, caveat, decision, or recommendation meaning changes, update canonical narrative first, then report alignment diagnostics before compiling a new deck plan.
@@ -295,7 +296,7 @@ Technical blockers only:
295
296
  Report format:
296
297
  - Start with \`Artifact diagnostics: <status>\`.
297
298
  - If technically blocked, list each blocker with file/slide when available, issue type, and smallest repair.
298
- - If warnings exist but no technical blocker exists, say the user can proceed and note residual risks.
299
+ - If warnings exist but no technical blocker exists, say the user can proceed and note residual diagnostics.
299
300
  - Include coverage-driven make diagnostics when returned: whether the active deck artifact coverage is current/stale/partial/missing, which required claims are missing, which claims are affected, and the next command/action recommended by the tool.
300
301
  - Report \`narrative_gap\` warnings as story-structure risks such as weak so-what, missing risk/assumption handling, conclusion before support, missing audience framing, or abrupt transition.
301
302
  - Do not invent evidence or silently downgrade blockers. Use the tool result as authoritative.
@@ -14,6 +14,7 @@ export const DECK_PLAN_INDEX_PATH = "deck-plan/index.md"
14
14
  export const DECK_PLAN_SLIDES_DIR = "deck-plan/slides"
15
15
  export const LEGACY_DECK_PLAN_ARTIFACT_PATH = "decks/deck-plan.md"
16
16
  export const DECK_PLAN_ARTIFACT_PATH = DECK_PLAN_MARKDOWN_PATH
17
+ export const MAX_HTML_SLIDES_PER_BATCH = 5
17
18
 
18
19
  export interface DeckPlanArtifactInput {
19
20
  deck: DeckSpec
@@ -69,11 +70,21 @@ export interface DeckPlanProjection {
69
70
  designName?: string
70
71
  outputPath?: string
71
72
  slides: DeckPlanSlideProjection[]
73
+ htmlWritingBatches: DeckPlanHtmlWritingBatch[]
74
+ htmlWritingInstruction: string
72
75
  graphNodes: Array<{ id: string; type: WorkspaceGraphNodeType; file: string }>
73
76
  graphRelations: VaultRelation[]
74
77
  diagnostics: DeckPlanProjectionDiagnostic[]
75
78
  }
76
79
 
80
+ export interface DeckPlanHtmlWritingBatch {
81
+ label: string
82
+ chapterTitle: string
83
+ slideIndexes: number[]
84
+ maxSlides: number
85
+ instructions: string
86
+ }
87
+
77
88
  export interface DeckPlanSlideProjection {
78
89
  path: string
79
90
  absolutePath: string
@@ -283,6 +294,7 @@ export function readDeckPlanProjection(workspaceRoot: string, expected?: { narra
283
294
  file: slide.path,
284
295
  source: "inline" as const,
285
296
  })))
297
+ const htmlWritingBatches = buildHtmlWritingBatches(slides)
286
298
  return {
287
299
  path,
288
300
  absolutePath,
@@ -294,6 +306,8 @@ export function readDeckPlanProjection(workspaceRoot: string, expected?: { narra
294
306
  designName: stringField(parsed.frontmatter, "designName") || stringField(parsed.frontmatter, "design"),
295
307
  outputPath: stringField(parsed.frontmatter, "outputPath") || stringField(parsed.frontmatter, "output"),
296
308
  slides,
309
+ htmlWritingBatches,
310
+ htmlWritingInstruction: htmlWritingInstruction(),
297
311
  graphNodes,
298
312
  graphRelations,
299
313
  diagnostics,
@@ -470,31 +484,35 @@ function writeDeckPlanSingleFile(workspaceRoot: string, input: {
470
484
 
471
485
  function renderDeckPlanSlideBlock(slide: DeckPlanSlideProjection, visualIntent?: DeckPlanSlideUpsertInput["visualIntent"]): string {
472
486
  const lines: string[] = []
473
- lines.push(`### Slide ${slide.slideIndex ?? "?"} — ${slide.title}`)
474
- lines.push("")
475
- lines.push(`- Id: ${slide.id}`)
476
- lines.push(`- Chapter: ${slide.chapter || "Unassigned"}`)
477
- lines.push(`- Role: ${slide.narrativeRole || "Not specified"}`)
478
- lines.push(`- Structural: ${slide.structural ? "true" : "false"}`)
479
- lines.push(`- Layout: ${slide.layout || "unspecified"}`)
480
- lines.push(`- Components: ${slide.components.join(", ") || "none"}`)
481
- lines.push("")
482
- lines.push("#### Visual Intent")
487
+ lines.push("---")
488
+ lines.push(`slideIndex: ${slide.slideIndex ?? ""}`)
489
+ lines.push(`id: ${slide.id}`)
490
+ lines.push(`title: ${yamlScalar(slide.title)}`)
491
+ lines.push(`chapter: ${yamlScalar(slide.chapter || "Unassigned")}`)
492
+ lines.push(`role: ${yamlScalar(slide.narrativeRole || "Not specified")}`)
493
+ lines.push(`structural: ${slide.structural ? "true" : "false"}`)
494
+ lines.push(`layout: ${slide.layout || "unspecified"}`)
495
+ lines.push(`components: ${slide.components.join(", ") || "none"}`)
496
+ lines.push("---")
483
497
  lines.push("")
484
- if (visualIntent) lines.push(renderVisualIntent(visualIntent))
485
- else lines.push("- Brief: Not specified.")
498
+ lines.push("#### Content Plan")
486
499
  lines.push("")
487
- lines.push("#### Component Plan")
500
+ lines.push(`- Message: ${slide.narrativeRole || "Not specified."}`)
501
+ lines.push(`- Role: ${slide.narrativeRole || "Not specified"}`)
502
+ lines.push("- Speaker notes: Not specified.")
488
503
  lines.push("")
489
- for (const component of slide.componentPlan) lines.push(renderComponentPlanMarkdown(component, 5))
490
504
  lines.push("#### Source Links")
491
505
  lines.push("")
492
506
  lines.push(renderSourceLinksMarkdown(slide.sourceLinks))
493
507
  lines.push("")
494
- lines.push("#### Caveats")
508
+ lines.push("#### Design Plan")
495
509
  lines.push("")
496
- if (slide.caveats.length === 0) lines.push("- None.")
497
- else for (const caveat of slide.caveats) lines.push(`- ${caveat}`)
510
+ lines.push(`- Layout: ${slide.layout || "unspecified"}`)
511
+ lines.push(`- Components: ${slide.components.join(", ") || "none"}`)
512
+ lines.push("- Visual intent:")
513
+ lines.push(...indentMultiline(visualIntent ? renderVisualIntent(visualIntent) : "- Brief: Not specified."))
514
+ lines.push("")
515
+ for (const component of slide.componentPlan) lines.push(renderComponentPlanMarkdown(component, 5))
498
516
  lines.push("")
499
517
  return lines.join("\n")
500
518
  }
@@ -525,7 +543,6 @@ function renderSourceLinksMarkdown(sourceLinks: DeckPlanSourceLinks): string {
525
543
  ["Findings", sourceLinks.findings],
526
544
  ["Assets", sourceLinks.assets],
527
545
  ["URLs", sourceLinks.urls],
528
- ["Caveats", sourceLinks.caveats],
529
546
  ] as const) {
530
547
  lines.push(`${label}:`)
531
548
  if (values.length === 0) lines.push("- None.")
@@ -575,6 +592,8 @@ function readDeckPlanSlideFiles(workspaceRoot: string, knownNodeIds?: Set<string
575
592
  }
576
593
 
577
594
  function readDeckPlanSlidesFromSingleFile(workspaceRoot: string, absolutePath: string, markdown: string, knownNodeIds?: Set<string>): DeckPlanSlideProjection[] {
595
+ const slideBlocks = readDeckPlanSeparatorSlidesFromSingleFile(workspaceRoot, absolutePath, markdown, knownNodeIds)
596
+ if (slideBlocks.length > 0) return slideBlocks
578
597
  const path = relativePath(workspaceRoot, absolutePath)
579
598
  const body = parseVaultFrontmatter(markdown).body
580
599
  const matches = [...body.matchAll(/^[ \t]*###\s+Slide\s+(\d+)\s+(?:—|-)\s+(.+?)\s*$/gm)]
@@ -620,6 +639,58 @@ function readDeckPlanSlidesFromSingleFile(workspaceRoot: string, absolutePath: s
620
639
  return slides.sort((a, b) => (a.slideIndex ?? Number.MAX_SAFE_INTEGER) - (b.slideIndex ?? Number.MAX_SAFE_INTEGER))
621
640
  }
622
641
 
642
+ function readDeckPlanSeparatorSlidesFromSingleFile(workspaceRoot: string, absolutePath: string, markdown: string, knownNodeIds?: Set<string>): DeckPlanSlideProjection[] {
643
+ const path = relativePath(workspaceRoot, absolutePath)
644
+ const body = parseVaultFrontmatter(markdown).body
645
+ const slidesHeading = /^[ \t]*##\s+Slides\s*$/mi.exec(body)
646
+ if (!slidesHeading || slidesHeading.index === undefined) return []
647
+ const headingEnd = body.indexOf("\n", slidesHeading.index)
648
+ const slidesStart = headingEnd === -1 ? slidesHeading.index + slidesHeading[0].length : headingEnd + 1
649
+ const rest = body.slice(slidesStart)
650
+ const nextSection = rest.search(/^[ \t]*##\s+(?!#)/m)
651
+ const slidesRegion = nextSection === -1 ? rest : rest.slice(0, nextSection)
652
+ const metadataMatches = [...slidesRegion.matchAll(/^[ \t]*---[ \t]*\n[\s\S]*?\n[ \t]*---[ \t]*(?:\n|$)/gm)]
653
+ const slides: DeckPlanSlideProjection[] = []
654
+ for (let i = 0; i < metadataMatches.length; i++) {
655
+ const match = metadataMatches[i]
656
+ const start = match.index ?? 0
657
+ const next = i + 1 < metadataMatches.length ? metadataMatches[i + 1].index ?? slidesRegion.length : slidesRegion.length
658
+ const block = slidesRegion.slice(start, next).trim()
659
+ const parsed = parseVaultFrontmatter(block)
660
+ const slideIndex = numberField(parsed.frontmatter, "slideIndex")
661
+ const title = stringField(parsed.frontmatter, "title") || firstHeading(parsed.body) || `Slide ${slideIndex ?? i + 1}`
662
+ const fields = parseSlideBlockFields(parsed.body)
663
+ const sourceLinks = normalizeSourceLinks(parseDeckPlanSourceLinks(singleFileSubsection(block, "Source Links")))
664
+ const narrativeLinks = parseDeckPlanNarrativeLinks(singleFileSubsection(block, "Narrative Links") || block, knownNodeIds)
665
+ const links = sourceLinksToNarrativeLinks(sourceLinks, narrativeLinks)
666
+ const componentPlan = parseDeckPlanComponentPlan(singleFileSubsection(block, "Component Plan") || singleFileSubsection(block, "Design Plan"))
667
+ slides.push({
668
+ path,
669
+ absolutePath,
670
+ id: stringField(parsed.frontmatter, "id") || fields.id || `slide-${slugify(title)}`,
671
+ slideIndex,
672
+ title,
673
+ chapter: stringField(parsed.frontmatter, "chapter") || fields.chapter || "",
674
+ layout: stringField(parsed.frontmatter, "layout") || fields.layout || "",
675
+ components: arrayField(parsed.frontmatter, "components").length > 0 ? arrayField(parsed.frontmatter, "components") : parseCsv(fields.components || componentPlan.map((component) => component.name).join(", ")),
676
+ componentPlan,
677
+ structural: booleanField(parsed.frontmatter, "structural", fields.structural === "true" || fields.structural === "yes"),
678
+ narrativeRole: stringField(parsed.frontmatter, "role") || stringField(parsed.frontmatter, "narrativeRole") || fields.role || fields.narrativeRole || "",
679
+ markdown: block,
680
+ frontmatter: parsed.frontmatter,
681
+ sections: parseMarkdownSections(block),
682
+ links,
683
+ sourceLinks,
684
+ caveats: uniqueStrings([...parseBulletText(singleFileSubsection(block, "Caveats")), ...sourceLinks.caveats]),
685
+ })
686
+ }
687
+ return slides.sort((a, b) => (a.slideIndex ?? Number.MAX_SAFE_INTEGER) - (b.slideIndex ?? Number.MAX_SAFE_INTEGER))
688
+ }
689
+
690
+ function firstHeading(markdown: string): string {
691
+ return /^#{1,6}\s+(.+?)\s*$/m.exec(markdown)?.[1]?.trim() ?? ""
692
+ }
693
+
623
694
  function parseSlideBlockFields(block: string): Record<string, string> {
624
695
  const fields: Record<string, string> = {}
625
696
  for (const rawLine of block.split(/\r?\n/)) {
@@ -787,9 +858,53 @@ function deckPlanIndexDiagnostics(slides: DeckPlanSlideProjection[]): DeckPlanPr
787
858
  return diagnostics
788
859
  }
789
860
 
861
+ function buildHtmlWritingBatches(slides: DeckPlanSlideProjection[]): DeckPlanHtmlWritingBatch[] {
862
+ const ordered = slides
863
+ .filter((slide) => Number.isInteger(slide.slideIndex) && (slide.slideIndex ?? 0) > 0)
864
+ .sort((a, b) => (a.slideIndex ?? Number.MAX_SAFE_INTEGER) - (b.slideIndex ?? Number.MAX_SAFE_INTEGER))
865
+ const chapterGroups: Array<{ chapterTitle: string; slideIndexes: number[] }> = []
866
+ for (const slide of ordered) {
867
+ const chapterTitle = slide.chapter || "Unassigned"
868
+ const current = chapterGroups[chapterGroups.length - 1]
869
+ if (current && current.chapterTitle === chapterTitle) current.slideIndexes.push(slide.slideIndex!)
870
+ else chapterGroups.push({ chapterTitle, slideIndexes: [slide.slideIndex!] })
871
+ }
872
+ const batches: DeckPlanHtmlWritingBatch[] = []
873
+ for (const group of chapterGroups) {
874
+ const chunks = chunkNumbers(group.slideIndexes, MAX_HTML_SLIDES_PER_BATCH)
875
+ for (let index = 0; index < chunks.length; index += 1) {
876
+ const chunk = chunks[index]
877
+ const chapterSuffix = chunks.length > 1 ? ` part ${index + 1}` : ""
878
+ const label = batches.length === 0
879
+ ? `Initial shell and ${group.chapterTitle}${chapterSuffix}`
880
+ : `${group.chapterTitle}${chapterSuffix}`
881
+ batches.push({
882
+ label,
883
+ chapterTitle: group.chapterTitle,
884
+ slideIndexes: chunk,
885
+ maxSlides: MAX_HTML_SLIDES_PER_BATCH,
886
+ instructions: batches.length === 0
887
+ ? `Create or update the foundation if needed, then write only slide sections ${formatSlideRange(chunk)}. Do not add or rewrite more than ${MAX_HTML_SLIDES_PER_BATCH} slide sections in this write.`
888
+ : `Patch only slide sections ${formatSlideRange(chunk)}, preserve previously written slides, and keep the file valid after the patch. Do not add or rewrite more than ${MAX_HTML_SLIDES_PER_BATCH} slide sections in this write.`,
889
+ })
890
+ }
891
+ }
892
+ return batches
893
+ }
894
+
895
+ function chunkNumbers(values: number[], size: number): number[][] {
896
+ const chunks: number[][] = []
897
+ for (let index = 0; index < values.length; index += size) chunks.push(values.slice(index, index + size))
898
+ return chunks
899
+ }
900
+
901
+ function htmlWritingInstruction(): string {
902
+ return `Before every HTML write/edit/apply_patch, follow htmlWritingBatches and add or rewrite at most ${MAX_HTML_SLIDES_PER_BATCH} <section class="slide"> blocks. Run Artifact QA after each batch before continuing.`
903
+ }
904
+
790
905
  function slideDiagnostics(slide: DeckPlanSlideProjection, knownNodeIds?: Set<string>): DeckPlanProjectionDiagnostic[] {
791
906
  const diagnostics: DeckPlanProjectionDiagnostic[] = []
792
- if (!slide.structural && slide.links.length === 0 && slide.caveats.length === 0) diagnostics.push({ severity: "warning", code: "slide_source_link_missing", message: `Non-structural deck-plan slide ${slide.id} has no source, research, asset, or caveat link.`, file: slide.path, nodeId: slide.id })
907
+ if (!slide.structural && linksCount(slide.sourceLinks) === 0) diagnostics.push({ severity: "warning", code: "slide_source_link_missing", message: `Non-structural deck-plan slide ${slide.id} has no material, finding, asset, or URL source link.`, file: slide.path, nodeId: slide.id })
793
908
  if (!slide.layout) diagnostics.push({ severity: "warning", code: "slide_layout_missing", message: `Deck-plan slide ${slide.id} is missing a layout.`, file: slide.path, nodeId: slide.id })
794
909
  if (slide.components.length === 0) diagnostics.push({ severity: "warning", code: "slide_components_missing", message: `Deck-plan slide ${slide.id} has no component names in frontmatter.`, file: slide.path, nodeId: slide.id })
795
910
  if (slide.componentPlan.length === 0) diagnostics.push({ severity: "warning", code: "slide_component_plan_missing", message: `Deck-plan slide ${slide.id} is missing structured ## Component Plan entries.`, file: slide.path, nodeId: slide.id })
@@ -847,7 +962,7 @@ function validateDeckPlanSlideUpsert(input: DeckPlanSlideUpsertInput, options: {
847
962
  const visual = normalizeVisualIntent(input.visualIntent)
848
963
  if (visual.component && !componentNames.has(visual.component)) diagnostics.push(errorDiagnostic("slide_visual_component_missing", `visualIntent.component '${visual.component}' is not present in component plan.`, nodeId))
849
964
  const sourceLinks = sourceLinksForInput(input)
850
- if (!input.structural && linksCount(sourceLinks) === 0) diagnostics.push({ severity: "warning", code: "slide_source_link_missing", message: "Non-structural slides should include at least one material, finding, asset, URL, or caveat source link.", nodeId })
965
+ if (!input.structural && linksCount(sourceLinks) === 0) diagnostics.push({ severity: "warning", code: "slide_source_link_missing", message: "Non-structural slides should include at least one material, finding, asset, or URL source link.", nodeId })
851
966
  return diagnostics
852
967
  }
853
968
 
@@ -887,7 +1002,7 @@ function validateComponentInput(component: DeckPlanSlideUpsertComponentInput, co
887
1002
  }
888
1003
 
889
1004
  function linksCount(sourceLinks: DeckPlanSourceLinks): number {
890
- return sourceLinks.materials.length + sourceLinks.findings.length + sourceLinks.assets.length + sourceLinks.urls.length + sourceLinks.caveats.length
1005
+ return sourceLinks.materials.length + sourceLinks.findings.length + sourceLinks.assets.length + sourceLinks.urls.length
891
1006
  }
892
1007
 
893
1008
  function errorDiagnostic(code: string, message: string, nodeId?: string): DeckPlanProjectionDiagnostic {
@@ -1017,12 +1132,6 @@ function renderDeckPlanSlideMarkdown(input: DeckPlanSlideUpsertInput & { id: str
1017
1132
  lines.push("")
1018
1133
  }
1019
1134
  lines.push(renderSourceLinksMarkdown(sourceLinksForInput(input)).replace(/^####/gm, "##"))
1020
- lines.push("## Caveats")
1021
- lines.push("")
1022
- const caveats = input.caveats?.filter((item) => item.trim()) ?? []
1023
- if (caveats.length === 0) lines.push("- None.")
1024
- else for (const caveat of caveats) lines.push(`- ${caveat.trim()}`)
1025
- lines.push("")
1026
1135
  return lines.join("\n")
1027
1136
  }
1028
1137
 
@@ -1083,10 +1192,10 @@ function renderMinimalDeckPlanIndex(narrativeHash: string | undefined, slides: D
1083
1192
  if (evidenceIds.length === 0) lines.push("- No evidence links planned yet.")
1084
1193
  else for (const id of evidenceIds) lines.push(`- [[${id}]]`)
1085
1194
  lines.push("")
1086
- lines.push("## Boundary / Risk Treatment")
1195
+ lines.push("## Source Limitations")
1087
1196
  lines.push("")
1088
1197
  const boundaryIds = uniqueStrings(slides.flatMap((slide) => slide.links.filter((link) => link.relation === "addresses_risk" || link.relation === "answers_objection" || link.relation === "mentions_gap").map((link) => link.id)))
1089
- if (boundaryIds.length === 0) lines.push("- No risk, objection, or gap links planned yet.")
1198
+ if (boundaryIds.length === 0) lines.push("- No legacy risk, objection, or gap links planned.")
1090
1199
  else for (const id of boundaryIds) lines.push(`- [[${id}]]`)
1091
1200
  lines.push("")
1092
1201
  lines.push("## Chapter Writing Batches")
@@ -1130,8 +1239,8 @@ function booleanField(frontmatter: Record<string, string | string[] | boolean>,
1130
1239
 
1131
1240
  function arrayField(frontmatter: Record<string, string | string[] | boolean>, key: string): string[] {
1132
1241
  const value = frontmatter[key]
1133
- if (Array.isArray(value)) return value.map((item) => item.trim()).filter(Boolean)
1134
- if (typeof value === "string" && value.trim()) return value.split(",").map((item) => item.trim()).filter(Boolean)
1242
+ if (Array.isArray(value)) return value.map((item) => item.trim()).filter((item) => item && item.toLowerCase() !== "none")
1243
+ if (typeof value === "string" && value.trim()) return value.split(",").map((item) => item.trim()).filter((item) => item && item.toLowerCase() !== "none")
1135
1244
  return []
1136
1245
  }
1137
1246
 
@@ -1265,8 +1374,8 @@ function renderDeckPlanMarkdown(input: DeckPlanArtifactInput): string {
1265
1374
  lines.push("")
1266
1375
  lines.push("- Write one `<section class=\"slide\" data-slide-index=\"N\">` per planned slide in the completed deck, using positive 1-based slide indexes that are unique and strictly increase in DOM order. Partial chapter-by-chapter drafts may contain only the written prefix/range.")
1267
1376
  lines.push("- Keep every rendered slide exactly 1920x1080px with no page-level scrollbars or hidden overflow.")
1268
- lines.push("- Preserve claim-led chapters, visual intent, evidence ids, source trace, supported scope, unsupported scope, caveats, and strength.")
1269
- lines.push("- Generate HTML chapter by chapter; do not draft a full 5+ slide deck in one broad write or patch.")
1377
+ lines.push("- Preserve claim-led chapters, visual intent, evidence ids, source trace, source limitations, unresolved inputs, and user review notes.")
1378
+ lines.push(`- Generate HTML in the listed writing batches; do not add or rewrite more than ${MAX_HTML_SLIDES_PER_BATCH} slide sections in one write or patch.`)
1270
1379
  lines.push("")
1271
1380
  lines.push("## Chapter Map")
1272
1381
  lines.push("")
@@ -1284,14 +1393,17 @@ function renderDeckPlanMarkdown(input: DeckPlanArtifactInput): string {
1284
1393
  }
1285
1394
  lines.push("## Chapter Writing Batches")
1286
1395
  lines.push("")
1287
- lines.push("Use these batches for HTML generation. Keep the HTML valid after every batch and preserve previously written slides.")
1396
+ lines.push(`Use these batches for HTML generation. Each batch is capped at ${MAX_HTML_SLIDES_PER_BATCH} slide sections. Keep the HTML valid after every batch and preserve previously written slides.`)
1288
1397
  lines.push("")
1289
1398
  if (input.renderPlan) {
1290
- for (const batch of input.renderPlan.chapterWritingBatches) lines.push(`- ${batch.label}: ${batch.chapterTitle}, slides ${formatSlideRange(batch.slideIndexes)}. ${batch.instructions}`)
1399
+ for (const batch of input.renderPlan.chapterWritingBatches) lines.push(`- ${batch.label}: ${batch.chapterTitle}, slides ${formatSlideRange(batch.slideIndexes)}; max ${batch.maxSlides} slides. ${batch.instructions}`)
1291
1400
  } else {
1292
1401
  input.chapters.forEach((chapter, index) => {
1293
1402
  const prefix = index === 0 ? "Initial shell and first chapter" : `Chapter batch ${index + 1}`
1294
- lines.push(`- ${prefix}: ${chapter.title}, slides ${formatSlideRange(chapter.slideIndexes)}.`)
1403
+ for (const [chunkIndex, chunk] of chunkNumbers(chapter.slideIndexes, MAX_HTML_SLIDES_PER_BATCH).entries()) {
1404
+ const suffix = chunkIndex === 0 ? "" : ` part ${chunkIndex + 1}`
1405
+ lines.push(`- ${prefix}${suffix}: ${chapter.title}, slides ${formatSlideRange(chunk)}; max ${MAX_HTML_SLIDES_PER_BATCH} slides.`)
1406
+ }
1295
1407
  })
1296
1408
  }
1297
1409
  if (input.renderPlan) {
@@ -93,6 +93,7 @@ export interface RenderPlanWritingBatch {
93
93
  label: string
94
94
  chapterTitle: string
95
95
  slideIndexes: number[]
96
+ maxSlides: number
96
97
  instructions: string
97
98
  }
98
99
 
@@ -112,6 +113,7 @@ export interface RenderPlanContract {
112
113
 
113
114
  type VisualIntentKind = "hero" | "toc" | "metric-stat" | "evidence-table" | "comparison-grid" | "risk-matrix" | "steps" | "text-only"
114
115
  type ClaimChapterSlideKind = "framing" | "evidence" | "implication"
116
+ const MAX_HTML_SLIDES_PER_BATCH = 5
115
117
 
116
118
  interface VisualIntent {
117
119
  kind: VisualIntentKind
@@ -251,10 +253,11 @@ function buildDeckPlanRequirements(narrativeHash: string): DeckPlanRequirements
251
253
  "Each substantive chapter should have framing, proof, and implication/boundary coverage.",
252
254
  "Chapter divider or chapter TOC slides may use the toc component as structural wayfinding.",
253
255
  "Do not create filler slides, repeated thesis pages, or generic bridge slides.",
254
- "Preserve evidence ids, source trace, supported scope, unsupported scope, caveats, and strength where available.",
256
+ "Preserve evidence ids, source trace, source limitations, unresolved inputs, and user review notes where available.",
255
257
  "Do not render internal labels such as Evidence gap:, Unsupported scope:, Caveat:, Missing Data, or Evidence Boundary in executive body copy.",
256
258
  "Do not infer plan structure from DECKS.json slides[]; it is compatibility cache only.",
257
- "Use sourceLinks in slide blocks for materials, findings, assets, URLs, and caveats; do not use canonical ## Relations in deck-plan files.",
259
+ "Use sourceLinks in slide blocks for materials, findings, assets, and URLs; do not use canonical ## Relations in deck-plan files.",
260
+ "Use `---` slide separators under ## Slides with slide-local metadata, followed by #### Content Plan, #### Source Links, and #### Design Plan.",
258
261
  ],
259
262
  requiredSections: [
260
263
  "Goal",
@@ -283,7 +286,7 @@ export function buildRenderPlanContract(deck: DeckSpec, chapters: DeckPlanChapte
283
286
  "Render chapter divider slides with the toc component when slideKind is chapter-divider.",
284
287
  "Chapter divider and global TOC slides are structural wayfinding and do not count toward central-claim substance.",
285
288
  "Each central claim chapter needs non-structural framing, proof, and implication/boundary slides unless the current deck-plan projection explicitly says otherwise.",
286
- "Generate HTML chapter by chapter, preserving valid HTML and already-written slides after every batch.",
289
+ `Generate HTML in chapter-bounded batches of at most ${MAX_HTML_SLIDES_PER_BATCH} slides, preserving valid HTML and already-written slides after every batch.`,
287
290
  ],
288
291
  htmlIdentityContract: [
289
292
  "Every written slide section uses class slide and a positive 1-based data-slide-index.",
@@ -306,18 +309,38 @@ export function buildRenderPlanContract(deck: DeckSpec, chapters: DeckPlanChapte
306
309
  allowedStructuralSlides: chapter.sourceClaimId ? ["chapter-divider", "toc"] : ["cover", "toc", "ask"],
307
310
  }
308
311
  }),
309
- chapterWritingBatches: chapters.map((chapter, index) => ({
310
- label: index === 0 ? "Initial shell and first chapter" : `Chapter batch ${index + 1}`,
311
- chapterTitle: chapter.title,
312
- slideIndexes: chapter.slideIndexes,
313
- instructions: index === 0
314
- ? "Create the stable HTML shell, required structural slides, and this first chapter range only."
315
- : "Patch exactly this chapter range, preserve previously written slides, and keep the file valid after the patch.",
316
- })),
312
+ chapterWritingBatches: chapterWritingBatches(chapters),
317
313
  slideRenderMetadata: deck.slides.map((slide) => slideRenderMetadata(slide, chapters)),
318
314
  }
319
315
  }
320
316
 
317
+ function chapterWritingBatches(chapters: DeckPlanChapter[]): RenderPlanWritingBatch[] {
318
+ const batches: RenderPlanWritingBatch[] = []
319
+ for (const chapter of chapters) {
320
+ const chunks = chunkNumbers(chapter.slideIndexes, MAX_HTML_SLIDES_PER_BATCH)
321
+ for (let index = 0; index < chunks.length; index += 1) {
322
+ const chunk = chunks[index]
323
+ const chapterSuffix = chunks.length > 1 ? ` part ${index + 1}` : ""
324
+ batches.push({
325
+ label: batches.length === 0 ? `Initial shell and ${chapter.title}${chapterSuffix}` : `${chapter.title}${chapterSuffix}`,
326
+ chapterTitle: chapter.title,
327
+ slideIndexes: chunk,
328
+ maxSlides: MAX_HTML_SLIDES_PER_BATCH,
329
+ instructions: batches.length === 0
330
+ ? `Create the stable HTML shell if needed, then write only slide sections ${formatSlideRange(chunk)}. Do not add or rewrite more than ${MAX_HTML_SLIDES_PER_BATCH} slide sections in this write.`
331
+ : `Patch only slide sections ${formatSlideRange(chunk)}, preserve previously written slides, and keep the file valid after the patch. Do not add or rewrite more than ${MAX_HTML_SLIDES_PER_BATCH} slide sections in this write.`,
332
+ })
333
+ }
334
+ }
335
+ return batches
336
+ }
337
+
338
+ function chunkNumbers(values: number[], size: number): number[][] {
339
+ const chunks: number[][] = []
340
+ for (let index = 0; index < values.length; index += size) chunks.push(values.slice(index, index + size))
341
+ return chunks
342
+ }
343
+
321
344
  function slideRenderMetadata(slide: SlideSpec, chapters: DeckPlanChapter[]): RenderPlanSlideMetadata {
322
345
  const chapter = chapters.find((item) => item.slideIndexes.includes(slide.index))
323
346
  const slideKind = renderPlanSlideKind(slide, chapter)
@@ -1115,6 +1138,13 @@ function claimChapterTitle(claim: NarrativeClaim): string {
1115
1138
  return title.endsWith(".") ? title.slice(0, -1) : title
1116
1139
  }
1117
1140
 
1141
+ function formatSlideRange(indexes: number[]): string {
1142
+ if (indexes.length === 0) return "none"
1143
+ const sorted = [...indexes].sort((a, b) => a - b)
1144
+ if (sorted.length === 1) return String(sorted[0])
1145
+ return `${sorted[0]}-${sorted[sorted.length - 1]}`
1146
+ }
1147
+
1118
1148
  function hasCurrentApprovalOrOverride(narrative: NarrativeStateV1, narrativeHash: string): boolean {
1119
1149
  return narrative.approvals.some((approval) => approval.narrativeHash === narrativeHash && (approval.scope === "narrative" && approval.approvedBy === "user" || approval.scope === "render_override" || approval.approvedBy === "override"))
1120
1150
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyber-dash-tech/revela",
3
- "version": "0.18.2",
3
+ "version": "0.18.3",
4
4
  "description": "OpenCode plugin for trusted narrative artifacts from local sources, research, and evidence",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
@@ -2,7 +2,7 @@
2
2
  "mcpServers": {
3
3
  "revela": {
4
4
  "command": "npx",
5
- "args": ["-y", "@cyber-dash-tech/revela@0.18.2", "mcp"]
5
+ "args": ["-y", "@cyber-dash-tech/revela@0.18.3", "mcp"]
6
6
  }
7
7
  }
8
8
  }
@@ -19,13 +19,14 @@ Use this skill when the user asks to plan, make, generate, or update a Revela de
19
19
  1. For planning requests, inspect local materials/reviews/research, then write or repair `deck-plan.md` directly. Do not use structured upsert tools for normal plan authoring.
20
20
  2. Call `revela_design_list`, `revela_design_read` with `section: "rules"`, and `revela_design_inventory` before selecting layouts/components; use the returned layout slots and component nesting hints in `deck-plan.md`.
21
21
  3. Call `revela_read_deck_plan` after writing or repairing `deck-plan.md`. If diagnostics report layout, slot, component, `children`, or `sourceLinks` issues, patch the Markdown directly and call `revela_read_deck_plan` again.
22
- 4. Call `revela_read_deck_plan` before HTML generation and follow the current projection. `revela_read_deck_plan` is QA/diagnostics, not a writer.
22
+ 4. Call `revela_read_deck_plan` before HTML generation and follow the current projection. Read `htmlWritingBatches` from the result before any HTML write. `revela_read_deck_plan` is QA/diagnostics, not a writer.
23
23
  5. For new HTML files, call `revela_create_deck_foundation`.
24
24
  6. Before patching slide HTML, read the specific layouts/components with `revela_design_read_layout` and `revela_design_read_component`; fetch chart rules before ECharts.
25
25
  7. Patch slides into the foundation between Revela slide markers. Preserve positive 1-based `data-slide-index` values. Every slide must have exactly one direct `.slide-canvas` child.
26
- 8. Generate chapter by chapter. Keep the HTML valid after each write.
27
- 9. After every HTML write, call `revela_run_deck_qa` and repair hard errors before review or export.
26
+ 8. Generate one `htmlWritingBatches` entry at a time. A single HTML write/edit/apply_patch may add or rewrite at most 5 slide sections. If a chapter is longer than 5 slides, use the consecutive batch parts returned by `revela_read_deck_plan`.
27
+ 9. Keep the HTML valid after each write.
28
+ 10. After every HTML write, call `revela_run_deck_qa` and repair hard errors before review or export.
28
29
 
29
30
  ## Deck Plan Requirements
30
31
 
31
- Every normal deck plan should include Cover, Table of Contents, and Closing. Use 3-5 chapter headings, explicit slide ranges, `sourceLinks` for materials/findings/assets/URLs/caveats, visual intent, caveats, and unresolved inputs. Use `box.children` when multiple child components support one semantic idea; do not duplicate the same child as both nested and top-level.
32
+ Every normal deck plan should include Cover, Table of Contents, and Closing. Use 3-5 chapter headings, explicit slide ranges, and `---` slide separators under `## Slides`. Each slide block should have slide-local metadata followed by `#### Content Plan`, `#### Source Links` for materials/findings/assets/URLs, and `#### Design Plan` for layout, component plan, visual intent, placement notes, and render notes. Use unresolved inputs, source limitations, and user review notes instead of AI-authored caveat/risk judgement. Use `box.children` when multiple child components support one semantic idea; do not duplicate the same child as both nested and top-level.
package/skill/SKILL.md CHANGED
@@ -78,12 +78,14 @@ Batches, slide plan, visual intent, evidence trace, boundaries, and narrative
78
78
  links. Do not call `compileDeckPlan` merely to understand an existing plan, and
79
79
  do not reinterpret cached `DECKS.json.slides[]` as the render contract.
80
80
 
81
- Decks with 5 or more slides must be generated chapter by chapter, not in one
82
- broad `write` or `apply_patch` call. The first HTML write may create the stable
83
- HTML shell, structural slides, and the first chapter only. Subsequent writes
84
- must patch one chapter at a time, preserving already-written slides and keeping
85
- the file valid after every write. Do not continue to the next chapter while the
86
- current file has Artifact QA hard errors.
81
+ Deck HTML must be generated in bounded batches, not in one broad `write` or
82
+ `apply_patch` call. Follow `htmlWritingBatches` from `readDeckPlan`; each HTML
83
+ write/edit/apply_patch may add or rewrite at most 5 `<section class="slide">`
84
+ blocks. The first HTML write may create the stable HTML shell, but its slide
85
+ sections are still capped at 5. Subsequent writes must patch only the next
86
+ listed batch, preserving already-written slides and keeping the file valid after
87
+ every write. Do not continue to the next batch while the current file has
88
+ Artifact QA hard errors.
87
89
 
88
90
  ---
89
91
 
@@ -118,15 +120,17 @@ Before writing HTML, the deck-plan projection should include:
118
120
 
119
121
  - `deck-plan.md` with `designName`, `outputPath` when known, chapter map, and
120
122
  ordered slide blocks.
121
- - Each slide block uses `sourceLinks` for materials, findings, assets, URLs,
122
- and caveats. Legacy narrative links may be read for compatibility, but new
123
+ - Each slide block uses `sourceLinks` for materials, findings, assets, and URLs.
124
+ Legacy narrative/caveat links may be read for compatibility, but new
123
125
  plans should not use them.
126
+ - Use `---` slide separators under `## Slides` with slide-local metadata, then
127
+ `#### Content Plan`, `#### Source Links`, and `#### Design Plan`.
124
128
  - `Required structure: Cover + Table of Contents + Closing`.
125
129
  - A `Chapters` section with 3-5 TOC headings, slide ranges, and the
126
130
  non-structural slides assigned to each chapter.
127
131
  - One row/block per slide with title, purpose, narrative role, content summary,
128
132
  layout, components, `sourceLinks`, visual intent, visual brief, render notes,
129
- and caveats/unsupported scope.
133
+ unresolved inputs, source limitations, and user review notes.
130
134
  - Source Authority, Chapter Map, Slides, Unresolved Inputs, and HTML Contract
131
135
  sections.
132
136
  - A low-fidelity layout sketch for every slide when requested by the handoff
@@ -167,14 +171,16 @@ a required workflow gate.
167
171
 
168
172
  ## Chapter-By-Chapter Generation
169
173
 
170
- Generate the artifact chapter by chapter. Never draft a full 5+ slide deck in
171
- one broad `write`, `edit`, or `apply_patch` call.
174
+ Generate the artifact by following `htmlWritingBatches`. Never add or rewrite
175
+ more than 5 slide sections in one `write`, `edit`, or `apply_patch` call.
172
176
 
173
177
  For decks with 5 or more slides:
174
178
 
175
179
  - First call `revela-deck-foundation` for new files, then patch structural
176
- slides and the first chapter between the `revela-slides` markers.
177
- - Then fill or revise exactly one chapter range at a time.
180
+ slides and the first listed batch between the `revela-slides` markers.
181
+ - Then fill or revise exactly one listed batch at a time.
182
+ - If a chapter has more than 5 slides, split it into consecutive batches from
183
+ `htmlWritingBatches`.
178
184
  - Do not mix multiple central-claim chapters in the same write.
179
185
  - Chapter divider or chapter TOC slides are allowed as structural wayfinding and
180
186
  should usually use the `toc` component.
@@ -292,15 +298,15 @@ patch and rerun QA before considering the deck ready.
292
298
 
293
299
  ## Evidence And Source Rules
294
300
 
295
- - Do not invent quotes, URLs, page references, source paths, caveats, or evidence
296
- ids.
297
- - Preserve supported scope, unsupported scope, caveats, and source trace when
298
- visible in narrative state or slide specs.
301
+ - Do not invent quotes, URLs, page references, source paths, source limitations,
302
+ user review notes, or evidence ids.
303
+ - Preserve source trace, explicit source limitations, and unresolved inputs when
304
+ visible in deck-plan source context or slide specs.
299
305
  - Evidence-sensitive claims need visible evidence/source context when available.
300
306
  - Never stretch partial evidence into support for future-state, recommendation,
301
307
  roadmap, or product-vision claims.
302
- - Keep missing evidence visible as a caveat, gap, or blocker instead of filling
303
- it with assumptions.
308
+ - Keep missing evidence visible as an unresolved input, source limitation, user
309
+ review note, or blocker instead of filling it with assumptions.
304
310
  - Do not render internal evidence diagnostics as executive-facing body copy.
305
311
  Avoid labels such as `Evidence gap:`, `Unsupported scope:`, `Caveat:`,
306
312
  `Missing Data`, or `Evidence Boundary` in normal slide text unless the user