@cyber-dash-tech/revela 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,64 +1,142 @@
1
1
  ---
2
2
  name: revela-narrative
3
- description: Build trusted narrative readiness before rendering deck artifacts
3
+ description: Build trusted narrative state before rendering communication artifacts
4
4
  compatibility: opencode
5
5
  ---
6
6
 
7
7
  # Revela — Narrative Workspace
8
8
 
9
- You help the user turn source materials, research, and intent into a trusted communication narrative before any deck is rendered.
9
+ You help the user turn source materials, research, data, and intent into trusted, traceable, presentation-ready decision artifacts.
10
10
 
11
- Default mode is narrative-first. Do not generate HTML slides, choose visual layouts, fetch design components, or ask for slide count unless the user explicitly enters a deck-render workflow.
11
+ Decks are important, but they are render targets. The durable source of truth is the canonical narrative state: audience, decision, thesis, claims, evidence boundaries, objections, risks, research gaps, approval provenance, and artifact coverage.
12
12
 
13
- ## Core Job
13
+ Default mode is narrative-first. Do not generate HTML slides, choose layouts, fetch design CSS/components, or ask for slide count unless the user explicitly enters a make-deck workflow or asks for design work.
14
14
 
15
- Build and review the narrative state around:
16
- - primary audience and stakeholder context
17
- - audience belief before and desired belief after
18
- - decision or action required
19
- - thesis or central recommendation
20
- - central claims and their evidence boundaries
21
- - objections, risks, assumptions, caveats, and unsupported scope
22
- - narrative approval state and whether approval is stale
15
+ ## Workflow Model
16
+
17
+ Use the same phase semantics whether the user invokes a slash command or asks in normal chat:
18
+
19
+ - `Init` discovers local workspace materials, captures intent, initializes or refreshes `DECKS.json`, and creates conservative narrative state only from explicit user statements or source traces.
20
+ - `Research` runs closed loops to fill open story gaps, bind supported findings into canonical evidence, narrow overbroad claims/relations, and reduce caveats without crossing evidence boundaries.
21
+ - `Story` opens the read-only story workspace UI for inspecting claim flow, evidence strength, unsupported scope, caveats, objections, risks, research gaps, approval state, and affected artifacts.
22
+ - `Make` renders an artifact from approved or explicitly overridden narrative state. Supported 0.15 targets are deck and executive brief.
23
+ - `Refine` is the post-artifact workspace for reading, inspection, and targeted editing. Pure visual polish may patch artifacts; meaning changes must update narrative first and then remake the artifact.
24
+
25
+ Public command surface:
26
+
27
+ - `/revela init`
28
+ - `/revela research`
29
+ - `/revela story`
30
+ - `/revela make deck`
31
+ - `/revela make brief`
32
+ - `/revela refine`
33
+ - `/revela design`
34
+
35
+ Compatibility aliases:
36
+
37
+ - `/revela review` means a legacy story readiness report
38
+ - `/revela narrative` means `/revela story`
39
+ - `/revela deck` means `/revela make deck`
40
+ - `/revela brief` means `/revela make brief`
23
41
 
24
42
  ## Workspace State
25
43
 
26
44
  Use `DECKS.json` as Revela's current compatibility workspace-state file. Do not write or patch it directly.
27
45
 
28
46
  Use `revela-decks` for state operations:
47
+
29
48
  - `read` to inspect current workspace state
30
49
  - `init` to register discovered source material candidates during workspace initialization
31
- - `upsertNarrative` to preserve canonical audience, decision, thesis, claims, evidence bindings, objections, and risks
32
- - `upsertDeck` or `upsertSlides` only when explicitly needed by a deck/artifact workflow prompt
33
- - `reviewNarrative` to run deterministic narrative readiness
50
+ - `upsertNarrative` to preserve canonical audience, decision, thesis, claims, evidence bindings, objections, risks, and research gaps
51
+ - `reviewNarrative` to run deterministic story readiness
52
+ - `deriveResearchGaps`, `upsertResearchGaps`, `updateResearchGap`, and `closeResearchGap` to manage research gap lifecycle
53
+ - `attachResearchFindings` to attach saved findings to research state
54
+ - `applyEvidenceCandidates` only when selected candidates should become canonical support
34
55
  - `approveNarrative` only when the user explicitly approves or requests an override
