@cyber-dash-tech/revela 0.15.2 → 0.15.4

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.
@@ -1,25 +1,7 @@
1
- import { openRefineDeck } from "../refine/open"
2
-
3
1
  export async function handleInspect(
4
2
  options: { client: any; sessionID: string; workspaceRoot: string; openBrowser?: boolean },
5
3
  send: (text: string) => Promise<void>,
6
4
  ): Promise<void> {
7
- try {
8
- const result = openRefineDeck("", {
9
- client: options.client,
10
- sessionID: options.sessionID,
11
- workspaceRoot: options.workspaceRoot,
12
- mode: "inspect",
13
- openBrowser: options.openBrowser,
14
- })
15
- await send(
16
- `\`/revela inspect\` is deprecated. Opened \`/revela refine\` in Inspect mode for the active HTML deck.\n` +
17
- `File: \`${result.deck.file}\`\n` +
18
- `${result.stateNote}\n` +
19
- `URL: ${result.url}\n\n` +
20
- `Use \`/revela refine\` directly going forward. Use Ctrl/Cmd-click in the browser to reference deck elements, then use the Inspect tab for read-only Source/Purpose review. There is no chat box or freeform prompt.`
21
- )
22
- } catch (e: any) {
23
- await send(`**Inspect failed:** ${e.message || String(e)}`)
24
- }
5
+ void options
6
+ await send("`/revela inspect` is no longer a public command. Use `/revela review --deck` and the Insight tab for grounded Source/Purpose/Narrative Reading.")
25
7
  }
@@ -34,7 +34,7 @@ export function parseStoryArgs(param: string): ParseStoryArgsResult {
34
34
  if (token.startsWith("--language=")) {
35
35
  return { ok: false, error: "Usage: `/revela story --language <language>` or `/revela story -l <language>`. Do not use `--language=<language>`." }
36
36
  }
37
- return { ok: false, error: "Usage: `/revela story [--language <language> | -l <language>]`. Use `/revela review` for a readiness report." }
37
+ return { ok: false, error: "Usage: `/revela story [--language <language> | -l <language>]`." }
38
38
  }
39
39
 
40
40
  return { ok: true, args: { language } }
@@ -130,9 +130,9 @@ export function buildNarrativeViewPrompt(options: { workspaceRoot: string; langu
130
130
  return `Prepare the read-only Revela narrative UI display model.
131
131
 
132
132
  Target language request: ${options.language}
133
- - The language value is passed from the user's /revela narrative arguments. Interpret it as the desired UI/display language.
133
+ - The language value is passed from the user's /revela story arguments. Interpret it as the desired UI/display language.
134
134
  - Examples: --cn maps to zh-CN, --jp maps to ja-JP, while --fr, --de, --es, --ko, --Arabic, --Portuguese-BR, or a written language name should be localized normally into that requested language.
135
- - Default /revela narrative language is en when the user provides no language request.
135
+ - Default /revela story language is en when the user provides no language request.
136
136
 
137
137
  You must call the \`revela-narrative-view\` tool exactly once.
138
138
 
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * lib/commands/pdf.ts
3
3
  *
4
- * Handler for `/revela pdf <file_path>` — exports an HTML slide deck to PDF.
4
+ * Handler for `/revela export --deck pdf <file_path>` — exports an HTML slide deck to PDF.
5
5
  *
6
6
  * Output: same directory and base name as the input, with .pdf extension.
7
7
  * Example: decks/my-deck.html → decks/my-deck.pdf
@@ -24,8 +24,8 @@ export async function handlePdf(
24
24
 
25
25
  if (!resolvedFile) {
26
26
  await send(
27
- "**Usage:** `/revela pdf [file_path]`\n\n" +
28
- "Example: `/revela pdf decks/my-deck.html`"
27
+ "**Usage:** `/revela export --deck pdf [file_path]`\n\n" +
28
+ "Example: `/revela export --deck pdf decks/my-deck.html`"
29
29
  )
30
30
  return
31
31
  }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * lib/commands/pptx.ts
3
3
  *
4
- * Handler for `/revela pptx [file_path]` — exports an HTML slide deck to PPTX.
4
+ * Handler for `/revela export --deck pptx [file_path]` — exports an HTML slide deck to PPTX.
5
5
  *
6
6
  * Output: same directory and base name as the input, with .pptx extension.
7
7
  * Example: decks/my-deck.html → decks/my-deck.pptx
@@ -64,7 +64,7 @@ export function resolvePptxDeck(workspaceRoot: string, filePath = ""): ResolvedP
64
64
  throw new Error("No deck HTML found in decks/. Generate a deck first or pass a file path.")
65
65
  }
66
66
  if (htmlFiles.length > 1) {
67
- throw new Error("This workspace contains multiple deck HTML files. Run `/revela pptx decks/<file>.html` to choose one.")
67
+ throw new Error("This workspace contains multiple deck HTML files. Run `/revela export --deck pptx decks/<file>.html` to choose one.")
68
68
  }
69
69
 
70
70
  const absoluteFile = resolve(root, htmlFiles[0])
@@ -14,13 +14,13 @@ export async function handleRefine(
14
14
  })
15
15
 
16
16
  await send(
17
- `Opened Revela Refine for the active HTML deck.\n` +
17
+ `Opened Revela Review for the active HTML deck.\n` +
18
18
  `File: \`${result.deck.file}\`\n` +
19
19
  `${result.stateNote}\n` +
20
20
  `URL: ${result.url}\n\n` +
21
- `Use Ctrl/Cmd-click in the browser to reference deck elements. The Edit tab sends targeted change comments; the Inspect tab reviews the same selection with Source/Purpose cards and does not edit the deck.`
21
+ `Use Ctrl/Cmd-click in the browser to reference deck elements. The Comment tab sends targeted change comments; the Insight tab reviews the same selection with Source/Purpose cards and does not edit the deck.`
22
22
  )
23
23
  } catch (e: any) {
24
- await send(`**Refine failed:** ${e.message || String(e)}`)
24
+ await send(`**Review failed:** ${e.message || String(e)}`)
25
25
  }
