@cyber-dash-tech/revela 0.8.7 → 0.8.8

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
@@ -209,6 +209,7 @@ Minimum readiness conditions:
209
209
  - source materials are identified or explicitly deemed unnecessary
210
210
  - research need is assessed
211
211
  - needed research findings have been read and reflected in the slide specs
212
+ - evidence-sensitive claims have slide-level evidence with useful source trace when available, such as `findingsFile`, `sourcePath`, `location`, `quote`, `url`, or `caveat`
212
213
  - the user has confirmed the slide plan
213
214
  - required design layouts and components have been fetched
214
215
  - every slide has a title, layout, components, and structured content
@@ -225,6 +226,8 @@ The gate checks:
225
226
  - every slide has title, layout, components, and structured content
226
227
  - every needed research axis is `done`, `read`, or `skipped`
227
228
 
229
+ `/revela review` distinguishes missing evidence from weak source-only evidence. A claim with no evidence remains a blocker; evidence that only names a source is reported as a warning so the agent can add source trace before writing the deck.
230
+
228
231
  If the gate blocks a write, Revela writes a marker file under `.opencode/revela/blocked-writes/` instead of creating or overwriting the deck HTML. This makes the failure visible to the agent while keeping the real deck file untouched.
229
232
 
230
233
  For `apply_patch`, Revela only checks whether the patch touches `decks/*.html`. If not ready, the whole patch is replaced with a blocked marker patch. The `edit` tool is not gated.
package/README.zh-CN.md CHANGED
@@ -208,6 +208,7 @@ Revela 使用工作区根目录的 `DECKS.json` 做跨会话记忆和 deck 生
208
208
  - source materials 已识别,或明确不需要源材料
209
209
  - research need 已评估
210
210
  - 需要调研时,相关 findings 已读取并反映到逐页规格中
211
+ - evidence-sensitive claim 尽量带有逐页 evidence 和可用 source trace,例如 `findingsFile`、`sourcePath`、`location`、`quote`、`url` 或 `caveat`
211
212
  - 用户已确认 slide plan
212
213
  - 需要的 design layouts 和 components 已获取
213
214
  - 每页都有 title、layout、components 和结构化 content
@@ -224,6 +225,8 @@ Revela 使用工作区根目录的 `DECKS.json` 做跨会话记忆和 deck 生
224
225
  - 每页都有 title、layout、components 和结构化 content
225
226
  - 每个 needed research axis 都是 `done`、`read` 或 `skipped`
226
227
 
228
+ `/revela review` 会区分缺失 evidence 和较弱的 source-only evidence。完全没有 evidence 的 claim 仍是 blocker;只写了 source 名称但缺少 source trace 的 evidence 会作为 warning 报告,方便 agent 在写 deck 前补足溯源信息。
229
+
227
230
  如果门禁阻止写入,Revela 会在 `.opencode/revela/blocked-writes/` 下写一个 marker 文件,而不是创建或覆盖真实 HTML deck。这样 agent 能看到失败原因,同时真实 deck 文件不会被污染。
228
231
 
229
232
  对 `apply_patch`,Revela 只检查 patch 是否触碰 `decks/*.html`。如果未 ready,整个 patch 会被替换成 blocked marker patch。`edit` 工具不做门禁。
