@cyber-dash-tech/revela 0.16.4 → 0.17.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.
- package/README.md +7 -5
- package/README.zh-CN.md +7 -5
- package/lib/commands/brief.ts +9 -0
- package/lib/commands/help.ts +5 -2
- package/lib/commands/init.ts +42 -27
- package/lib/commands/narrative.ts +39 -6
- package/lib/commands/research.ts +36 -20
- package/lib/commands/review.ts +35 -28
- package/lib/ctx.ts +1 -1
- package/lib/decks-state.ts +38 -4
- package/lib/edit/prompt.ts +1 -1
- package/lib/hook-notifications.ts +53 -0
- package/lib/media/download.ts +23 -3
- package/lib/media/save.ts +1 -0
- package/lib/media/types.ts +1 -0
- package/lib/narrative-state/display.ts +74 -4
- package/lib/narrative-state/map-html.ts +242 -107
- package/lib/narrative-state/render-plan.ts +238 -35
- package/lib/narrative-state/research-binding-eval.ts +260 -0
- package/lib/narrative-state/research-gaps.ts +2 -88
- package/lib/narrative-vault/authoring-contract.ts +127 -0
- package/lib/narrative-vault/authoring-guard.ts +122 -0
- package/lib/narrative-vault/auto-compile.ts +134 -0
- package/lib/narrative-vault/bootstrap.ts +63 -0
- package/lib/narrative-vault/cache.ts +14 -0
- package/lib/narrative-vault/compile-mirror.ts +45 -0
- package/lib/narrative-vault/compile.ts +350 -0
- package/lib/narrative-vault/constants.ts +6 -0
- package/lib/narrative-vault/diagnostic-report.ts +117 -0
- package/lib/narrative-vault/export.ts +71 -0
- package/lib/narrative-vault/frontmatter.ts +41 -0
- package/lib/narrative-vault/hook-targets.ts +40 -0
- package/lib/narrative-vault/index.ts +18 -0
- package/lib/narrative-vault/inventory.ts +392 -0
- package/lib/narrative-vault/markdown-qa.ts +237 -0
- package/lib/narrative-vault/markdown.ts +34 -0
- package/lib/narrative-vault/migration.ts +52 -0
- package/lib/narrative-vault/mutate.ts +361 -0
- package/lib/narrative-vault/paths.ts +19 -0
- package/lib/narrative-vault/read.ts +52 -0
- package/lib/narrative-vault/relations.ts +32 -0
- package/lib/narrative-vault/source-loader.ts +19 -0
- package/lib/narrative-vault/timestamp.ts +32 -0
- package/lib/narrative-vault/types.ts +44 -0
- package/lib/qa/checks.ts +206 -5
- package/lib/qa/measure.ts +63 -1
- package/lib/refine/server.ts +157 -20
- package/lib/source-materials.ts +98 -0
- package/lib/tool-result.ts +34 -0
- package/package.json +2 -2
- package/plugin.ts +60 -22
- package/skill/NARRATIVE_SKILL.md +25 -10
- package/skill/SKILL.md +6 -1
- package/tools/decks.ts +363 -67
- package/tools/narrative-view.ts +16 -0
- package/tools/research-save.ts +3 -0
- package/tools/workspace-scan.ts +1 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**English** | [中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@cyber-dash-tech/revela) [](LICENSE) [](https://www.npmjs.com/package/@cyber-dash-tech/revela) [](LICENSE) [](tests/) [](https://opencode.ai) [](https://bun.sh)
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<img src="assets/img/logo.png" alt="Revela" width="800" />
|
|
@@ -20,7 +20,7 @@ Its first render target is still the HTML slide deck: start a Revela workflow co
|
|
|
20
20
|
- injects one-shot workflow instructions for explicit commands such as `/revela init`, `/revela story`, and `/revela make --deck`
|
|
21
21
|
- switches into deck-render prompt mode only when you explicitly start `/revela make --deck`
|
|
22
22
|
- supports workspace document discovery, transparent text extraction for `.pdf`, `.docx`, `.pptx`, and `.xlsx`, and cached embedded-material extraction for those formats
|
|
23
|
-
-
|
|
23
|
+
- uses `revela-narrative/` as the editable Markdown narrative vault when present, with `DECKS.json` as the compatibility/render-state mirror
|
|
24
24
|
- reviews narrative readiness before artifact rendering, then separately gates deck HTML writes through deck/artifact readiness
|
|
25
25
|
- records review snapshots so stale readiness cannot silently authorize new deck HTML after important state changes
|
|
26
26
|
- treats HTML decks, PDF, and PPTX as render targets from shared workspace state rather than isolated output files
|
|
@@ -168,17 +168,19 @@ The ambient enabled or disabled state is session-level only.
|
|
|
168
168
|
|
|
169
169
|
### Workspace State
|
|
170
170
|
|
|
171
|
-
`
|
|
171
|
+
`revela-narrative/` is Revela's editable Markdown narrative vault when present. It stores the human/LLM-editable source for audience, decision, thesis, claims, evidence nodes, objections, risks, research gaps, and typed narrative relations.
|
|
172
|
+
|
|
173
|
+
`DECKS.json` remains Revela's compatibility and render-state file. It is still stored at the workspace root and remains readable as the current deck project state, but when a vault exists its top-level `narrative` is a compiled mirror from Markdown rather than the primary editing surface.
|
|
172
174
|
|
|
173
175
|
The state records:
|
|
174
176
|
|
|
175
177
|
- workspace source materials and reusable extraction cache paths
|
|
176
178
|
- research plans, saved findings, and compact action provenance
|
|
177
|
-
- canonical narrative
|
|
179
|
+
- compiled canonical narrative mirror, approvals, objections, risks, slide specs, claim candidates, and evidence trace
|
|
178
180
|
- render targets such as the active HTML deck plus derived PDF and PPTX artifacts
|
|
179
181
|
- review snapshots with input hashes so old readiness results become stale after meaningful state changes
|
|
180
182
|
|
|
181
|
-
|
|
183
|
+
New workspaces bootstrap `revela-narrative/` directly with `initNarrativeVault`; stable findings can be recorded as partial Markdown nodes without waiting for a complete story. `/revela init` is repeatable ingest: first runs consider all supported source files, later runs prioritize files added or modified after the latest vault Markdown timestamp plus same-path files whose fingerprint changed, then distill stable findings into vault nodes. Developer workspaces that still have a JSON narrative but no Markdown vault receive a migration hint from `revela-decks read` with `summary: true`; `exportNarrativeVault` can export that narrative into `revela-narrative/` without moving approvals, render targets, review snapshots, artifact coverage, actions, deck specs, or source material records into Markdown. Generated cache files live under `.opencode/revela/narrative-cache/` and should not be edited by hand. `writeReadiness.status: "ready"` is deck/artifact readiness only; it is never narrative approval.
|
|
182
184
|
|
|
183
185
|
Decks remain the primary authored artifact, but they are now treated as render targets from the same workspace state that can later support briefs, appendix material, Evidence Inspector views, Q&A, and interactive reading layers without duplicating source/evidence logic.
|
|
184
186
|
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | **中文**
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/@cyber-dash-tech/revela) [](LICENSE) [](https://www.npmjs.com/package/@cyber-dash-tech/revela) [](LICENSE) [](tests/) [](https://opencode.ai) [](https://bun.sh)
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<img src="assets/img/logo.png" alt="Revela" width="800" />
|
|
@@ -20,7 +20,7 @@ Revela 是一个 [OpenCode](https://opencode.ai) 插件,用来把工作区来
|
|
|
20
20
|
- 为 `/revela init`、`/revela story`、`/revela make --deck` 等显式命令注入一次性 workflow instructions
|
|
21
21
|
- 只有在显式运行 `/revela make --deck` 时,才切换到 deck-render prompt mode
|
|
22
22
|
- 支持工作区文档扫描,以及 `.pdf`、`.docx`、`.pptx`、`.xlsx` 的透明文本提取和嵌入素材缓存提取
|
|
23
|
-
-
|
|
23
|
+
- 存在 `revela-narrative/` 时,将它作为可编辑 Markdown narrative vault,并让 `DECKS.json` 作为兼容/render-state mirror
|
|
24
24
|
- 先检查 narrative readiness,再用独立 deck/artifact gate 保护 deck HTML 写入
|
|
25
25
|
- 记录 review snapshots,避免重要状态变化后旧的 ready 结果继续默默授权写入 deck HTML
|
|
26
26
|
- 把 HTML deck、PDF 和 PPTX 视为来自同一 workspace state 的 render targets,而不是互相孤立的输出文件
|
|
@@ -166,17 +166,19 @@ Active domain 只进入 narrative pipeline。它帮助 `init`、`research`、`st
|
|
|
166
166
|
|
|
167
167
|
### Workspace State
|
|
168
168
|
|
|
169
|
-
`
|
|
169
|
+
存在 `revela-narrative/` 时,它就是 Revela 可编辑的 Markdown narrative vault,用来保存 audience、decision、thesis、claims、evidence nodes、objections、risks、research gaps 和 typed narrative relations。
|
|
170
|
+
|
|
171
|
+
`DECKS.json` 仍然是 Revela 的兼容状态和 render-state 文件。它仍然保存在工作区根目录,也仍然可以理解为当前 deck 项目的状态入口;但当 vault 存在时,顶层 `narrative` 是从 Markdown 编译得到的 mirror,不再是主要编辑面。
|
|
170
172
|
|
|
171
173
|
状态中会记录:
|
|
172
174
|
|
|
173
175
|
- 工作区来源材料和可复用的 extraction cache 路径
|
|
174
176
|
- 调研计划、已保存 findings,以及精简的 action provenance
|
|
175
|
-
- canonical narrative
|
|
177
|
+
- 编译得到的 canonical narrative mirror、approvals、objections、risks、slide specs、claim candidates 和 evidence trace
|
|
176
178
|
- active HTML deck 以及派生 PDF、PPTX 等 render targets
|
|
177
179
|
- 带 input hash 的 review snapshots,使重要状态变化后旧的 readiness 自动变 stale
|
|
178
180
|
|
|
179
|
-
|
|
181
|
+
新工作区会直接用 `initNarrativeVault` bootstrap `revela-narrative/`;LLM 扫描到稳定 finding 后,可以先写入 partial Markdown nodes,不需要等待完整故事成型。`/revela init` 是可重复 ingest:首次运行会考虑所有支持的 source files,后续运行优先处理晚于最新 vault Markdown timestamp 的新增/修改文件,以及同一路径 fingerprint 变化的文件,并把稳定 finding 提炼进 vault nodes。仍只有 JSON narrative、还没有 Markdown vault 的开发期工作区,会在 `revela-decks read` 加 `summary: true` 时收到 migration hint;`exportNarrativeVault` 可以把该 narrative 导出到 `revela-narrative/`,同时不会把 approvals、render targets、review snapshots、artifact coverage、actions、deck specs 或 source material records 搬进 Markdown。生成缓存位于 `.opencode/revela/narrative-cache/`,不应手工编辑。`writeReadiness.status: "ready"` 只代表 deck/artifact readiness,永远不等于 narrative approval。
|
|
180
182
|
|
|
181
183
|
Deck 仍然是主要 authored artifact,但现在它是从同一份 workspace state 渲染出来的目标之一。后续 briefs、appendix material、Evidence Inspector views、Q&A 和 interactive reading layers 都可以复用同一套来源/证据逻辑,而不是各自生成孤立内容。
|
|
182
184
|
|
package/lib/commands/brief.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, writeFileSync } from "fs"
|
|
|
2
2
|
import { dirname, isAbsolute, join, normalize, resolve } from "path"
|
|
3
3
|
import { readDecksState, writeDecksState } from "../decks-state"
|
|
4
4
|
import { compileExecutiveBrief, DEFAULT_EXECUTIVE_BRIEF_PATH } from "../narrative-state/executive-brief"
|
|
5
|
+
import { compileNarrativeVault, formatVaultDiagnosticMarkdown, formatVaultDiagnosticReport, hasNarrativeVault } from "../narrative-vault"
|
|
5
6
|
|
|
6
7
|
export interface BriefArgs {
|
|
7
8
|
outputPath?: string
|
|
@@ -29,6 +30,14 @@ export async function handleBrief(
|
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const state = readDecksState(input.workspaceRoot)
|
|
33
|
+
if (hasNarrativeVault(input.workspaceRoot)) {
|
|
34
|
+
const vault = compileNarrativeVault(input.workspaceRoot, { fallbackApprovals: state.narrative?.approvals ?? [] })
|
|
35
|
+
const report = formatVaultDiagnosticReport(vault.diagnostics)
|
|
36
|
+
if (!report.ok) {
|
|
37
|
+
await send(`**Executive brief not rendered**\n\n${formatVaultDiagnosticMarkdown(report)}\n\nFix the narrative vault blockers before rendering.`)
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
}
|
|
32
41
|
const result = compileExecutiveBrief(state, { outputPath: input.outputPath })
|
|
33
42
|
if (!result.ok) {
|
|
34
43
|
await send(
|
package/lib/commands/help.ts
CHANGED
|
@@ -14,7 +14,7 @@ export async function handleHelp(
|
|
|
14
14
|
): Promise<void> {
|
|
15
15
|
const design = activeDesign()
|
|
16
16
|
const domain = activeDomain()
|
|
17
|
-
const status = ctx.enabled ? "enabled
|
|
17
|
+
const status = ctx.enabled ? "enabled - Revela prompt is loaded" : "disabled - run `/revela enable` or any workflow command"
|
|
18
18
|
await send(
|
|
19
19
|
`\`\`\`\n` +
|
|
20
20
|
` R E V E L A H e l p v${pkg.version}\n` +
|
|
@@ -23,7 +23,8 @@ export async function handleHelp(
|
|
|
23
23
|
`**Current**\n\n` +
|
|
24
24
|
`Status: ${status}\n` +
|
|
25
25
|
`Design: \`${design}\`\n` +
|
|
26
|
-
`Domain: \`${domain}\`\n
|
|
26
|
+
`Domain: \`${domain}\`\n` +
|
|
27
|
+
`Run \`/revela enable\` to load Revela context without starting a workflow, or run \`/revela disable\` to pause it. Workflow commands still auto-enable Revela.\n\n` +
|
|
27
28
|
`---\n\n` +
|
|
28
29
|
`**Workflow**\n\n` +
|
|
29
30
|
`1. \`init\` — discover workspace sources and capture intent\n` +
|
|
@@ -35,6 +36,8 @@ export async function handleHelp(
|
|
|
35
36
|
`---\n\n` +
|
|
36
37
|
`**Commands**\n\n` +
|
|
37
38
|
`\`/revela\` — show REVELA help\n` +
|
|
39
|
+
`\`/revela enable\` — enable Revela prompt/context without starting a workflow\n` +
|
|
40
|
+
`\`/revela disable\` — disable Revela prompt/context for this session\n` +
|
|
38
41
|
`\`/revela init\` — initialize or refresh workspace story state\n` +
|
|
39
42
|
`\`/revela research\` — research, bind evidence, and reduce story gaps\n` +
|
|
40
43
|
`\`/revela story [-l language]\` — open the read-only story workspace UI\n` +
|
package/lib/commands/init.ts
CHANGED
|
@@ -9,17 +9,15 @@ export function buildInitPrompt({
|
|
|
9
9
|
}): string {
|
|
10
10
|
const mode = exists
|
|
11
11
|
? `A ${DECKS_STATE_FILE} file already exists. Read it first through the revela-decks tool and update it conservatively.`
|
|
12
|
-
: `No ${DECKS_STATE_FILE} file exists yet.
|
|
12
|
+
: `No ${DECKS_STATE_FILE} file exists yet. Initialize the Markdown narrative vault through the revela-decks tool before writing narrative meaning.`
|
|
13
13
|
|
|
14
14
|
return `Initialize Revela narrative workspace state.
|
|
15
15
|
|
|
16
16
|
Goal:
|
|
17
|
-
- Build or
|
|
18
|
-
-
|
|
19
|
-
- Capture
|
|
20
|
-
- Do not treat initialization as permission to write a deck.
|
|
21
|
-
- Do not require slide count, visual style, design selection, output path, layout choices, or component choices during narrative initialization unless the user explicitly asks to render a deck now.
|
|
22
|
-
- ${DECKS_STATE_FILE} is the compatibility workspace-state file. Deck specs are render-target projections, not the center of initialization.
|
|
17
|
+
- Build or refresh ${DECKS_STATE_FILE} and the Markdown narrative vault from local workspace evidence.
|
|
18
|
+
- Treat init as repeatable ingest: discover files, register source materials, follow returned ingest task hints, and distill stable narrative meaning.
|
|
19
|
+
- Capture primary audience, belief before/after, decision/action, thesis, central claims, evidence availability, objections, risks, source materials, artifact history, and open questions.
|
|
20
|
+
- Do not treat initialization as permission to write a deck. Do not require slide count, visual style, design selection, output path, layout choices, or component choices unless the user explicitly asks to render.
|
|
23
21
|
|
|
24
22
|
Current state:
|
|
25
23
|
- ${mode}
|
|
@@ -33,26 +31,43 @@ Workspace boundary rules:
|
|
|
33
31
|
- Do not use \`~\`, \`..\`, or parent-directory traversal to discover files.
|
|
34
32
|
- If the current workspace appears too broad, stop and ask the user which workspace subdirectory to initialize instead of scanning outside or deeply across everything.
|
|
35
33
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
Expected tool use during init:
|
|
35
|
+
- \`revela-decks init\` and \`revela-decks initNarrativeVault\` are expected controlled workspace-state/vault boundaries. Empty-looking optional fields in tool UI are a schema display artifact, not user-provided evidence.
|
|
36
|
+
- Treat \`authoringContract\` returned by \`read(summary: true)\`, \`initNarrativeVault\`, or \`narrativeInventory\` as the Markdown authoring guide: valid node types, plain id convention, inline relation syntax, forbidden compatibility actions, and optional helper templates.
|
|
37
|
+
- Treat \`markdownQa\` returned by \`read(summary: true)\`, \`compileNarrativeVault\`, or \`revela-decks markdownQa\` as post-authoring repair feedback that is separate from compiler diagnostics. Fix \`repairCards\` by smallest repair; do not invent missing claims, evidence, source paths, URLs, quotes, or caveats just to clear QA. If \`compileNarrativeVault\` output does not visibly include \`markdownQa\`, call \`revela-decks markdownQa\` before final reporting.
|
|
38
|
+
- Before authoring claims, evidence, relations, objections, risks, or research gaps, inspect \`narrativeInventory\` from \`read(summary: true)\` or call \`revela-decks narrativeInventory\`. Reuse existing ids and relation targets. Do not invent evidence ids, claim ids, or relation targets before checking inventory unless you are intentionally creating the missing node in Markdown.
|
|
39
|
+
- Create/update content nodes first. Add graph edges afterward in the source node's \`## Relations\` section with plain node-id wikilinks. Do not use \`relations.md\`, typed wikilinks, or hand-written relation ids.
|
|
40
|
+
- You may directly maintain \`revela-narrative/**/*.md\` knowledge nodes. Use structured vault helpers only when they reduce schema risk or express a narrow lifecycle/evidence-binding action: \`bindResearchFindings\`, \`upsertVaultEvidence\`, \`upsertVaultResearchGap\`, \`updateVaultResearchGap\`, or similar targeted helpers.
|
|
41
|
+
- Use targeted vault helpers only when you have a complete payload for that node/action. If a helper returns missing fields, report the gap or repair Markdown directly; do not invent fields.
|
|
42
|
+
- Do not use JSON-era compatibility actions such as \`upsertResearchGaps\`, \`deriveResearchGaps\`, \`updateResearchGap\`, \`closeResearchGap\`, \`applyEvidenceCandidates\`, or \`upsertNarrative\` in vault workspaces. Follow the tool error and \`authoringContract\` replacement action.
|
|
43
|
+
- Direct Markdown patches must update existing sections in place. Do not duplicate stable headings such as \`## Evidence\`, \`## Caveats\`, \`## Relations\`, \`## Response\`, or \`## Mitigation\`.
|
|
44
|
+
- Do not append a second frontmatter block. A vault Markdown file must have one leading \`---\` frontmatter block only.
|
|
45
|
+
|
|
46
|
+
Minimum vault authoring contract:
|
|
47
|
+
- Supported \`type\` values are \`index\`, \`audience\`, \`decision\`, \`thesis\`, \`claim\`, \`evidence\`, \`objection\`, \`risk\`, and \`research-gap\`. Use \`research-gap\`, not \`researchGap\` or \`research_gap\`.
|
|
48
|
+
- New graph relations belong in node-local \`## Relations\` sections, for example \`- supports: [[claim-belief-change-purpose]] - Optional rationale.\` Compiler-generated ids are deterministic; never hand-write relation ids.
|
|
49
|
+
- Relation wikilinks reference plain frontmatter node ids directly. Do not write typed targets such as \`[[claim:claim-belief-change-purpose]]\`.
|
|
50
|
+
- Evidence nodes require source trace (\`source\`, \`sourcePath\` or \`url\` when known, \`location\` when known), \`supportScope\`, \`unsupportedScope\`, \`caveat\`, \`strength\`, a quoted/snippet body, and a \`## Relations\` line such as \`- supports: [[claim-id]]\` when the supported claim is explicit. Keep \`claimId\` only as compatibility fallback for existing vaults or helper outputs.
|
|
51
|
+
- When fixing a new node created earlier in the same turn, patch the broken line or section. Do not delete and recreate existing nodes just to fix \`type\`, frontmatter, or relation syntax.
|
|
52
|
+
|
|
53
|
+
Required workflow:
|
|
54
|
+
1. If ${DECKS_STATE_FILE} exists, call \`revela-decks read\` with \`summary: true\`. If \`migration.available: true\`, prefer \`exportNarrativeVault\`; if no vault exists, call \`initNarrativeVault\` before recording narrative meaning.
|
|
55
|
+
2. Call \`revela-workspace-scan\` with no \`path\` and \`max_depth: 2\`. Scan deeper only when the user points to a workspace-relative folder or expected files are missing.
|
|
56
|
+
3. Search workspace-local generated artifact history only when useful: \`decks/**/*.html\`, \`slides/**/*.html\`, \`presentations/**/*.html\`, \`decks/**/*.pdf\`, and \`slides/**/*.pdf\`.
|
|
57
|
+
4. Register scan results with \`revela-decks init\`. Treat returned \`ingest.suggestedTasks\` as the authoritative init task list. Each task includes \`path\`, \`reason\`, \`materialType\`, \`needsExtraction\`, and \`suggestedAction\`.
|
|
58
|
+
5. For selected relevant tasks, read directly when \`suggestedAction: "read_directly"\`; call \`revela-extract-document-materials\` first when \`suggestedAction: "extract_then_read"\`. Do not extract every document by default.
|
|
59
|
+
6. Before writing narrative meaning, inspect \`narrativeInventory\` from the latest \`read(summary: true)\` result or call \`revela-decks narrativeInventory\`. Then distill stable findings into \`revela-narrative/**/*.md\` using the Markdown authoring guide. Completeness is not a gate: write partial claims, caveats, unsupported scope, and research gaps rather than waiting for a complete story. Use optional helpers such as \`upsertVaultResearchGap\`, \`upsertVaultEvidence\`, or \`bindResearchFindings\` only when they fit the exact update. Preserve frontmatter ids and existing section headings when editing Markdown. Write nodes first; add inline \`## Relations\` edges afterward only when explicit.
|
|
60
|
+
7. After Markdown changes, rely on the vault write hook or call \`revela-decks markdownQa\`, then \`revela-decks compileNarrativeVault\`; keep \`markdownQa.repairCards\` separate from compiler blockers and fix both before treating the narrative as usable. If no explicit \`markdownQa\` result is visible after compile, call \`revela-decks markdownQa\` as a manual fallback. Do not use \`upsertNarrative\`.
|
|
61
|
+
8. If explicit deck/artifact information exists, record conservative deck specs only from visible information. Do not infer hidden evidence from generated artifacts.
|
|
62
|
+
9. Report initialized/updated/migrated state plus counts and paths for added, changed, newer-than-vault, unchanged, \`ingest.ingestCandidates\`, and \`ingest.suggestedTasks\`. Always include \`Markdown QA: clean\` or \`Markdown QA blockers:\` in the final report. If Markdown QA blockers remain, do not say the workspace initialized cleanly; say the vault was initialized but Markdown repairs remain.
|
|
63
|
+
|
|
64
|
+
Evidence boundary:
|
|
65
|
+
- \`workspace.sourceMaterials\` and ingest task hints are candidate context, not proof.
|
|
66
|
+
- A finding becomes canonical only when a vault node preserves source trace, quote/snippet, support scope, unsupported scope, caveat, and strength.
|
|
67
|
+
- Preserve graph meaning by writing explicit edges in node-local \`## Relations\` sections after nodes exist. Use plain node-id wikilinks and optional inline rationale.
|
|
68
|
+
- Intent briefs, proposals, and user-authored plans may support audience, decision, thesis, stakeholder framing, and stated internal intent. They do not by themselves prove market size, competitor performance, product-market fit, operating-model effectiveness, or external factual claims.
|
|
69
|
+
- If a source states an intended strategy but not its external factual basis, record the strategy as a claim with partial or missing support and add a research gap instead of binding it as strong evidence.
|
|
70
|
+
- A successful vault compile means the vault is structurally valid. It is not evidence readiness, narrative approval, or permission to make a deck/brief.
|
|
56
71
|
|
|
57
72
|
Narrative questions to ask only when missing:
|
|
58
73
|
- Who is the primary audience?
|
|
@@ -6,6 +6,8 @@ import { hasDecksState, readDecksState } from "../decks-state"
|
|
|
6
6
|
import { buildNarrativeMap, formatNarrativeMap } from "../narrative-state/map"
|
|
7
7
|
import { renderNarrativeMapHtmlWithDisplay } from "../narrative-state/map-html"
|
|
8
8
|
import { emptyDisplayModel, type NarrativeViewLanguage, type ValidatedNarrativeDisplayModel } from "../narrative-state/display"
|
|
9
|
+
import type { NarrativeApproval } from "../narrative-state/types"
|
|
10
|
+
import { compileNarrativeVault, formatVaultDiagnosticMarkdown, formatVaultDiagnosticReport, hasNarrativeVault } from "../narrative-vault"
|
|
9
11
|
|
|
10
12
|
export interface NarrativeArgs {
|
|
11
13
|
language: NarrativeViewLanguage
|
|
@@ -82,7 +84,8 @@ export async function handleNarrative(
|
|
|
82
84
|
|
|
83
85
|
const state = readDecksState(options.workspaceRoot)
|
|
84
86
|
const map = buildNarrativeMap(state)
|
|
85
|
-
const
|
|
87
|
+
const diagnosticsMarkdown = vaultDiagnosticsMarkdown(options.workspaceRoot, state.narrative?.approvals ?? [])
|
|
88
|
+
const markdown = [diagnosticsMarkdown, formatNarrativeMap(map)].filter(Boolean).join("\n\n")
|
|
86
89
|
|
|
87
90
|
if (options.openBrowser) {
|
|
88
91
|
const htmlPath = writeNarrativeMapHtml(map, options.display ?? emptyDisplayModel(options.language ?? "en"))
|
|
@@ -102,16 +105,35 @@ export async function handleNarrative(
|
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
|
|
108
|
+
function vaultDiagnosticsMarkdown(workspaceRoot: string, fallbackApprovals: NarrativeApproval[]): string {
|
|
109
|
+
if (!hasNarrativeVault(workspaceRoot)) return ""
|
|
110
|
+
const result = compileNarrativeVault(workspaceRoot, { fallbackApprovals })
|
|
111
|
+
return formatVaultDiagnosticMarkdown(formatVaultDiagnosticReport(result.diagnostics))
|
|
112
|
+
}
|
|
113
|
+
|
|
105
114
|
export function buildNarrativeViewPrompt(options: { workspaceRoot: string; language: NarrativeViewLanguage }): string {
|
|
106
115
|
if (!hasDecksState(options.workspaceRoot)) {
|
|
107
116
|
return "No `DECKS.json` found. Tell the user to run `/revela init` before opening the narrative view. Do not call any tool."
|
|
108
117
|
}
|
|
109
118
|
|
|
110
|
-
const
|
|
119
|
+
const state = readDecksState(options.workspaceRoot)
|
|
120
|
+
const map = buildNarrativeMap(state)
|
|
121
|
+
const vaultDiagnostics = hasNarrativeVault(options.workspaceRoot)
|
|
122
|
+
? formatVaultDiagnosticReport(compileNarrativeVault(options.workspaceRoot, { fallbackApprovals: state.narrative?.approvals ?? [] }).diagnostics)
|
|
123
|
+
: undefined
|
|
111
124
|
const projection = {
|
|
112
125
|
narrativeHash: map.snapshot.narrativeHash,
|
|
113
126
|
language: options.language,
|
|
114
127
|
snapshot: map.snapshot,
|
|
128
|
+
vaultDiagnostics: vaultDiagnostics
|
|
129
|
+
? {
|
|
130
|
+
ok: vaultDiagnostics.ok,
|
|
131
|
+
errorCount: vaultDiagnostics.errorCount,
|
|
132
|
+
warningCount: vaultDiagnostics.warningCount,
|
|
133
|
+
blockers: vaultDiagnostics.blockers.map((diagnostic) => ({ file: diagnostic.file, nodeId: diagnostic.nodeId, code: diagnostic.code, message: diagnostic.message, suggestedAction: diagnostic.suggestedAction })),
|
|
134
|
+
warnings: vaultDiagnostics.warnings.map((diagnostic) => ({ file: diagnostic.file, nodeId: diagnostic.nodeId, code: diagnostic.code, message: diagnostic.message, suggestedAction: diagnostic.suggestedAction })),
|
|
135
|
+
}
|
|
136
|
+
: undefined,
|
|
115
137
|
claims: map.claimFlow.map((claim) => ({
|
|
116
138
|
id: claim.id,
|
|
117
139
|
kind: claim.kind,
|
|
@@ -125,7 +147,7 @@ export function buildNarrativeViewPrompt(options: { workspaceRoot: string; langu
|
|
|
125
147
|
relations: map.claimRelations.map((relation) => ({ id: relation.id, fromClaimId: relation.fromClaimId, toClaimId: relation.toClaimId, relation: relation.relation, rationale: relation.rationale, inferred: relation.inferred })),
|
|
126
148
|
objections: map.objections.map((objection) => ({ id: objection.id, claimId: objection.claimId, priority: objection.priority, text: objection.text, response: objection.response })),
|
|
127
149
|
risks: map.risks.map((risk) => ({ id: risk.id, claimId: risk.claimId, severity: risk.severity, text: risk.text, mitigation: risk.mitigation })),
|
|
128
|
-
researchGaps: map.researchGaps.map((gap) => ({ id: gap.id, targetType: gap.targetType, targetId: gap.targetId, status: gap.status, priority: gap.priority, question: gap.question })),
|
|
150
|
+
researchGaps: map.researchGaps.map((gap) => ({ id: gap.id, targetType: gap.targetType, targetId: gap.targetId, status: gap.status, priority: gap.priority, question: gap.question, findingsFile: gap.findingsFile, evidenceBindingIds: gap.evidenceBindingIds, notes: gap.notes })),
|
|
129
151
|
artifactCoverage: map.artifactCoverage.map((artifact) => ({ type: artifact.type, outputPath: artifact.outputPath, stale: artifact.stale, coverageStatus: artifact.coverageStatus, affectedClaimIds: artifact.affectedClaimIds, missingClaimIds: artifact.missingClaimIds, slideRefs: artifact.slideRefs.map((ref) => ({ claimId: ref.claimId, slideIndex: ref.slideIndex, role: ref.role, match: ref.match, location: ref.location })) })),
|
|
130
152
|
}
|
|
131
153
|
|
|
@@ -143,16 +165,27 @@ Hard rules:
|
|
|
143
165
|
- Do not invent new claims, evidence, relations, slide coverage, source paths, findings files, quotes, or caveats.
|
|
144
166
|
- Preserve every claimId exactly.
|
|
145
167
|
- Preserve every relation endpoint exactly: fromClaimId, toClaimId, relation.
|
|
146
|
-
- You may only organize and localize display copy for the UI: pageTitle, summaryLine, section labels, claim card displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, relation displayLabel, and relation displayRationale.
|
|
168
|
+
- You may only organize and localize display copy for the UI: pageTitle, summaryLine, section labels, claim card displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, research gap displayQuestion, relation displayLabel, and relation displayRationale.
|
|
147
169
|
- For inferred relations, do not provide relation displayLabel or displayRationale; inferred relations are unconfirmed order notes, not causal/support/dependency judgments.
|
|
148
170
|
- relation displayRationale may only localize or clarify an existing canonical relation rationale. If relation.rationale is missing or the relation is inferred, do not provide displayRationale; the UI will show the missing or inferred status.
|
|
149
171
|
- Keep source paths, findings files, claim IDs, narrative hash, and numbers unchanged.
|
|
150
|
-
- Translate normal UI/display text into the target language request: pageTitle, summaryLine, labels, claim displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, relation displayLabel, and relation displayRationale.
|
|
172
|
+
- Translate normal UI/display text into the target language request: pageTitle, summaryLine, labels, claim displayTitle, roleLabel, narrativeJob, evidenceSummary, supportRationale, supportedScope, unsupportedScope, objectionsSummary, risksSummary, riskOrGapSummary, researchGapsSummary, research gap displayQuestion, relation displayLabel, and relation displayRationale.
|
|
151
173
|
- For every claim in a non-English target language, provide displayTitle so the selected-claim panel does not fall back to canonical English claim text.
|
|
152
|
-
- For every
|
|
174
|
+
- For every evidence/detail field that has canonical user-facing text, provide the matching localized display field when it exists: supportedScope for supported scope, unsupportedScope for evidence boundaries, supportRationale for why the evidence supports the claim, objectionsSummary for objections, risksSummary for risks, and researchGapsSummary for canonical research gaps.
|
|
153
175
|
- Do not translate claim IDs, relation endpoints, narrative hash, source paths, findings files, URLs, numbers, or quoted/source facts.
|
|
176
|
+
- For every canonical research gap in a non-English target language, provide researchGapCards[].displayQuestion so gap cards do not fall back to canonical English question text. Preserve gapId exactly and do not change the gap meaning.
|
|
154
177
|
- Use natural business and manufacturing terminology in the target language, not word-by-word machine translation.
|
|
155
178
|
- If a fact is missing, describe it as missing instead of filling it in.
|
|
179
|
+
- If vaultDiagnostics.blockers is present in the compact map, keep Story read-only but surface the blocker state in summaryLine and the relevant claim card riskOrGapSummary when applicable. Include diagnostic file/nodeId/code/message/suggestedAction in display copy; do not invent missing evidence, source trace, quotes, or caveats to hide the blocker.
|
|
180
|
+
- Do not turn Story into a workflow dashboard: diagnostic copy is for reading context only, not command suggestions or mutation planning.
|
|
181
|
+
- Story UI is evidence-first: clicking a claim shows evidence/gap cards; evidence cards must carry the evidence description, why it supports the claim, and source trace; clicking evidence shows only canonical gaps linked to that evidence.
|
|
182
|
+
- The selected-claim panel is only an evidence/research-gap card list. Do not repeat canonical claim text there; the claim itself is already visible in Claim Flow.
|
|
183
|
+
- Claim cards should not explain gaps or risks through riskOrGapSummary when the same topic belongs in evidence/gap cards. Keep claim cards focused on role, narrative job, and evidence summary.
|
|
184
|
+
- Do not make evidence detail a schema dump. Do not default to unsupportedScope, caveat, IDs, target fields, or evidenceBindingIds for evidence cards; evidence cards should explain what the source says, why it supports the claim, and where it came from.
|
|
185
|
+
- Do not invent, infer, or soften new gaps in display copy. Show research gaps only when they exist in compactMap.researchGaps; do not turn unsupportedScope, weak evidence, caveats, objections, risks, or your own judgment into a gap.
|
|
186
|
+
- researchGapsSummary and riskOrGapSummary may only summarize existing canonical research gaps or diagnostics. If no canonical gap exists for the claim, leave gap-specific display copy empty instead of implying a gap.
|
|
187
|
+
- Localize new Story labels when useful: selectedEvidence, evidenceList, gap, gaps, noEvidence, selectEvidencePrompt, sourceTrace, evidenceSource, whyThisSupports, linkedGaps, selectedGap, and noLinkedGaps.
|
|
188
|
+
- Gap detail may only use canonical research gap fields from the compact map: id, targetType, targetId, status, priority, question, findingsFile, evidenceBindingIds, and notes.
|
|
156
189
|
|
|
157
190
|
Chinese localization rules when the target language request is Chinese, zh, zh-CN, --cn, 中文, or Simplified Chinese:
|
|
158
191
|
- Use natural business/manufacturing Chinese, not word-by-word machine translation.
|
package/lib/commands/research.ts
CHANGED
|
@@ -11,12 +11,12 @@ export function buildResearchPrompt({
|
|
|
11
11
|
? `${DECKS_STATE_FILE} exists. Read it through the revela-decks tool before researching.`
|
|
12
12
|
: `${DECKS_STATE_FILE} does not exist yet. Do not start broad internet research; initialize the workspace first with /revela init unless the user supplied a specific research question in chat.`
|
|
13
13
|
|
|
14
|
-
return `Run Revela
|
|
14
|
+
return `Run Revela research from deterministic state.
|
|
15
15
|
|
|
16
16
|
Goal:
|
|
17
17
|
- Reduce open gaps, unsupported scope, weak evidence, unattached findings, and overextended relation rationale for the current story.
|
|
18
18
|
- Drive research from canonical narrative gaps: unsupported central claims, objections, risks, decision questions, explicit researchGaps, and claim_chain_gap warnings.
|
|
19
|
-
- Treat /revela research as authorization to bind clearly supported findings
|
|
19
|
+
- Treat /revela research as authorization to bind clearly supported findings through the safe \`bindResearchFindings\` boundary without asking for item-by-item user confirmation.
|
|
20
20
|
- Preserve evidence boundaries: eliminate caveats only when evidence or narrower wording actually resolves them; otherwise keep precise caveats visible.
|
|
21
21
|
- Do not write decks, briefs, or design artifacts during research.
|
|
22
22
|
|
|
@@ -24,20 +24,32 @@ Current state:
|
|
|
24
24
|
- ${state}
|
|
25
25
|
${workspaceRoot ? `- Current workspace root: \`${workspaceRoot}\`` : ""}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
1. Call \`revela-decks
|
|
29
|
-
2. If
|
|
30
|
-
3.
|
|
31
|
-
4.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
Required first calls:
|
|
28
|
+
1. Call \`revela-decks read\` with \`summary: true\`.
|
|
29
|
+
2. If the workspace has a Markdown narrative vault, inspect \`narrativeInventory\` from the read summary or call \`revela-decks narrativeInventory\` before editing claims, gaps, evidence, or relations. If \`markdownQa.repairCards\` are present, fix structural repair cards before binding or research mutations unless the selected target is the exact repair.
|
|
30
|
+
3. Call \`revela-decks reviewNarrative\`.
|
|
31
|
+
4. Call \`revela-decks deriveResearchTargets\` and treat \`selected\`, \`bindingDiagnostic\`, and target order as deterministic inputs, not LLM judgement.
|
|
32
|
+
|
|
33
|
+
Tool-driven research contract:
|
|
34
|
+
- If \`selected\` or any high-priority target references a \`findingsFile\`, call \`revela-decks evaluateResearchFindings\` before external search.
|
|
35
|
+
- If \`bindingEval.status === "bindable"\`, call \`revela-decks bindResearchFindings\` with that \`findingsFile\`. Do not hand-author evidence Markdown for bindable findings.
|
|
36
|
+
- If findings are not bindable, report \`missingFields\` and \`failureReasons\`; then run only targeted research for those missing fields.
|
|
37
|
+
- Treat \`markdownQa\` as structural authoring feedback only. It does not prove evidence strength; \`bindingEval\`, \`bindingDiagnostic\`, and compiled claim \`evidenceStatus\` remain the trust/evidence boundary.
|
|
38
|
+
- For external research, use the \`revela-research\` subagent and save findings with \`revela-research-save\`. Ask for source URLs/paths, quotes/snippets, supportScope, unsupportedScope, caveat, strength, and the supported claim id/relation target when available.
|
|
39
|
+
- Re-run \`deriveResearchTargets\` after attachment, binding, or explicit vault edits. Stop after at most 3 rounds.
|
|
40
|
+
- After explicit Markdown edits, rely on the write hook feedback or call \`revela-decks markdownQa\`, then \`compileNarrativeVault\`; keep Markdown QA repair cards separate from compiler diagnostics and repair both before treating the edit as usable research state.
|
|
41
|
+
- For relation changes, update content nodes first, then add explicit edges in the source node's \`## Relations\` section using plain node-id wikilinks. Do not use \`relations.md\`, typed wikilinks, or hand-written relation ids.
|
|
42
|
+
|
|
43
|
+
Allowed mutations:
|
|
44
|
+
- Canonical evidence: use \`bindResearchFindings\` for bindable saved findings; the safe boundary writes \`revela-narrative/evidence/*.md\` and compiles the vault.
|
|
45
|
+
- Research gap lifecycle: after checking inventory and reading the target node, edit \`revela-narrative/research-gaps/*.md\` or use \`updateVaultResearchGap\` when the update is explicit.
|
|
46
|
+
- Safe claim narrowing: after checking inventory and reading the target node, edit \`revela-narrative/claims/*.md\` only when it preserves strategic meaning and evidence boundaries.
|
|
47
|
+
- Relation rewrites must patch node-local \`## Relations\` lines and be reported in \`Narrative changes\`; broader strategic claim changes require Story/user confirmation.
|
|
48
|
+
- Initialize the vault with \`initNarrativeVault\` if a canonical vault is needed and missing.
|
|
49
|
+
- Never call \`upsertNarrative\` during research.
|
|
50
|
+
|
|
51
|
+
Binding criteria:
|
|
52
|
+
- supported claim id exists and is expressed as \`## Relations\` with \`- supports: [[claim-id]]\` for new evidence; quote/snippet is traceable and not invented; source URL/path/findingsFile is present; supportScope and unsupportedScope are explicit; caveat is preserved; strength is strong or useful partial; binding does not expand the claim. Frontmatter \`claimId\` is compatibility fallback, not the preferred graph source.
|
|
41
53
|
|
|
42
54
|
Stop conditions:
|
|
43
55
|
- No open externally researchable gaps remain.
|
|
@@ -50,7 +62,10 @@ Report format:
|
|
|
50
62
|
- Start with \`Research loop completed after <n> round(s).\`
|
|
51
63
|
- Then use these exact sections in order:
|
|
52
64
|
- \`Selected target\`: report \`kind\`, \`priority\`, \`reason\`, \`question\`, \`targetId\`, \`claimId\`, and any \`findingsFile\`.
|
|
53
|
-
- \`
|
|
65
|
+
- \`Vault diagnostics\`: if \`vaultDiagnostics\` or a mutation \`diagnosticReport\` was returned, list blockers first with file/node/code/message and the suggested next action; otherwise write \`clean\` or \`not a vault workspace\`. If blockers exist, pause binding and research mutations unless the selected target is the exact diagnostic fix.
|
|
66
|
+
- \`Markdown QA\`: if \`markdownQa.repairCards\` was returned, list repair cards by severity, file, nodeId, issueCode, message, and smallestRepair. If no cards were returned, write \`clean\` or \`not checked\`.
|
|
67
|
+
- \`Evidence trust\`: report \`bindingEval.status\`, \`bindingDiagnostic.bindable\`, and compiled claim \`evidenceStatus\` separately from Markdown QA so structurally valid weak/partial evidence remains visible as weak/partial/missing support.
|
|
68
|
+
- \`Existing findings inspected\`: for each file, report \`findingsFile\`, \`bindingEval.status\` when available, \`bindingDiagnostic.bindable\`, \`missingFields\`, \`failureReasons\`, and which explicit fields were present: \`source\`, \`quoteOrSnippet\`, \`supportScope\`, \`unsupportedScope\`, \`caveat\`, \`strength\`. If none were inspected, write \`none\`.
|
|
54
69
|
- \`Attachments\`: list findings attached with axis/status, or \`none\`.
|
|
55
70
|
- \`Evidence bound\`: list evidence bindings by claim id, source, quote/snippet, supportScope, unsupportedScope, caveat, and strength, or \`none\`.
|
|
56
71
|
- \`Unbound findings\`: list every inspected but unbound findings file with structured failure reasons such as \`missing_quote\`, \`unclear_source\`, \`unsupported_scope\`, \`caveat_conflict\`, \`weak_source\`, \`source_mismatch\`, or \`context_only_finding\`. If none, write \`none\`.
|
|
@@ -63,12 +78,13 @@ Report format:
|
|
|
63
78
|
Rules:
|
|
64
79
|
- Do not use primary-agent broad websearch. Use the \`revela-research\` subagent for external search.
|
|
65
80
|
- Do not invent quotes, source paths, URLs, page references, locations, or caveats.
|
|
81
|
+
- Do not invent claim ids, evidence ids, research-gap ids, or relation targets before checking \`narrativeInventory\` unless you are intentionally creating the missing node in Markdown.
|
|
66
82
|
- Do not treat \`researches/**/*.md\` as canonical evidence until attached or evidence-bound, but do not stop at findings_saved when binding criteria are met.
|
|
67
|
-
- Do not bypass \`deriveResearchTargets\`; target selection, \`selected\`, and \`
|
|
83
|
+
- Do not bypass \`deriveResearchTargets\` or \`evaluateResearchFindings\`; target selection, \`selected\`, \`bindingDiagnostic\`, and \`bindingEval\` are deterministic inputs, not LLM judgement.
|
|
68
84
|
- Do not mutate canonical claims merely to fit a source; narrow only to preserve evidence boundaries and avoid overstated claims.
|
|
69
|
-
- Do not call \`upsertNarrative\` during research.
|
|
85
|
+
- Do not call \`upsertNarrative\` during research. Initialize the Markdown vault with \`initNarrativeVault\` if needed; research should author bindable canonical evidence through \`bindResearchFindings\`, then use explicit Markdown edits for \`research-gaps/*.md\` and safe \`claims/*.md\` when needed. Targeted vault actions are fallback helpers, not the primary writing path. Broader narrative rewrites must be reported for Story/user confirmation.
|
|
70
86
|
- Do not ask the user to approve each evidence binding. Ask only when binding would change strategic meaning, downgrade a central claim, rely on suspicious sources, or require narrative approval.
|
|
71
87
|
- Do not store secrets, credentials, tokens, or sensitive personal information.
|
|
72
88
|
|
|
73
|
-
Start now by reading ${DECKS_STATE_FILE} through \`revela-decks\`, reviewing current readiness, deriving research targets, and running the first research/binding loop from the selected target.`
|
|
89
|
+
Start now by reading ${DECKS_STATE_FILE} through \`revela-decks\`, inspecting narrative inventory when a vault exists, reviewing current readiness, deriving research targets, and running the first research/binding loop from the selected target.`
|
|
74
90
|
}
|