26
26
  }
@@ -18,7 +18,7 @@ Goal:
18
18
  - Treat this as a narrative readiness review, not a deck HTML write-readiness review.
19
19
  - Do not write, patch, or directly edit ${DECKS_STATE_FILE}. Use the \`revela-decks\` tool for all state changes.
20
20
  - Call \`revela-decks\` action \`reviewNarrative\` as the authoritative deterministic readiness engine.
21
- - Do not call \`revela-decks\` action \`review\` here. That action is the deck/artifact gate and belongs to \`/revela make deck --review\`.
21
+ - Do not call \`revela-decks\` action \`review\` here. That action is the deck/artifact gate inside \`/revela make --deck\` after the deck plan is confirmed.
22
22
  - Do not treat legacy \`writeReadiness.status\`, old review snapshots, or an existing HTML deck as narrative approval.
23
23
  - Do not write or overwrite \`decks/*.html\` during narrative review.
24
24
  - If the narrative is \`ready_for_approval\`, ask whether the user wants to approve it or revise it. Do not approve automatically.
@@ -50,7 +50,7 @@ Report format:
50
50
  - If warnings exist, list them after blockers as residual risks.
51
51
  - If approval is missing, ask whether the user wants to approve the narrative or revise it.
52
52
  - If approval is stale, say the prior approval no longer matches the current narrative hash.
53
- - Keep deck/artifact readiness separate. If the user wants to review slide-writing readiness, tell them to run \`/revela make deck --review\`.
53
+ - Keep deck/artifact readiness separate. If the user wants to write or review deck artifacts, tell them to run \`/revela make --deck\`.
54
54
 
55
55
  Rules:
56
56
  - Do not write or overwrite \`decks/*.html\` during narrative review.
@@ -79,6 +79,7 @@ Goal:
79
79
  - Treat this as the explicit transition from approved narrative state to user-confirmed deck planning.
80
80
  - Use the deck-render prompt mode for design, layout, component, HTML, QA, and deck artifact rules.
81
81
  - Default behavior is two-stage: first show the compiled deck plan with low-fidelity layout sketches, then stop for user confirmation before any artifact review or HTML writing.
82
+ - 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.
82
83
  - Do not write or overwrite \`decks/*.html\` until the narrative handoff, explicit user deck-plan confirmation, and deck/artifact gate are all satisfied.
83
84
  - Do not treat legacy \`writeReadiness.status\`, old review snapshots, or existing HTML decks as narrative approval.
84
85
  - Do not bypass the deck HTML contract, review snapshot freshness, source-trace expectations, or export preflight protections.
@@ -93,19 +94,22 @@ Workflow:
93
94
  3. If narrative readiness is \`approved\`, continue. If it is \`ready_for_approval\`, ask the user for explicit approval before continuing. If it is blocked, stale, or needs research, stop and report the smallest next action. Do not call \`approveNarrative\` unless the user explicitly approves or requests a render override.
94
95
  4. After approval or explicit render override exists, call \`revela-decks\` action \`compileDeckPlan\`. This projects canonical narrative claims and evidence bindings into compatibility \`slides[]\` and \`slides[].evidence[]\`; it must not write HTML.
95
96
  5. If \`compileDeckPlan\` returns \`skipped\`, stop and report the reason. Do not invent slide specs manually to bypass approval.
96
- 6. Present the compiled deck plan to the user and include a low-fidelity layout sketch for every slide. The sketch is ASCII/text structure only; do not generate visual images or HTML mockups.
97
+ 6. Present the compiled deck plan to the user and include a low-fidelity layout sketch for every slide. The plan must identify the chapter structure first: 3-5 chapter headings, each chapter's slide range, and which non-structural slides belong to each chapter. The sketch is ASCII/text structure only; do not generate visual images or HTML mockups.
97
98
  7. Stop after presenting the plan. Ask the user to confirm or request changes. Do not call \`revela-decks review\`, do not fetch design context, and do not write HTML in the same turn unless the user had already explicitly confirmed the current plan before this command.
98
99
  8. Only after explicit user confirmation of the current slide plan, call \`revela-decks\` action \`confirmDeckPlan\` with \`approvalBy=user\` and a compact \`approvalNote\`.
99
100
  9. After confirmation is recorded, ask for or confirm visual design only after the narrative deck plan exists. Fetch required design layouts/components with \`revela-designs read\` as needed.
100
101
  10. Update only deck/artifact metadata through \`revela-decks upsertDeck\` / \`upsertSlides\` when required by confirmed design/layout choices. Do not change canonical narrative claims unless the user asks to revise the narrative.
101
102
  11. Call \`revela-decks\` action \`review\` as the artifact gate. It computes \`writeReadiness\` and review snapshots for deck HTML writing. If it reports \`slide_plan_unconfirmed\`, stop and ask for explicit deck-plan confirmation.
102
- 12. Write \`decks/*.html\` only if the deck/artifact gate is ready and all deck HTML contract requirements can be satisfied. After each HTML write, the system automatically runs artifact QA before opening Refine.
103
- 13. If post-write artifact QA reports hard errors, fix them and let QA run again. Refine 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 Refine.
103
+ 12. Write \`decks/*.html\` only if the deck/artifact gate is ready and all deck HTML contract requirements can be satisfied. Generate the artifact chapter by chapter instead of drafting all content slides in one broad pass. Keep the HTML file valid after every write, preserve already-written slides, and update one chapter's slide sections at a time.
104
+ 13. 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.
105
+ 14. 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.
104
106
 
105
107
  Deck plan report format:
106
108
  - Start with \`Deck plan: awaiting confirmation\` when a plan was compiled and has not yet been confirmed.
107
109
  - Include narrative readiness status and narrative hash when available.
108
110
  - Include whether \`compileDeckPlan\` compiled or skipped.
111
+ - Include \`Required structure: Cover + Table of Contents + Closing\` and do not omit any of those slides.
112
+ - 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.
109
113
  - For every slide, include: slide index, title, purpose, narrative role, low-fidelity layout sketch, layout, components, primary/supporting claim ids, evidence binding ids or source summary, visual intent, and caveats/unsupported scope.
110
114
  - Use this sketch style or similarly simple ASCII boxes:
111
115
 
@@ -135,12 +139,15 @@ Caveats / unsupported scope:
135
139
  Report format before any HTML write after confirmation:
136
140
  - Start with \`Deck handoff: <status>\`.
137
141
  - Include which user-confirmed plan, approved narrative hash, and deck review snapshot authorized the artifact work.
142
+ - Include the chapter currently being generated and confirm already-written slides are being preserved.
138
143
  - If deck/artifact review is blocked, list blockers separately from narrative blockers.
139
- - 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 Refine.
144
+ - 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.
140
145
 
141
146
  Rules:
142
147
  - \`compileDeckPlan\` is the canonical narrative-to-deck planning path. Do not manually invent slide specs to avoid it.
143
148
  - Deck slide specs are render-target projections. Canonical narrative remains the authority for audience, decision, claims, evidence boundaries, objections, risks, and approval.
149
+ - Cover, Table of Contents, and Closing are mandatory deck structure. TOC chapter headings must match the chapter grouping used for generation.
150
+ - Do not generate the complete deck content in one broad pass after confirmation. Work chapter by chapter while keeping the artifact valid after each write.
144
151
  - Applying evidence candidates, rewriting canonical claims, or approving narratives requires explicit user instruction.
145
152
  - If the user requests slide order, layout, component, or visual-intent changes that do not alter meaning, update only the deck projection through \`upsertSlides\` and present the revised plan for confirmation.
146
153
  - If the user requests claim, evidence, caveat, decision, or recommendation meaning changes, update canonical narrative first and rerun narrative review/approval or explicit render override before compiling a new deck plan.
@@ -165,7 +172,7 @@ export function buildDeckReviewPrompt({
165
172
 
166
173
  Goal:
167
174
  - Use ${DECKS_STATE_FILE} as the source of truth for whether the current workspace deck is ready to be written to \`decks/*.html\`.
168
- - Treat this as an artifact gate for deck rendering, not strategic narrative approval. Narrative readiness reports are reviewed by \`/revela review\`.
175
+ - Treat this as an artifact gate for deck rendering, not strategic narrative approval. Narrative readiness is reviewed through \`/revela story\`.
169
176
  - Preserve the deck spec for future sessions: every slide's content, layout, components, evidence, visuals, production status, and the 0.9 narrative compiler brief when available.
170
177
  - Do not write, patch, or directly edit ${DECKS_STATE_FILE}. Use the \`revela-decks\` tool for all state changes.
171
178
  - Let \`revela-decks\` action \`review\` compute writeReadiness; do not manually set readiness to ready.
@@ -661,7 +661,7 @@ export function evaluateDeckStateWriteReadiness(state: DecksState, filePath: str
661
661
  type: "missing_slide_spec",
662
662
  severity: "blocker",
663
663
  message,
664
- suggestedAction: "Run /revela make deck --review and resolve all readiness blockers before writing deck HTML.",
664
+ suggestedAction: "Run /revela make --deck and resolve all readiness blockers before writing deck HTML.",
665
665
  })
666
666
  }
667
667
  if (deck.writeReadiness.blockers.length > 0) {
@@ -671,7 +671,7 @@ export function evaluateDeckStateWriteReadiness(state: DecksState, filePath: str
671
671
  type: "missing_slide_spec",
672
672
  severity: "blocker",
673
673
  message,
674
- suggestedAction: "Resolve the stored writeReadiness blockers and rerun /revela make deck --review.",
674
+ suggestedAction: "Resolve the stored writeReadiness blockers and rerun /revela make --deck.",
675
675
  })
676
676
  }
677
677
  if (normalized.reviews.length > 0) {
@@ -684,7 +684,7 @@ export function evaluateDeckStateWriteReadiness(state: DecksState, filePath: str
684
684
  type: "missing_slide_spec",
685
685
  severity: "blocker",
686
686
  message,
687
- suggestedAction: "Run /revela make deck --review so readiness is recorded against the current active render target.",
687
+ suggestedAction: "Run /revela make --deck so readiness is recorded against the current active render target.",
688
688
  })
689
689
  } else if (!isReviewSnapshotCurrent(normalized, snapshot, deck.slug)) {
690
690
  const message = "Latest review snapshot is stale for the current deck, sources, evidence, narrative state, or render target"
@@ -693,7 +693,7 @@ export function evaluateDeckStateWriteReadiness(state: DecksState, filePath: str
693
693
  type: "missing_slide_spec",
694
694
  severity: "blocker",
695
695
  message,
696
- suggestedAction: "Run /revela make deck --review again after the latest state changes before writing deck HTML.",
696
+ suggestedAction: "Run /revela make --deck again after the latest state changes before writing deck HTML.",
697
697
  })
698
698
  } else if (snapshot.status !== "ready") {
699
699
  const message = `Latest review snapshot is ${snapshot.status}, not ready`
@@ -702,7 +702,7 @@ export function evaluateDeckStateWriteReadiness(state: DecksState, filePath: str
702
702
  type: "missing_slide_spec",
703
703
  severity: "blocker",
704
704
  message,
705
- suggestedAction: "Resolve review blockers and rerun /revela make deck --review before writing deck HTML.",
705
+ suggestedAction: "Resolve review blockers and rerun /revela make --deck before writing deck HTML.",
706
706
  })
707
707
  }
708
708
  }
@@ -748,7 +748,7 @@ export function buildDecksStatePromptLayer(workspaceRoot: string, maxChars = 140
748
748
  }
749
749
  let text = JSON.stringify(compact, null, 2)
750
750
  if (text.length > maxChars) text = text.slice(0, maxChars).trimEnd() + "\n[DECKS.json state truncated for prompt size.]"
751
- return `---\n\n# Revela Workspace State From ${DECKS_STATE_FILE}\n\n\`\`\`json\n${text}\n\`\`\`\n\nRules for this state layer:\n- Treat ${DECKS_STATE_FILE} as the source of truth for the single current deck's specs, slide plan, evidence, render targets, and write readiness.\n- The decks map is compatibility storage; operate only on the current workspace deck.\n- ${DECKS_STATE_FILE} deck slides use 1-based \`slides[].index\` values. Render every HTML \`<section class="slide">\` with a matching 1-based \`data-slide-index\` attribute, and do not use 0-based \`data-index\` as slide identity.\n- The active HTML deck is represented as a \`renderTarget\` of type \`html_deck\`; PDF/PPTX exports should be recorded as derived render targets, not as separate deck specs.\n- \`writeReadiness\` is a compatibility projection for the /revela make deck generation workflow, not a hard blocker for targeted artifact-level HTML fixes.\n- Do not edit ${DECKS_STATE_FILE} directly; use the revela-decks tool.\n- For /revela make deck generated HTML, use the current deck's outputPath and satisfy the deck HTML contract. For targeted artifact-level edits, patch the requested deck HTML directly without treating \`writeReadiness\` or \`planReview\` as a precondition.`
751
+ return `---\n\n# Revela Workspace State From ${DECKS_STATE_FILE}\n\n\`\`\`json\n${text}\n\`\`\`\n\nRules for this state layer:\n- Treat ${DECKS_STATE_FILE} as the source of truth for the single current deck's specs, slide plan, evidence, render targets, and write readiness.\n- The decks map is compatibility storage; operate only on the current workspace deck.\n- ${DECKS_STATE_FILE} deck slides use 1-based \`slides[].index\` values. Render every HTML \`<section class="slide">\` with a matching 1-based \`data-slide-index\` attribute, and do not use 0-based \`data-index\` as slide identity.\n- The active HTML deck is represented as a \`renderTarget\` of type \`html_deck\`; PDF/PPTX exports should be recorded as derived render targets, not as separate deck specs.\n- \`writeReadiness\` is a compatibility projection for the /revela make --deck generation workflow, not a hard blocker for targeted artifact-level HTML fixes.\n- Do not edit ${DECKS_STATE_FILE} directly; use the revela-decks tool.\n- For /revela make --deck generated HTML, use the current deck's outputPath and satisfy the deck HTML contract. For targeted artifact-level edits, patch the requested deck HTML directly without treating \`writeReadiness\` or \`planReview\` as a precondition.`
752
752
  }