@@ -29,7 +29,7 @@ Given a research brief specifying your topic and axis, you will:
29
29
  2. Use \`DECKS.json\` through \`revela-decks\` as the workspace material index when it exists
30
30
  3. Run a lightweight workspace freshness check when needed
31
31
  4. Search the web for current data, reports, and case studies when the brief requires it
32
- 5. Write all findings to ONE structured file: \`researches/{topic-key}/{axis-name}.md\`
32
+ 5. Write all findings to ONE structured file: \`researches/{topic-key}/{axis-name}.md\` with source trace detailed enough for slide-level evidence mapping
33
33
  6. Return a brief summary of what you found
34
34
 
35
35
  ---
@@ -112,18 +112,21 @@ Use **\`revela-research-save\`** to write ONE file with all your findings.
112
112
  - \`content\`: structured findings using the four sections below
113
113
  - \`sources\`: list of all URLs and filenames used
114
114
 
115
+ The primary agent will map your findings into \`DECKS.json\` slide-level evidence.
116
+ Preserve compact source trace so it can do that without rediscovering sources.
117
+
115
118
  ### Findings file format
116
119
 
117
120
  Use these four sections — omit any that are empty:
118
121
 
119
122
  \`\`\`markdown
120
123
  ## Data
121
- - {stat or finding} [Source: {url or filename}]
122
- - {stat or finding} [Source: {url or filename}]
124
+ - {stat or finding} [Source: {url or filename}; Location: {page/slide/sheet/section if known}; Quote: "{short exact snippet if available}"; Caveat: {scope/uncertainty if relevant}]
125
+ - {stat or finding} [Source: {url or filename}; Location: {page/slide/sheet/section if known}; Quote: "{short exact snippet if available}"; Caveat: {scope/uncertainty if relevant}]
123
126
  (5–10 items, most argument-worthy only)
124
127
 
125
128
  ## Cases
126
- - **{Company/Entity}**: {1–2 sentence profile with key metrics} [Source: {url}]
129
+ - **{Company/Entity}**: {1–2 sentence profile with key metrics} [Source: {url or filename}; Location: {page/slide/sheet/section if known}; Caveat: {scope/uncertainty if relevant}]
127
130
  (2–4 entries max)
128
131
 
129
132
  ## Images
@@ -136,6 +139,10 @@ Use these four sections — omit any that are empty:
136
139
 
137
140
  Content rules:
138
141
  - Every data point MUST have inline source attribution: \`[Source: {url}]\` or \`[Source: AI knowledge — verify]\` or \`[Source: {filename}]\`
142
+ - For workspace documents, identify the original filename and available page, slide, sheet, or section location. Do not cite only the extracted summary.
143
+ - When extracted materials were used, include \`extractedTextPath\` or \`extractedManifestPath\` when useful for traceability.
144
+ - Preserve compact direct snippets or quotes when available. Do not invent quotes, page references, locations, URLs, or caveats.
145
+ - Include caveats or scope limitations for estimates, rankings, market sizes, forecasts, and conflicting sources.
139
146
  - Preserve raw numbers and direct quotes — do not summarize prematurely
140
147
  - Use tables for comparative data when 3+ entities are compared
141
148
  - Include publication dates where available
@@ -170,6 +177,7 @@ Gaps:
170
177
  - **Always** call \`revela-extract-document-materials\` for every selected workspace file before deciding which extracted materials to read next
171
178
  - **Avoid** repeated extraction or deep reading for files that are clearly irrelevant to this axis
172
179
  - **Always** include source attribution on every data point
180
+ - **Always** preserve source trace: URL or filename, location when available, compact quote/snippet when available, and caveat/scope where relevant
173
181
  - **Always** use tables for comparative data (more useful than bullets for presentations)
174
182
  - **Preserve** raw data — the primary agent will select what to include in slides
175
183
  - **Note** data freshness — include publication dates where available
@@ -48,8 +48,10 @@ Workflow:
48
48
  6. Before extracting or deeply reading a selected document, check \`DECKS.json.workspace.sourceMaterials\`. If the same path has the same fingerprint and valid extraction paths, reuse those paths instead of repeating extraction.
49
49
  7. Read only the materials needed to form a conservative workspace memory. Do not exhaustively read every file if the workspace is large.
50
50
  8. If this conversation or the workspace contains a concrete deck task or an existing deck artifact, call \`revela-decks\` with action \`upsertDeck\` and later \`upsertSlides\` for explicit deck information. Do not pass or ask for a deck key; the tool uses the workspace folder name internally. Do not mark readiness ready during init.
51
- 9. When adopting an existing HTML deck, analyze the artifact and create one conservative \`SlideSpec\` per identifiable slide/page. The \`SlideSpec[]\` itself is the worklist; do not create a separate target slide count.
52
- 10. Report what was initialized or updated and list any open questions.
51
+ 9. When adopting an existing HTML deck, analyze the artifact and create one conservative \`SlideSpec\` per identifiable slide/page. Record only visible source notes or explicit source information as evidence; do not infer original evidence that is not present in the artifact.
52
+ 10. When a read or extracted source material clearly supports a specific slide claim, you may attach compact evidence fields such as \`sourcePath\`, \`location\`, \`extractedTextPath\`, or \`extractedManifestPath\`. Attach extraction cache paths only when they support that specific claim, not to every slide by default.
53
+ 11. Treat \`workspace.sourceMaterials\` as a reusable candidate index, not proof by itself. A source material record alone is not slide evidence.
54
+ 12. Report what was initialized or updated and list any open questions.
53
55
 
54
56
  Memory rules:
55
57
  - Only write facts supported by workspace files into ${DECKS_STATE_FILE} workspace state, source materials, deck memory, and open questions.
@@ -19,6 +19,7 @@ Goal:
19
19
  - Do not write, patch, or directly edit ${DECKS_STATE_FILE}. Use the \`revela-decks\` tool for all state changes.
20
20
  - Let \`revela-decks\` action \`review\` compute writeReadiness; do not manually set readiness to ready.
21
21
  - Treat this as an evidence-readiness review, not only a checklist review: unsupported numbers, market sizing, recommendations, competitor comparisons, technical assertions, or investment conclusions should be made visible before writing.
22
+ - Treat source trace mapping as part of evidence readiness: when research findings have been read, relevant findings should appear in slide-level \`slides[].evidence[]\` records rather than only in raw research files.
22
23
 
23
24
  Current state:
24
25
  - ${state}
@@ -33,19 +34,23 @@ Workspace boundary rules:
33
34
  Workflow:
34
35
  1. Call \`revela-decks\` with action \`read\` for the current workspace deck.
35
36
  2. If no current deck exists but the conversation contains enough deck context, call \`revela-decks\` action \`upsertDeck\` with goal, outputPath, theme, requiredInputs, and researchPlan. Do not invent or ask for a deck key; the tool uses the workspace folder name internally.
36
- 3. If a user-confirmed slide plan is available, call \`revela-decks\` action \`upsertSlides\` with every slide's title, purpose, layout, components, structured content, evidence, visuals, and status.
37
- 4. Only set requiredInputs fields true when explicit conversation state, files read, research findings read, selected design, fetched layouts/components, or user confirmation supports them. Do not infer completion.
38
- 5. Call \`revela-decks\` action \`review\`. The tool computes and writes \`writeReadiness\` plus structured readiness issues for the current workspace deck.
39
- 6. Briefly report whether the deck is ready. If blocked, list the exact blockers returned by the tool. If warnings exist, list them after blockers as residual risks.
37
+ 3. If \`researchPlan[].status\` is \`done\` or \`read\` and \`researchPlan[].findingsFile\` exists, verify that evidence-sensitive slide claims are backed by compact \`slides[].evidence[]\` records that reference the relevant findings file or source material where known.
38
+ 4. If a user-confirmed slide plan is available, call \`revela-decks\` action \`upsertSlides\` with every slide's title, purpose, layout, components, structured content, evidence, visuals, and status.
39
+ 5. Prefer evidence records with \`findingsFile\`, \`sourcePath\`, \`location\`, \`quote\`, \`url\`, \`caveat\`, \`extractedTextPath\`, or \`extractedManifestPath\` when those fields are known from research files or extracted workspace materials.
40
+ 6. Do not invent quotes, page references, locations, URLs, caveats, or extraction paths. If source trace is missing, preserve the blocker or warning and report exactly what trace is needed.
41
+ 7. Only set requiredInputs fields true when explicit conversation state, files read, research findings read, selected design, fetched layouts/components, or user confirmation supports them. Do not infer completion.
42
+ 8. Call \`revela-decks\` action \`review\`. The tool computes and writes \`writeReadiness\` plus structured readiness issues for the current workspace deck.
43
+ 9. Briefly report whether the deck is ready. If blocked, list the exact blockers returned by the tool. If warnings exist, list them after blockers as residual risks.
40
44
 
41
45
  Minimum conditions for \`ready\`:
42
46
  - Topic, audience, slide count, language, and visual style/design are decided.
43
47
  - Source materials have been identified or explicitly deemed unnecessary.
44
48
  - Research need has been assessed.
45
49
  - If research is needed, all relevant findings have been read and reflected in the slide specs.
50
+ - Read or done research findings are mapped into \`slides[].evidence[]\` where they support evidence-sensitive slide claims.
46
51
  - The user has confirmed the slide plan.
47
52
  - ${DECKS_STATE_FILE} contains per-slide specs with content, layout, components, and evidence where applicable.
48
- - Evidence-sensitive slide claims have compact evidence references. Numeric claims and strong recommendations should not be unsupported.
53
+ - Evidence-sensitive slide claims have compact evidence references with source trace where available. Numeric claims and strong recommendations should not be unsupported or source-only when trace exists.
49
54
  - The needed design layouts and components have been fetched with \`revela-designs read\`.
50
55
  - No unresolved blockers remain.
51
56
 
@@ -54,6 +59,7 @@ Report format:
54
59
  - If blocked, list each blocker with slide index/title when the tool provides it, the issue type, and the suggested next action.
55
60
  - If warnings exist but the deck is otherwise ready, say the deck can be written but note the residual risks.
56
61
  - Do not invent evidence or silently downgrade blockers. Use the tool result as authoritative.
62
+ - When reporting weak evidence, say whether the missing trace is \`findingsFile\`, \`sourcePath\`, \`location\`, \`quote\`, \`url\`, or \`caveat\` if that is clear from the reviewed materials.
57
63
 
58
64
  Rules:
59
65
  - Do not write or overwrite \`decks/*.html\` during review.
@@ -117,6 +117,12 @@ export interface EvidenceRef {
117
117
  quote?: string
118
118
  page?: string
119
119
  url?: string
120
+ sourcePath?: string
121
+ location?: string
122
+ findingsFile?: string
123
+ caveat?: string
124
+ extractedTextPath?: string
125
+ extractedManifestPath?: string
120
126
  }
121
127
 
122
128
  export interface VisualBrief {
@@ -164,6 +170,8 @@ export interface ReadinessIssue {
164
170
  claimText?: string
165
171
  }
166
172
 
173
+ const SOURCE_TRACE_ACTION = "Add slide evidence with source plus source trace such as findingsFile or sourcePath, and quote, location, url, or caveat where available; otherwise reframe the claim as an explicit assumption/opinion."
174
+
167
175
  export function decksStatePath(workspaceRoot: string): string {
168
176
  return join(workspaceRoot, DECKS_STATE_FILE)
169
177
  }
@@ -432,14 +440,58 @@ export function buildDecksStatePromptLayer(workspaceRoot: string, maxChars = 140
432
440
  const compact = {
433
441
  sourceOfTruth: DECKS_STATE_FILE,
434
442
  activeDeck: activeKey,
435
- workspace: state.workspace,
436
- deck: active,
443
+ workspace: compactWorkspaceForPrompt(state.workspace),
444
+ deck: active ? compactDeckForPrompt(active) : undefined,
437
445
  }
438
446
  let text = JSON.stringify(compact, null, 2)
439
447
  if (text.length > maxChars) text = text.slice(0, maxChars).trimEnd() + "\n[DECKS.json state truncated for prompt size.]"
440
448
  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, and write readiness.\n- The decks map is compatibility storage; operate only on the current workspace deck.\n- Do not edit ${DECKS_STATE_FILE} directly; use the revela-decks tool.\n- Before writing decks/*.html, the current deck must have writeReadiness.status=ready and a complete slide spec, and its outputPath must match the target file.`
