@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 +3 -0
- package/README.zh-CN.md +3 -0
- package/lib/agents/research-prompt.ts +12 -4
- package/lib/commands/init.ts +4 -2
- package/lib/commands/review.ts +11 -5
- package/lib/decks-state.ts +66 -6
- package/package.json +1 -1
- package/tools/decks.ts +10 -4
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
|
package/lib/commands/init.ts
CHANGED
|
@@ -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.
|
|
52
|
-
10.
|
|
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.
|
package/lib/commands/review.ts
CHANGED
|
@@ -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
|
|
37
|
-
4.
|
|
38
|
-
5.
|
|
39
|
-
6.
|
|
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.
|
package/lib/decks-state.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
525
|
-
"Add quote
|
|
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(
|
|
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
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
|
-
|
|
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(),
|