753
753
 
754
754
  function compactWorkspaceForPrompt(workspace: DecksState["workspace"]): DecksState["workspace"] {
@@ -84,7 +84,7 @@ function inferSlides(filePath: string): SlideSpec[] {
84
84
  evidence: [],
85
85
  visuals: [],
86
86
  status: "ready",
87
- notes: "Inferred automatically by /revela edit preflight.",
87
+ notes: "Inferred automatically by /revela review --deck preflight.",
88
88
  }
89
89
  })
90
90
  }
@@ -12,7 +12,7 @@ export interface EditableDeck {
12
12
 
13
13
  export function resolveEditableDeck(workspaceRoot: string, input = ""): EditableDeck {
14
14
  if (input.trim()) {
15
- throw new Error("/revela refine does not accept a target. It opens the active HTML deck or the only HTML deck in decks/.")
15
+ throw new Error("/revela review --deck does not accept a target. It opens the active HTML deck or the only HTML deck in decks/.")
16
16
  }
17
17
 
18
18
  if (hasDecksState(workspaceRoot)) {
@@ -484,7 +484,7 @@ export function renderInspectorShell(token: string): string {
484
484
  <aside>
485
485
  <div>
486
486
  <h1>Evidence Inspector</h1>
487
- <p class="hint">Cmd/Ctrl-click slide elements to attach them as references, exactly like /revela edit. Then click <b>Inspect Selection</b>. This is not chat.</p>
487
+ <p class="hint">Cmd/Ctrl-click slide elements to attach them as references in /revela review --deck. Then click <b>Get Insight</b>. This is not chat.</p>
488
488
  </div>
489
489
  <div id="selection" class="selection">
490
490
  <strong>Selection</strong>
@@ -632,7 +632,7 @@ export function renderInspectorShell(token: string): string {
632
632
  if (bindAttempts >= 80) {
633
633
  clearInterval(bindTimer);
634
634
  bindTimer = 0;
635
- setBindingStatus('error', 'Selection binding timed out. Reopen /revela inspect or reload this page.');
635
+ setBindingStatus('error', 'Selection binding timed out. Reopen /revela review --deck or reload this page.');
636
636
  }
637
637
  }, 150);
638
638
  }
@@ -7,8 +7,10 @@
7
7
  *
8
8
  * Deck-render mode:
9
9
  * Layer 1: SKILL.md — legacy deck render protocol (HTML rules, quality)
10
- * Layer 2: DOMAIN.md — domain structure/terminology
11
- * Layer 3: DESIGN.md — visual style (colors, fonts, animations, layout)
10
+ * Layer 2: DESIGN.md — visual style (colors, fonts, animations, layout)
11
+ *
12
+ * Domain guidance is intentionally narrative-only. Deck-render mode must render
13
+ * the approved canonical narrative instead of re-interpreting domain semantics.
12
14
  *
13
15
  * When the active DESIGN.md has @section markers, only the global section,
14
16
  * layouts section, and a generated component index are injected into the
@@ -87,19 +89,23 @@ export function buildPrompt(optionsOrDesignName?: BuildPromptOptions | string, l
87
89
  ? "<!-- - preview.html — canonical visual reference (read this before generating slides) -->"
88
90
  : "<!-- - (no preview.html for this design) -->"
89
91
 
90
- // Layer 2 — DOMAIN.md skill text (may be empty for "general")
92
+ // Layer 2 — DOMAIN.md skill text (narrative mode only). Deck-render mode
93
+ // renders the approved canonical narrative and must not re-interpret domain
94
+ // semantics from the full domain prompt.
91
95
  let domainSkill = ""
92
- try {
93
- domainSkill = getDomainSkillMd(domain)
94
- } catch (e) {
95
- // Domain not installed or empty — proceed without domain layer
96
- promptLog.warn("domain skill not foundbuilding without domain layer", {
97
- domain,
98
- error: e instanceof Error ? e.message : String(e),
99
- })
96
+ if (mode === "narrative") {
97
+ try {
98
+ domainSkill = getDomainSkillMd(domain)
99
+ } catch (e) {
100
+ // Domain not installed or empty proceed without domain layer
101
+ promptLog.warn("domain skill not found — building without domain layer", {
102
+ domain,
103
+ error: e instanceof Error ? e.message : String(e),
104
+ })
105
+ }
100
106
  }
101
107
 
102
- // Layer 3 — DESIGN.md: deck-render only. Narrative mode must not inject
108
+ // DESIGN.md: deck-render only. Narrative mode must not inject
103
109
  // visual CSS, layout catalogs, component indexes, or HTML skeleton rules.
104
110
  const designSkill = mode === "deck-render" ? buildDesignLayer(design) : ""
105
111
 
@@ -107,7 +113,7 @@ export function buildPrompt(optionsOrDesignName?: BuildPromptOptions | string, l
107
113
  const header = mode === "deck-render"
108
114
  ? `<!-- Revela prompt mode: deck-render -->\n` +
109
115
  `<!-- Active design: ${design} -->\n` +
110
- `<!-- Active domain: ${domain} -->\n` +
116
+ `<!-- Active domain: ${domain} (not injected in deck-render mode) -->\n` +
111
117
  `<!-- Design files: ${designDir}/ -->\n` +
112
118
  `<!-- - DESIGN.md — metadata + style instructions (injected below) -->\n` +
113
119
  `${previewLine}\n\n`
@@ -115,7 +121,7 @@ export function buildPrompt(optionsOrDesignName?: BuildPromptOptions | string, l
115
121
  `<!-- Active domain: ${domain} -->\n` +
116
122
  `<!-- Design layer intentionally omitted in narrative mode. Use deck-render mode before writing deck artifacts. -->\n\n`
117
123
 
118
- // Concatenation: Header → Skill → Domain → Design (deck-render only)
124
+ // Concatenation: Header → Skill → Domain (narrative only) → Design (deck-render only)
119
125
  const parts = [header, coreSkill]
120
126
  if (domainSkill) {
121
127
  parts.push(`\n\n---\n\n${domainSkill}`)
@@ -247,7 +247,7 @@ async function handleAssetSave(req: Request, session: EditSession): Promise<Resp
247
247
  id: body?.id || candidate.candidateId,
248
248
  type: "image",
249
249
  purpose,
250
- brief: body?.brief || `Saved from ${candidate.provider} for Refine asset placement.`,
250
+ brief: body?.brief || `Saved from ${candidate.provider} for Review asset placement.`,
251
251
  status: "success",
252
252
  sourceUrl: candidate.imageUrl,
253
253
  alt: body?.alt || candidate.alt || candidate.title,
@@ -652,7 +652,7 @@ function handleInspectResult(requestId: string | null, session: EditSession): Re
652
652
  session.lastActiveAt = Date.now()
653
653
  scheduleIdleStop()
654
654
  if (request.status === "completed") return jsonResponse({ ok: true, requestId, status: request.status, deckVersion: request.deckVersion, result: request.result })
655
- if (request.status === "failed" || request.status === "expired") return jsonResponse({ ok: true, requestId, status: request.status, deckVersion: request.deckVersion, error: request.error || "Inspection failed" })
655
+ if (request.status === "failed" || request.status === "expired") return jsonResponse({ ok: true, requestId, status: request.status, deckVersion: request.deckVersion, error: request.error || "Insight failed" })
656
656
  return jsonResponse({ ok: true, requestId, status: request.status, deckVersion: request.deckVersion })
657
657
  }
658
658
 
@@ -764,7 +764,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
764
764
  <head>
765
765
  <meta charset="utf-8" />
766
766
  <meta name="viewport" content="width=device-width, initial-scale=1" />
767
- <title>Revela Refine</title>
767
+ <title>Revela Review</title>
768
768
  <style>
769
769
  :root { color-scheme: light; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
770
770
  * { box-sizing: border-box; }
@@ -783,15 +783,16 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
783
783
  .deck-nav button:hover:not(:disabled) { background: rgba(255,255,255,.22); }
784
784
  .deck-nav button:disabled { opacity: .38; }
785
785
  .deck-nav-status { min-width: 76px; color: #e2e8f0; font-size: 12px; font-weight: 900; text-align: center; font-variant-numeric: tabular-nums; }
786
- aside { position: relative; display: flex; flex-direction: column; gap: 16px; padding: 20px; background: linear-gradient(180deg, #fbfaf7 0%, #f2eee6 100%); overflow: auto; border-left: 1px solid #d8d2c6; }
786
+ aside { position: relative; display: flex; flex-direction: column; gap: 16px; padding: 20px; background: linear-gradient(180deg, #fbfaf7 0%, #f2eee6 100%); overflow: auto; border-left: 1px solid #d8d2c6; font-family: Garamond, "Iowan Old Style", Georgia, serif; }
787
+ aside button, aside input, aside select, aside textarea, aside .comment-editor { font-family: inherit; }
787
788
  h1 { margin: 0; font-size: 18px; line-height: 1.2; letter-spacing: -.01em; color: #0f172a; }
788
789
  .wordmark { font-family: Garamond, "Iowan Old Style", Georgia, serif; font-size: 21px; letter-spacing: .08em; font-weight: 600; }
789
- .hint { margin: 0; color: #756f66; font-size: 13px; line-height: 1.5; }
790
790
  .panel { display: flex; flex-direction: column; gap: 10px; }
791
- .tabs { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 4px; border: 1px solid #d8d2c6; border-radius: 14px; background: #ebe4d8; }
792
- .tab { padding: 9px 10px; border: 0; border-radius: 10px; background: transparent; color: #5f594f; box-shadow: none; font-weight: 900; }
793
- .tab.active { background: #fbfaf7; color: #111827; box-shadow: 0 6px 16px rgba(31,41,51,.1); }
794
- .tab-panel { display: none; flex-direction: column; gap: 12px; }
791
+ .tabs { display: flex; gap: 2px; padding: 0 0 0 8px; border-bottom: 1px solid #d8d2c6; background: transparent; }
792
+ .tab { width: auto; min-width: 112px; padding: 10px 18px; border: 1px solid transparent; border-bottom: 0; border-radius: 13px 13px 0 0; background: transparent; color: #5f594f; box-shadow: none; font-weight: 900; }
793
+ .tab:hover:not(:disabled) { background: rgba(255,253,248,.58); }
794
+ .tab.active { position: relative; top: 1px; background: #fbfaf7; border-color: #d8d2c6; color: #111827; box-shadow: 0 -7px 16px rgba(31,41,51,.05); }
795
+ .tab-panel { display: none; flex-direction: column; gap: 12px; padding-top: 12px; }
795
796
  .tab-panel.active { display: flex; }
796
797
  .sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
797
798
  .selection-summary { padding: 10px 12px; border: 1px solid #d8d2c6; border-radius: 14px; background: #fbfaf7; color: #3f3a33; font-size: 13px; line-height: 1.45; box-shadow: 0 8px 22px rgba(31,41,51,.05); }
@@ -885,20 +886,19 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
885
886
  <div id="resizeHandle" class="resize-handle" role="separator" aria-label="Resize editor panel" aria-orientation="vertical" title="Drag to resize editor. Double-click to reset."></div>
886
887
  <aside>
887
888
  <div>
888
- <h1><span class="wordmark">REVELA</span> Refine</h1>
889
- <p class="hint">Select refs, describe the change, then send. Use Inspect only when you need source or purpose context.</p>
889
+ <h1><span class="wordmark">REVELA</span> Review</h1>
890
890
  </div>
891
891
  <div id="selectionSummary" class="selection-summary sr-only" aria-live="polite"><strong>Selection</strong><span>No references selected.</span><div id="selectionChips" class="selection-chips"></div></div>
892
- <div class="tabs" role="tablist" aria-label="Refine mode">
893
- <button id="editTab" class="tab" type="button" role="tab">Edit</button>
894
- <button id="inspectTab" class="tab" type="button" role="tab">Inspect</button>
892
+ <div class="tabs" role="tablist" aria-label="Review mode">
893
+ <button id="editTab" class="tab" type="button" role="tab">Comment</button>
894
+ <button id="inspectTab" class="tab" type="button" role="tab">Insight</button>
895
895
  </div>
896
896
  <div id="editPanel" class="tab-panel">
897
897
  <div class="panel">
898
898
  <div class="label">Describe the change</div>
899
899
  <div id="comment" class="comment-editor" contenteditable="true" role="textbox" aria-multiline="true" data-placeholder="Cmd/Ctrl-click slide elements to add @refs, then describe the exact edit."></div>
900
900
  </div>
901
- <div class="edit-assets" aria-label="Edit assets">
901
+ <div class="edit-assets" aria-label="Comment assets">
902
902
  <div class="panel">
903
903
  <div class="asset-tools"><div class="label">Local Assets</div><button id="assetSearchToggle" class="asset-search-toggle" type="button" aria-expanded="false" aria-controls="assetSearchView" title="Search assets">+</button></div>
904
904
  <div id="editSavedAssets" class="asset-grid"><p class="asset-empty">No local assets yet. Click + to search assets.</p></div>
@@ -909,20 +909,20 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
909
909
  </div>
910
910
  <div id="inspectPanel" class="tab-panel">
911
911
  <div class="panel">
912
- <label class="label" for="inspectComment">Inspect comment</label>
912
+ <label class="label" for="inspectComment">Insight comment</label>
913
913
  <div id="inspectComment" class="comment-editor" contenteditable="true" role="textbox" aria-multiline="true" data-placeholder="Cmd/Ctrl-click slide elements to add @refs, then ask about purpose or source."></div>
914
914
  </div>
915
915
  <div class="inspect-actions">
916
916
  <div class="inspect-options"><label for="inspectLanguage">Display Language</label><select id="inspectLanguage" class="inspect-select"><option>Auto</option><option>English</option><option>简体中文</option><option>繁體中文</option><option>日本語</option><option>Deutsch</option><option>Français</option><option>Español</option><option>Português</option><option>Arabic</option></select></div>
917
- <button id="inspectButton" disabled>Inspect Reference</button>
917
+ <button id="inspectButton" disabled>Get Insight</button>
918
918
  <div id="inspectStale"></div>
919
919
  </div>
920
- <div id="inspectCards" class="inspect-cards"><div class="inspect-empty">Select a deck element to create an @ref, optionally ask a question, then Inspect. This does not edit the deck.</div></div>
920
+ <div id="inspectCards" class="inspect-cards"><div class="inspect-empty">Select a deck element to create an @ref, optionally ask a question, then get insight. This does not edit the deck.</div></div>
921
921
  </div>
922
922
  <div id="assetSearchView" class="asset-search-view" aria-hidden="true">
923
923
  <div class="asset-search-head">
924
924
  <button id="assetSearchBack" class="asset-back" type="button">← Back</button>
925
- <div class="asset-search-title"><h2>Search Assets</h2><span>Save images to Local Assets, then use them from Edit.</span></div>
925
+ <div class="asset-search-title"><h2>Search Assets</h2><span>Save images to Local Assets, then use them from Comment.</span></div>
926
926
  </div>
927
927
  <div class="panel">
928
928
  <div class="asset-search"><input id="assetQuery" type="search" placeholder="Company logo, product photo, portrait..." /><select id="assetPurpose"><option value="logo" selected>logo</option><option value="illustration">photo</option><option value="hero">hero</option><option value="portrait">portrait</option><option value="screenshot">screenshot</option></select></div>
@@ -1072,7 +1072,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1072
1072
  restoreEditorWidth();
1073
1073
  bindEvents();
1074
1074
  setMode(state.mode);
1075
- setStatus('Editor ready. Ctrl/Cmd + click deck elements to reference them.');
1075
+ setStatus('Review ready. Ctrl/Cmd + click deck elements to reference them.');
1076
1076
  initFrame();
1077
1077
  loadSavedAssets();
1078
1078
  startDeckVersionPolling();
@@ -1116,6 +1116,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1116
1116
  els.inspectComment.addEventListener('mouseup', saveCommentRange);
1117
1117
  document.addEventListener('selectionchange', saveCommentRange);
1118
1118
  els.hitbox.addEventListener('pointermove', onHover);
1119
+ els.hitbox.addEventListener('pointerleave', clearHoverSilently);
1119
1120
  els.hitbox.addEventListener('pointerdown', onPointerDown);
1120
1121
  els.hitbox.addEventListener('click', onClick);
1121
1122
  els.hitbox.addEventListener('contextmenu', (event) => {
@@ -1263,7 +1264,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1263
1264
  state.pendingRefreshMessage = false;
1264
1265
  setStatus('Deck updated. Preview refreshed. Element references were cleared.');
1265
1266
  } else {
1266
- setStatus(slides.length > 0 ? 'Editor ready. Found ' + slides.length + ' slides. Ctrl/Cmd + click to reference elements.' : 'Editor ready, but no .slide elements were found. Ctrl/Cmd + click to reference elements.');
1267
+ setStatus(slides.length > 0 ? 'Review ready. Found ' + slides.length + ' slides. Ctrl/Cmd + click to reference elements.' : 'Review ready, but no .slide elements were found. Ctrl/Cmd + click to reference elements.');
1267
1268
  }
1268
1269
  } catch (error) {
1269
1270
  reportError(error);
@@ -1336,9 +1337,11 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1336
1337
  } catch {}
1337
1338
  }
1338
1339
  if (!handled) applyFallbackDeckNavigation(win, doc, slides, clamped);
1340
+ const changed = clamped !== state.deckSlideIndex;
1339
1341
  state.deckSlideIndex = clamped;
1340
1342
  updateDeckNavControls();
1341
- renderHoverOutline(state.hoverEl);
1343
+ if (changed) clearHoverSilently();
1344
+ else renderHoverOutline(state.hoverEl);
1342
1345
  renderReferenceOutlines();
1343
1346
  } catch (error) {
1344
1347
  reportError(error);
@@ -1415,6 +1418,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1415
1418
  initFrame();
1416
1419
  const target = selectable(targetFromPointer(event));
1417
1420
  if (!target || isReferenced(target)) {
1421
+ state.hoverEl = null;
1418
1422
  renderHoverOutline(null);
1419
1423
  return;
1420
1424
  }
@@ -1829,7 +1833,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1829
1833
  renderReferenceOutlines();
1830
1834
  updateSendState();
1831
1835
  renderSelectionSummary();
1832
- resetInspectCards('References ready. Open Inspect and click Inspect Reference for concise Purpose and Source context.');
1836
+ resetInspectCards('References ready. Open Insight and click Get Insight for concise Purpose and Source context.');
1833
1837
  setStatus('Inserted @' + label + '. ' + state.references.length + ' reference' + (state.references.length === 1 ? '' : 's') + ' will be sent.');
1834
1838
  }
1835
1839
 
@@ -1997,14 +2001,27 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
1997
2001
  function renderReferenceOutlines() {
1998
2002
  const doc = els.frame.contentDocument;
1999
2003
  if (!doc || doc.location.href === 'about:blank') return;
2004
+ const slides = getSlides(doc);
2005
+ const currentSlide = slides[state.deckSlideIndex];
2006
+ const explicitSlideIndex = Number(currentSlide?.getAttribute('data-slide-index'));
2007
+ const currentSlideIndex = Number.isFinite(explicitSlideIndex) && explicitSlideIndex > 0 ? explicitSlideIndex : state.deckSlideIndex + 1;
2000
2008
  while (state.referenceOutlines.length < state.references.length) state.referenceOutlines.push(createOutline(doc, '#7aa6d8', 'rgba(122,166,216,.18)'));
2001
2009
  state.referenceOutlines.forEach((outline, index) => {
2002
2010
  const reference = state.references[index];
2003
2011
  setOutlineColor(outline, reference?.color);
2012
+ if (!reference || reference.payload?.slideIndex !== currentSlideIndex) {
2013
+ renderBox(outline, null);
2014
+ return;
2015
+ }
2004
2016
  renderBox(outline, reference?.target);
2005
2017
  });
2006
2018
  }
2007
2019
 
2020
+ function clearHoverSilently() {
2021
+ state.hoverEl = null;
2022
+ if (state.hoverOutline) state.hoverOutline.style.display = 'none';
2023
+ }
2024
+
2008
2025
  function clearHover() {
2009
2026
  state.hoverEl = null;
2010
2027
  setStatus('Hover cleared. Existing references are kept.');
@@ -2015,8 +2032,8 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
2015
2032
  if (state.sendingEdit) setButtonLoading(els.send, true, 'Sending...');
2016
2033
  else setButtonLoading(els.send, false, '<svg class="send-icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94L14.7 6.3z"/></svg><span>Apply Fix</span>', true);
2017
2034
  els.send.disabled = state.sendingEdit || !getCommentText().trim();
2018
- if (state.inspecting) setButtonLoading(els.inspectButton, true, 'Inspecting...');
2019
- else setButtonLoading(els.inspectButton, false, 'Inspect Reference');
2035
+ if (state.inspecting) setButtonLoading(els.inspectButton, true, 'Getting insight...');
2036
+ else setButtonLoading(els.inspectButton, false, 'Get Insight');
2020
2037
  els.inspectButton.disabled = state.inspecting || state.references.length === 0;
2021
2038
  }
2022
2039
 
@@ -2077,7 +2094,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
2077
2094
  body: JSON.stringify({ snapshot, deckVersion: state.deckVersion, language: state.inspectLanguage, comment }),
2078
2095
  });
2079
2096
  const body = await res.json().catch(() => ({}));
2080
- if (!res.ok || !body.ok) throw new Error(body.error || 'Inspection failed');
2097
+ if (!res.ok || !body.ok) throw new Error(body.error || 'Insight failed');
2081
2098
  state.deckVersion = body.deckVersion || state.deckVersion;
2082
2099
  state.activeInspectRequestId = body.requestId;
2083
2100
  state.inspectFallback = body.preprocess || null;
@@ -2086,7 +2103,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
2086
2103
  } catch (error) {
2087
2104
  if (state.inspectFallback) {
2088
2105
  renderInspectResult(state.inspectFallback, 'Deterministic fallback');
2089
- els.inspectCards.insertAdjacentHTML('afterbegin', '<div class="inspect-warning">Generated inspection failed or timed out. Showing deterministic fallback context only.</div>');
2106
+ els.inspectCards.insertAdjacentHTML('afterbegin', '<div class="inspect-warning">Generated insight failed or timed out. Showing deterministic fallback context only.</div>');
2090
2107
  } else {
2091
2108
  resetInspectCards(error && error.message ? error.message : String(error));
2092
2109
  }
@@ -2101,15 +2118,15 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
2101
2118
  await delay(900);
2102
2119
  const res = await fetch('/api/inspect-result?token=' + encodeURIComponent(token) + '&requestId=' + encodeURIComponent(requestId));
2103
2120
  const body = await res.json().catch(() => ({}));
2104
- if (!res.ok || !body.ok) throw new Error(body.error || 'Inspection result failed');
2121
+ if (!res.ok || !body.ok) throw new Error(body.error || 'Insight result failed');
2105
2122
  if (body.status === 'completed') {
2106
2123
  state.deckVersion = body.deckVersion || state.deckVersion;
2107
2124
  renderInspectResult(body.result, 'Generated');
2108
2125
  return;
2109
2126
  }
2110
- if (body.status === 'failed' || body.status === 'expired') throw new Error(body.error || 'Inspection failed');
2127
+ if (body.status === 'failed' || body.status === 'expired') throw new Error(body.error || 'Insight failed');
2111
2128
  }
2112
- throw new Error('Inspection timed out while waiting for OpenCode result');
2129
+ throw new Error('Insight timed out while waiting for OpenCode result');
2113
2130
  }
2114
2131
 
2115
2132
  function collectReferenceSnapshot() {
@@ -2136,10 +2153,10 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
2136
2153
  }
2137
2154
 
2138
2155
  function renderInspectResult(result, phase) {
2139
- if (result.stale?.stale) els.inspectStale.innerHTML = '<div class="inspect-stale">' + escapeHtml(result.stale.reason || 'Inspection may be stale.') + '</div>';
2156
+ if (result.stale?.stale) els.inspectStale.innerHTML = '<div class="inspect-stale">' + escapeHtml(result.stale.reason || 'Insight may be stale.') + '</div>';
2140
2157
  else els.inspectStale.innerHTML = '';
2141
2158
  els.inspectCards.innerHTML = [
2142
- '<div class="status">' + escapeHtml(phase || 'Inspection') + '</div>',
2159
+ '<div class="status">' + escapeHtml(phase || 'Insight') + '</div>',
2143
2160
  renderInspectCard('Purpose', result.cards.purpose.status, result.cards.purpose.rationale, renderPurpose(result.cards.purpose)),
2144
2161
  renderInspectCard('Source', result.cards.source.status, result.cards.source.rationale, renderSource(result.cards.source)),
2145
2162
  ].join('');
@@ -2303,7 +2320,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
2303
2320
  removeAssetChip();
2304
2321
  }
2305
2322
  renderSelectionSummary();
2306
- resetInspectCards('Select a deck element to create an @ref, optionally ask a question, then Inspect. This does not edit the deck.');
2323
+ resetInspectCards('Select a deck element to create an @ref, optionally ask a question, then get insight. This does not edit the deck.');
2307
2324
  }
2308
2325
 
2309
2326
  function getCommentText(editor) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyber-dash-tech/revela",
3
- "version": "0.15.2",
3
+ "version": "0.15.4",
4
4
  "description": "OpenCode plugin that turns AI into an HTML slide deck generator",
5
5
  "type": "module",
6
6
  "main": "./index.ts",