441
449
  }
442
450
 
451
+ function compactWorkspaceForPrompt(workspace: DecksState["workspace"]): DecksState["workspace"] {
452
+ return {
453
+ brief: truncatePromptText(workspace.brief),
454
+ sourceMaterials: workspace.sourceMaterials.map((source) => ({
455
+ ...source,
456
+ summary: truncatePromptText(source.summary),
457
+ bestUsedFor: truncatePromptText(source.bestUsedFor),
458
+ })),
459
+ preferences: workspace.preferences,
460
+ deckMemory: workspace.deckMemory,
461
+ openQuestions: workspace.openQuestions.map((question) => truncatePromptText(question)).filter(Boolean) as string[],
462
+ }
463
+ }
464
+
465
+ function compactDeckForPrompt(deck: DeckSpec): DeckSpec {
466
+ return {
467
+ ...deck,
468
+ slides: deck.slides.map((slide) => ({
469
+ ...slide,
470
+ content: {
471
+ ...slide.content,
472
+ speakerNotes: truncatePromptText(slide.content.speakerNotes),
473
+ },
474
+ evidence: slide.evidence.map(compactEvidenceForPrompt),
475
+ notes: truncatePromptText(slide.notes),
476
+ })),
477
+ }
478
+ }
479
+
480
+ function compactEvidenceForPrompt(evidence: EvidenceRef): EvidenceRef {
481
+ return {
482
+ ...evidence,
483
+ source: truncatePromptText(evidence.source, 180) ?? evidence.source,
484
+ quote: truncatePromptText(evidence.quote, 320),
485
+ caveat: truncatePromptText(evidence.caveat, 220),
486
+ }
487
+ }
488
+
489
+ function truncatePromptText(text: string | undefined, maxLength = 400): string | undefined {
490
+ if (!text) return undefined
491
+ if (text.length <= maxLength) return text
492
+ return `${text.slice(0, maxLength).trimEnd()}... [truncated]`
493
+ }
494
+
443
495
  function normalizeDecksState(input: DecksState): DecksState {
444
496
  const state: DecksState = {
445
497
  version: 1,
@@ -515,14 +567,14 @@ function computeDeckReadinessIssues(deck: DeckSpec, workspace: DecksState["works
515
567
  issues.push(blockerIssue(
516
568
  "missing_evidence",
517
569
  `Slide ${slide.index} has an evidence-sensitive claim without evidence: ${claim}`,
518
- "Add a compact evidence reference to slides[].evidence or reframe the claim as an explicit assumption/opinion.",
570
+ SOURCE_TRACE_ACTION,
519
571
  { ...slideRef, claimText: claim },
520
572
  ))
521
573
  } else if (claim && slide.evidence.some((item) => !hasEvidenceDetail(item))) {
522
574
  issues.push(warningIssue(
523
575
  "weak_evidence",
524
- `Slide ${slide.index} evidence for a high-risk claim has no quote, page, or URL detail: ${claim}`,
525
- "Add quote/page/url details where available so the writing agent can ground the slide more reliably.",
576
+ `Slide ${slide.index} evidence for a high-risk claim has no source trace detail: ${claim}`,
577
+ "Add source trace detail to this evidence record: findingsFile or sourcePath plus quote, location, url, or caveat where available so the writing agent can ground the slide reliably.",
526
578
  { ...slideRef, claimText: claim },
527
579
  ))
528
580
  }
@@ -592,7 +644,15 @@ function hasNumericClaim(text: string): boolean {
592
644
  }
593
645
 
594
646
  function hasEvidenceDetail(evidence: EvidenceRef): boolean {
595
- return Boolean(evidence.quote?.trim() || evidence.page?.trim() || evidence.url?.trim())
647
+ return Boolean(
648
+ evidence.quote?.trim() ||
649
+ evidence.page?.trim() ||
650
+ evidence.location?.trim() ||
651
+ evidence.url?.trim() ||
652
+ evidence.findingsFile?.trim() ||
653
+ evidence.sourcePath?.trim() ||
654
+ evidence.extractedTextPath?.trim()
655
+ )
596
656
  }
597
657
 
598
658
  const EVIDENCE_SENSITIVE_TERMS = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyber-dash-tech/revela",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "description": "OpenCode plugin that turns AI into an HTML slide deck generator",
5
5
  "type": "module",
6
6
  "main": "./index.ts",
package/tools/decks.ts CHANGED
@@ -86,10 +86,16 @@ export default tool({
86
86
  }).describe("Structured slide content."),
87
87
  evidence: tool.schema.array(tool.schema.object({
88
88
  source: tool.schema.string().describe("Source file, URL, or research note."),
89
- quote: tool.schema.string().optional(),
90
- page: tool.schema.string().optional(),
91
- url: tool.schema.string().optional(),
92
- })).optional().describe("Evidence references for this slide."),
89
+ quote: tool.schema.string().optional().describe("Compact quote or snippet supporting the slide claim."),
90
+ page: tool.schema.string().optional().describe("Legacy page reference; prefer location for new page/slide/sheet/section references."),
91
+ url: tool.schema.string().optional().describe("Source URL when available."),
92
+ sourcePath: tool.schema.string().optional().describe("Workspace source file path when the evidence came from a local material."),
93
+ location: tool.schema.string().optional().describe("Generic page, slide, sheet, section, or other source location reference."),
94
+ findingsFile: tool.schema.string().optional().describe("researches/{topic}/{axis}.md findings file that records the supporting evidence."),
95
+ caveat: tool.schema.string().optional().describe("Scope, uncertainty, or limitation that should travel with this evidence."),
96
+ extractedTextPath: tool.schema.string().optional().describe("Reusable extracted text cache path when this evidence came from extracted materials."),
97
+ extractedManifestPath: tool.schema.string().optional().describe("Reusable extracted materials manifest path when available."),
98
+ })).optional().describe("Compact evidence references and source trace for this slide."),
93
99
  visuals: tool.schema.array(tool.schema.object({
94
100
  id: tool.schema.string().optional(),
95
101
  purpose: tool.schema.string().optional(),