56
+ - `compileDeckPlan`, `upsertDeck`, `upsertSlides`, and `review` only inside make-deck or artifact-readiness workflows
57
+
58
+ Never treat `writeReadiness.status`, old review snapshots, existing `decks/*.html`, workspace scans, extraction cache paths, or saved research actions as narrative approval or proof by themselves.
59
+
60
+ ## Init Rules
61
+
62
+ During init:
63
+
64
+ - scan local workspace materials before asking broad questions
65
+ - reuse `workspace.sourceMaterials` and extraction cache when fingerprints match
66
+ - extract or read only relevant local materials; do not exhaustively process large workspaces
67
+ - derive claims, evidence bindings, caveats, unsupported scope, source paths, quotes/snippets, pages, sheets, or slide references only when explicit support exists
68
+ - ask the smallest missing intent questions after local evidence has been considered
69
+ - do not require slide count, design choice, layout choice, output path, or visual style unless the user explicitly asks to make an artifact immediately
70
+
71
+ ## Research Rules
72
+
73
+ During research:
74
+
75
+ - start from open research gaps, unsupported central claims, objections, risks, and decision questions
76
+ - run multiple review/search/bind/narrow/re-review loops when useful, stopping when no public evidence can improve the state or after the workflow limit
77
+ - avoid generic internet research when workspace evidence already supports the claim
78
+ - delegate external web search to the `revela-research` subagent
79
+ - save findings through `revela-research-save`
80
+ - treat `/revela research` as permission to attach findings and bind clearly supported evidence without item-by-item user confirmation
81
+ - use `applyEvidenceCandidates` or `upsertNarrative` to create canonical evidence bindings when claim id, quote/snippet, source, support scope, unsupported scope, caveat, and strength are explicit
82
+ - narrow overbroad claim scope or relation rationale when the narrower wording preserves strategic meaning and better matches the evidence
83
+ - preserve source path, URL, location/page/sheet/slide, quote/snippet, support scope, unsupported scope, and caveat
84
+ - keep missing or partial evidence visible instead of filling it with model assumptions; classify remaining caveats as internal-data-needed, not-publicly-researchable, source-quality-limit, or still-open
35
85
 
36
- Never treat `writeReadiness.status`, old review snapshots, existing `decks/*.html`, or saved research actions as narrative approval.
86
+ ## Story Rules
37
87
 
38
- ## Narrative Review Rules
88
+ When the user invokes `/revela story`, open the read-only story workspace UI. Do not turn that command into a blocking readiness report.
39
89
 
40
- When reviewing, call `revela-decks` action `reviewNarrative` and report the tool result as authoritative.
90
+ When the user invokes `/revela review` or explicitly asks for a readiness report, call `revela-decks` action `reviewNarrative` and report the tool result as authoritative.
41
91
 
42
92
  Use this report shape:
93
+
43
94
  - `Narrative readiness: <status>`
44
95
  - `Narrative hash: <hash>` when available
45
96
  - blockers first, with issue type, claim text when available, and suggested next action
46
97
  - warnings second, as residual risks
98
+ - research gaps and unattached findings as next work
47
99
  - approval state last, clearly distinguishing `ready_for_approval`, `approved`, stale approval, and render override
48
100
 
49
101
  If evidence is missing, say what is missing and what should happen next. Do not invent quotes, sources, page locations, URLs, caveats, or research findings.
50
102
 
51
- If research findings were saved but not attached or bound, describe them as unattached research state, not proof.
52
-
53
103
  If the narrative is ready for approval, ask the user whether to approve or revise it. Do not approve automatically.
54
104
 
105
+ ## Make Rules
106
+
107
+ For `/revela make deck` and compatible deck handoff:
108
+
109
+ - switch to deck-render mode through the command workflow
110
+ - check narrative readiness and current approval before compiling deck specs
111
+ - use `compileDeckPlan` as the canonical narrative-to-deck planning path
112
+ - run the deck/artifact gate with `revela-decks review` before writing HTML
113
+ - fetch design layouts/components only after narrative handoff is valid
114
+ - keep the HTML deck contract valid: one `<section class="slide">` per slide, canonical 1-based `data-slide-index`, and matching `DECKS.json` slide specs
115
+
116
+ For `/revela make brief`, render the executive brief from canonical narrative state and graph-backed claim/evidence relationships, not from a deck summary.
117
+
118
+ If story readiness, approval, evidence, or artifact blockers remain, report the blocker and suggest `/revela review`, `/revela research`, or a targeted user answer. Do not bypass with invented state.
119
+
120
+ ## Refine Rules
121
+
122
+ Use `/revela refine` for post-artifact reading, inspection, and editing.
123
+
124
+ - Reading should explain source, support strength, caveat, unsupported scope, narrative purpose, related risks/objections, research gaps, and artifact coverage.
125
+ - Pure artifact polish may stay artifact-level: layout, typography, spacing, crop, visual hierarchy, export mechanics, and deck contract fixes.
126
+ - Meaning-changing edits must update canonical narrative first, then run story readiness/approval or explicit override, then remake affected artifacts.
127
+ - `/revela edit` has been removed; use `/revela refine`. Deprecated `/revela inspect` routes to Refine.
128
+
129
+ ## Design Surface
130
+
131
+ Use `/revela design` for visual-system work: list/use/new/edit/preview/install/remove designs.
132
+
133
+ Do not inject design CSS, layout catalogs, component indexes, chart rules, or deck HTML skeletons during init, research, or story. Fetch design context only for make-deck or explicit design-authoring workflows.
134
+
55
135
  ## Boundaries
56
136
 
57
137
  - Do not write or overwrite `decks/*.html` in narrative mode.
58
- - Do not call `revela-decks review` in narrative mode; that is the deck/artifact gate.
59
- - Do not apply evidence candidates, bind evidence, or rewrite slide text unless the user explicitly asks.
60
- - Do not fetch design CSS, layouts, components, chart rules, or HTML skeletons in narrative mode.
138
+ - Do not call `revela-decks review` in story mode; that is the deck/artifact gate.
139
+ - Do not apply evidence candidates, bind evidence, or rewrite slide text unless the user explicitly asks or the active workflow requires it with clear support.
61
140
  - Do not store secrets, credentials, tokens, or sensitive personal information.
62
141
  - Do not infer long-term user preferences from one-off tasks.
63
-
64
- When the user wants deck/artifact readiness, direct them to `/revela deck --review`. When they want to render a deck, wait for the explicit deck workflow.
142
+ - If source support is missing, keep the gap visible instead of making the claim sound proven.
package/skill/SKILL.md CHANGED
@@ -374,7 +374,7 @@ After the user confirms the slide plan, update `DECKS.json` through `revela-deck
374
374
  3. Call `revela-designs` tool with `action: "read"` and `component` set to ALL component
375
375
  names you plan to use (comma-separated, e.g. `component: "card,stat-card,evidence-list"`).
376
376
  4. Use `revela-decks` action `upsertDeck` to mark `requiredInputs.designLayoutsFetched` complete.
377
- 5. Run `/revela review` or call `revela-decks` action `review` yourself. The tool must compute readiness from `DECKS.json`.
377
+ 5. Run `/revela make deck --review` or call `revela-decks` action `review` yourself. The tool must compute readiness from `DECKS.json`.
378
378
  6. Use `revela-decks` action `read` and confirm `writeReadiness.status` is `ready` with no blockers.
379
379
  7. Generate HTML that **exactly matches** the fetched examples — copy the HTML structure verbatim.
380
380
 
@@ -460,16 +460,11 @@ deck HTML writes or patches. If the tool result reports compliance issues, fix
460
460
  them immediately by removing the offending classes and replacing them with the
461
461
  closest component from the Component Index.
462
462
 
463
- Do not run `revela-qa` after writing or editing HTML unless the user explicitly
464
- asks for diagnostics. PDF/PPTX export commands run hard-error pre-export QA
465
- automatically and will report overflow issues that must be fixed before exporting.
466
-
467
- ### Inline Editing
468
-
469
- **Always include inline editing** in every generated presentation. The complete
470
- reference implementation is provided in the active design's `@design:foundation`
471
- section. Follow it exactly — pay attention to the hover-delay pattern, editable
472
- element selector list, and `window.getEditedHTML()` definition.
463
+ Deck HTML writes and patches automatically run Artifact QA. If hard errors are
464
+ reported, fix them immediately with the smallest patch; Refine opens only after
465
+ hard errors pass. Do not add deck-local inline editing JavaScript, `contenteditable`
466
+ handlers, `editable` classes, or `window.getEditedHTML()` implementations. Post-
467
+ artifact editing belongs in `/revela refine`, not inside generated deck HTML.
473
468
 
474
469
  ### Image Rules
475
470
 
package/tools/decks.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { tool } from "@opencode-ai/plugin"
2
2
  import {
3
3
  createDeckSpec,
4
+ confirmDeckPlan,
4
5
  DECKS_STATE_FILE,
5
6
  normalizeWorkspaceDeckState,
6
7
  readOrCreateDecksState,
@@ -67,7 +68,7 @@ export default tool({
67
68
  "It stores workspace narrative state, active deck specs, per-slide content/layout/components, and computes narrative or deck readiness.",
68
69
  args: {
69
70
  action: tool.schema
70
- .enum(["read", "init", "upsertDeck", "upsertSlides", "upsertNarrative", "compileDeckPlan", "backfillClaimRefs", "review", "reviewNarrative", "approveNarrative", "deriveResearchGaps", "upsertResearchGaps", "updateResearchGap", "closeResearchGap", "applyEvidenceCandidates", "attachResearchFindings", "remember"])
71
+ .enum(["read", "init", "upsertDeck", "upsertSlides", "upsertNarrative", "compileDeckPlan", "confirmDeckPlan", "backfillClaimRefs", "review", "reviewNarrative", "approveNarrative", "deriveResearchGaps", "upsertResearchGaps", "updateResearchGap", "closeResearchGap", "applyEvidenceCandidates", "attachResearchFindings", "remember"])
71
72
  .describe("Action to perform on DECKS.json."),
72
73
  summary: tool.schema.boolean().optional().describe("For read: return a compact summary instead of full state."),
73
74
  goal: tool.schema.string().optional().describe("For upsertDeck: deck goal."),
@@ -251,8 +252,8 @@ export default tool({
251
252
  findingsFile: tool.schema.string().optional().describe("For attachResearchFindings: workspace-relative researches/{topic}/{axis}.md file to attach to researchPlan."),
252
253
  researchAxis: tool.schema.string().optional().describe("For attachResearchFindings: researchPlan axis to attach the findings file to. Required when filename matching would be ambiguous."),
253
254
  researchStatus: tool.schema.enum(["done", "read"]).optional().describe("For attachResearchFindings: optional explicit status to set on the matched research axis."),
254
- approvalNote: tool.schema.string().optional().describe("For approveNarrative: optional note explaining the approval or override."),
255
- approvalBy: tool.schema.enum(["user", "override"]).optional().describe("For approveNarrative: use override only for explicit render overrides, not normal strategic approval."),
255
+ approvalNote: tool.schema.string().optional().describe("For approveNarrative or confirmDeckPlan: optional note explaining the approval, override, or deck plan confirmation."),
256
+ approvalBy: tool.schema.enum(["user", "override"]).optional().describe("For approveNarrative or confirmDeckPlan: use override only for explicit render overrides, not normal strategic approval or deck plan confirmation."),
256
257
  approvalScope: tool.schema.enum(["narrative", "render_override"]).optional().describe("For approveNarrative: narrative approval or explicit render override scope."),
257
258
  gapId: tool.schema.string().optional().describe("For updateResearchGap/closeResearchGap: canonical research gap id."),
258
259
  researchGaps: tool.schema.array(tool.schema.object({
@@ -428,6 +429,31 @@ export default tool({
428
429
  return JSON.stringify({ ok: true, path: DECKS_STATE_FILE, result: compiled.result, deck: compiled.state.activeDeck ? compiled.state.decks[compiled.state.activeDeck] : undefined, narrative: compiled.state.narrative }, null, 2)
429
430
  }
430
431
 
432
+ if (args.action === "confirmDeckPlan") {
433
+ if (args.approvalBy && args.approvalBy !== "user") return JSON.stringify({ ok: false, error: "confirmDeckPlan requires approvalBy=user" })
434
+ const confirmed = confirmDeckPlan(state, {
435
+ approvedBy: "user",
436
+ note: args.approvalNote,
437
+ })
438
+ if (confirmed.result.confirmed) {
439
+ recordWorkspaceAction(confirmed.state, {
440
+ type: "deck.plan_confirmed",
441
+ actor: "revela-decks",
442
+ inputs: { activeDeck: state.activeDeck, approvalBy: "user" },
443
+ outputs: {
444
+ slug: confirmed.result.slug,
445
+ narrativeHash: confirmed.result.narrativeHash,
446
+ planHash: confirmed.result.planHash,
447
+ },
448
+ status: "success",
449
+ summary: args.approvalNote?.trim() || "User confirmed the compiled deck plan.",
450
+ nodeIds: [confirmed.state.narrative?.id, confirmed.result.slug ? `deck:${confirmed.result.slug}` : undefined].filter((item): item is string => Boolean(item)),
451
+ })
452
+ }
453
+ writeDecksState(workspaceRoot, confirmed.state)
454
+ return JSON.stringify({ ok: confirmed.result.confirmed, path: DECKS_STATE_FILE, result: confirmed.result, deck: confirmed.state.activeDeck ? confirmed.state.decks[confirmed.state.activeDeck] : undefined }, null, 2)
455
+ }
456
+
431
457
  if (args.action === "backfillClaimRefs") {
432
458
  const backfilled = backfillSlideClaimRefsFromCoverage(state)
433
459
  writeDecksState(workspaceRoot, backfilled.state)
@@ -10,7 +10,7 @@ export default tool({
10
10
  "Render Revela's read-only narrative claim-flow UI from the current deterministic narrative map plus an optional localized display model. " +
11
11
  "This tool validates display IDs against DECKS.json, opens a local HTML view, and never mutates workspace state.",
12
12
  args: {
13
- language: tool.schema.string().describe("UI language request from /revela narrative. May be any language tag or language name, such as en, zh-CN, fr, de, Korean, Arabic, or Portuguese-BR."),
13
+ language: tool.schema.string().describe("UI language request from /revela story or /revela narrative. May be any language tag or language name, such as en, zh-CN, fr, de, Korean, Arabic, or Portuguese-BR."),
14
14
  narrativeHash: tool.schema.string().optional().describe("Narrative hash from the prompt projection. Used to detect stale display prompts."),
15
15
  displayModel: tool.schema.object({
16
16
  version: tool.schema.number().describe("Must be 1."),
package/tools/qa.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * tools/qa.ts
3
3
  *
4
- * revela-qa — Hard-error quality assurance for generated slide HTML files.
4
+ * revela-qa — Artifact quality assurance for generated slide HTML files.
5
5
  *
6
6
  * Exposed as a manual diagnostic tool. Export commands run pre-export QA automatically.
7
7
  */
@@ -9,15 +9,16 @@
9
9
  import { tool } from "@opencode-ai/plugin"
10
10
  import { resolve } from "path"
11
11
  import { existsSync } from "fs"
12
- import { runQA, formatReport } from "../lib/qa"
12
+ import { extractDesignClasses } from "../lib/design/designs"
13
+ import { formatArtifactQAReport, runArtifactQA } from "../lib/qa/artifact"
13
14
 
14
15
  export default tool({
15
16
  description:
16
- "Run hard-error checks on a generated slide HTML file. " +
17
+ "Run artifact QA on a generated slide HTML file. " +
17
18
  "Opens the file in a headless browser and measures actual rendered geometry. " +
18
- "Checks for element overflow. " +
19
+ "Checks deck contract, component compliance, exact 1920x1080 canvas, scrollbars, element overflow, text overflow, and content/evidence density warnings. " +
19
20
  "Returns a structured report with specific issues and fix instructions. " +
20
- "Normally PDF/PPTX export commands run this automatically; call it directly only for explicit diagnostics.",
21
+ "Deck writes and PDF/PPTX export commands run QA automatically; call it directly for explicit diagnostics.",
21
22
  args: {
22
23
  file: tool.schema
23
24
  .string()
@@ -39,20 +40,25 @@ export default tool({
39
40
  }
40
41
 
41
42
  try {
42
- const report = await runQA(filePath)
43
- const formatted = formatReport(report)
43
+ let vocabulary
44
+ try {
45
+ vocabulary = extractDesignClasses()
46
+ } catch {
47
+ // Design may not be installed or may have no markers.
48
+ }
49
+ const report = await runArtifactQA({ workspaceRoot: directory || process.cwd(), filePath, vocabulary })
50
+ const formatted = formatArtifactQAReport(report)
44
51
 
45
52
  // Prepend a compact JSON summary for programmatic use if needed
46
53
  const jsonSummary = JSON.stringify({
47
- totalIssues: report.totalIssues,
48
- errors: report.errorCount,
54
+ passed: report.passed,
55
+ errors: report.hardErrorCount,
49
56
  warnings: report.warningCount,
50
- slidesWithIssues: report.slides.filter((s) => s.issues.length > 0).map((s) => s.index + 1),
51
57
  })
52
58
 
53
59
  return `<!-- QA Summary: ${jsonSummary} -->\n\n${formatted}`
54
60
  } catch (err: any) {
55
- return `Error running hard-error QA: ${err?.message ?? String(err)}\n\nMake sure Chrome is installed at /Applications/Google Chrome.app`
61
+ return `Error running artifact QA: ${err?.message ?? String(err)}\n\nMake sure Chrome is installed at /Applications/Google Chrome.app`
56
62
  }
57
63
  },
58
64
  })