@cyber-dash-tech/revela 0.17.2 → 0.17.3
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 +11 -7
- package/README.zh-CN.md +11 -7
- package/lib/commands/help.ts +2 -2
- package/lib/commands/init.ts +10 -2
- package/lib/commands/narrative.ts +40 -19
- package/package.json +1 -1
- package/skill/NARRATIVE_SKILL.md +4 -1
- package/tools/narrative-view.ts +8 -10
package/README.md
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
**English** | [中文](README.zh-CN.md)
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/@cyber-dash-tech/revela) [](LICENSE) [](tests/) [](https://opencode.ai) [](https://bun.sh)
|
|
6
|
+
|
|
5
7
|
<p align="center">
|
|
6
8
|
<img src="assets/img/logo.png" alt="Revela" width="560" />
|
|
7
9
|
</p>
|
|
8
10
|
|
|
9
|
-
Revela is an [OpenCode](https://opencode.ai) plugin
|
|
11
|
+
Revela is an [OpenCode](https://opencode.ai) plugin that turns local sources and research into a traceable narrative graph, then renders that graph into briefs and presentation decks.
|
|
12
|
+
|
|
13
|
+
The narrative graph records the core elements needed to generate a brief or deck: audience, decision, claims, evidence, sources, risks, objections, and open gaps.
|
|
10
14
|
|
|
11
15
|
## Install
|
|
12
16
|
|
|
@@ -30,17 +34,17 @@ Revela includes built-in deck designs:
|
|
|
30
34
|
### [summit](designs/summit/preview.html)
|
|
31
35
|
|
|
32
36
|
<p align="center">
|
|
33
|
-
<img src="assets/img/summit-01.
|
|
34
|
-
<img src="assets/img/summit-02.
|
|
35
|
-
<img src="assets/img/summit-03.
|
|
37
|
+
<img src="assets/img/summit-01.jpg" alt="Summit design preview 1" width="32%" />
|
|
38
|
+
<img src="assets/img/summit-02.jpg" alt="Summit design preview 2" width="32%" />
|
|
39
|
+
<img src="assets/img/summit-03.jpg" alt="Summit design preview 3" width="32%" />
|
|
36
40
|
</p>
|
|
37
41
|
|
|
38
42
|
### [monet](designs/monet/preview.html)
|
|
39
43
|
|
|
40
44
|
<p align="center">
|
|
41
|
-
<img src="assets/img/monet-01.
|
|
42
|
-
<img src="assets/img/monet-02.
|
|
43
|
-
<img src="assets/img/monet-03.
|
|
45
|
+
<img src="assets/img/monet-01.jpg" alt="Monet design preview 1" width="32%" />
|
|
46
|
+
<img src="assets/img/monet-02.jpg" alt="Monet design preview 2" width="32%" />
|
|
47
|
+
<img src="assets/img/monet-03.jpg" alt="Monet design preview 3" width="32%" />
|
|
44
48
|
</p>
|
|
45
49
|
|
|
46
50
|
`starter` is the clean default presentation style.
|
package/README.zh-CN.md
CHANGED
|
@@ -2,11 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | **中文**
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/@cyber-dash-tech/revela) [](LICENSE) [](tests/) [](https://opencode.ai) [](https://bun.sh)
|
|
6
|
+
|
|
5
7
|
<p align="center">
|
|
6
8
|
<img src="assets/img/logo.png" alt="Revela" width="560" />
|
|
7
9
|
</p>
|
|
8
10
|
|
|
9
|
-
Revela 是一个 [OpenCode](https://opencode.ai)
|
|
11
|
+
Revela 是一个 [OpenCode](https://opencode.ai) 插件,用来把本地材料和调研结果转成可追踪的叙事图谱,再基于这个图谱生成 brief 和 presentation deck。
|
|
12
|
+
|
|
13
|
+
叙事图谱用 graph 方式记录生成 brief 或 deck 所需的关键要素:受众、决策目标、论点、论据、资料来源、风险、潜在质疑和待补齐的信息。
|
|
10
14
|
|
|
11
15
|
## 安装
|
|
12
16
|
|
|
@@ -30,17 +34,17 @@ Revela 内置多个 deck design:
|
|
|
30
34
|
### [summit](designs/summit/preview.html)
|
|
31
35
|
|
|
32
36
|
<p align="center">
|
|
33
|
-
<img src="assets/img/summit-01.
|
|
34
|
-
<img src="assets/img/summit-02.
|
|
35
|
-
<img src="assets/img/summit-03.
|
|
37
|
+
<img src="assets/img/summit-01.jpg" alt="Summit design preview 1" width="32%" />
|
|
38
|
+
<img src="assets/img/summit-02.jpg" alt="Summit design preview 2" width="32%" />
|
|
39
|
+
<img src="assets/img/summit-03.jpg" alt="Summit design preview 3" width="32%" />
|
|
36
40
|
</p>
|
|
37
41
|
|
|
38
42
|
### [monet](designs/monet/preview.html)
|
|
39
43
|
|
|
40
44
|
<p align="center">
|
|
41
|
-
<img src="assets/img/monet-01.
|
|
42
|
-
<img src="assets/img/monet-02.
|
|
43
|
-
<img src="assets/img/monet-03.
|
|
45
|
+
<img src="assets/img/monet-01.jpg" alt="Monet design preview 1" width="32%" />
|
|
46
|
+
<img src="assets/img/monet-02.jpg" alt="Monet design preview 2" width="32%" />
|
|
47
|
+
<img src="assets/img/monet-03.jpg" alt="Monet design preview 3" width="32%" />
|
|
44
48
|
</p>
|
|
45
49
|
|
|
46
50
|
`starter` 是简洁默认演示风格。
|
package/lib/commands/help.ts
CHANGED
|
@@ -27,7 +27,7 @@ export async function handleHelp(
|
|
|
27
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` +
|
|
28
28
|
`---\n\n` +
|
|
29
29
|
`**Workflow**\n\n` +
|
|
30
|
-
`1. \`init\` — discover
|
|
30
|
+
`1. \`init\` — discover sources, refresh the graph, ask key questions, and recommend next steps\n` +
|
|
31
31
|
`2. \`research\` — close evidence gaps and bind support\n` +
|
|
32
32
|
`3. \`story\` — inspect audience, thesis, claims, evidence, risks, and diagnostics\n` +
|
|
33
33
|
`4. \`make\` — generate deck or brief from canonical story state\n` +
|
|
@@ -38,7 +38,7 @@ export async function handleHelp(
|
|
|
38
38
|
`\`/revela\` — show REVELA help\n` +
|
|
39
39
|
`\`/revela enable\` — enable Revela prompt/context without starting a workflow\n` +
|
|
40
40
|
`\`/revela disable\` — disable Revela prompt/context for this session\n` +
|
|
41
|
-
`\`/revela init\` —
|
|
41
|
+
`\`/revela init\` — start Revela: discover sources, refresh story state, ask key questions, and recommend next steps\n` +
|
|
42
42
|
`\`/revela research\` — research, bind evidence, and reduce story gaps\n` +
|
|
43
43
|
`\`/revela story [-l language]\` — open the read-only story workspace UI\n` +
|
|
44
44
|
`\`/revela make --deck\` — make a deck from story state and deck-plan/\n` +
|
package/lib/commands/init.ts
CHANGED
|
@@ -11,12 +11,13 @@ export function buildInitPrompt({
|
|
|
11
11
|
? `A ${DECKS_STATE_FILE} file already exists as legacy/cache state. Read it first through the revela-decks tool and update it conservatively only for compatibility metadata.`
|
|
12
12
|
: `No ${DECKS_STATE_FILE} file exists yet. Keep this workspace file-native: initialize the Markdown narrative vault before writing narrative meaning and do not create ${DECKS_STATE_FILE}.`
|
|
13
13
|
|
|
14
|
-
return `
|
|
14
|
+
return `Start Revela on the current workspace.
|
|
15
15
|
|
|
16
16
|
Goal:
|
|
17
17
|
- Initialize or refresh the Markdown narrative vault and file-native source inventory from local workspace evidence.
|
|
18
18
|
- Treat init as repeatable ingest: discover files, register source materials, follow returned ingest task hints, and distill stable narrative meaning.
|
|
19
19
|
- Capture primary audience, belief before/after, decision/action, thesis, central claims, evidence availability, objections, risks, source materials, artifact history, and open questions.
|
|
20
|
+
- End init with a guided completion report: what local discovery found, what the narrative graph currently contains, what gaps remain, what user clarification is needed, and which command should run next.
|
|
20
21
|
- 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.
|
|
21
22
|
- Treat central claims as chapter-ready claims, not evidence fragments: a central claim should be able to support framing/context, proof/evidence, decision implication, and explicit boundary/gap/risk material. If local material only supports a narrow fact, record it as supporting evidence or a supporting claim instead of promoting it to central importance.
|
|
22
23
|
|
|
@@ -60,7 +61,7 @@ Required workflow:
|
|
|
60
61
|
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.
|
|
61
62
|
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\`.
|
|
62
63
|
8. If explicit deck/artifact information exists, record conservative artifact context in file-native outputs or existing compatibility state only from visible information. Do not infer hidden evidence from generated artifacts.
|
|
63
|
-
9. Report
|
|
64
|
+
9. Complete an Init Completion Report before ending. Do not end with only a technical success message. Include local discovery counts and paths for added, changed, newer-than-vault, unchanged, \`ingest.ingestCandidates\`, and \`ingest.suggestedTasks\`; a narrative graph summary; open evidence/research gaps; any Markdown QA status; user clarification questions; and recommended next commands. 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.
|
|
64
65
|
|
|
65
66
|
Evidence boundary:
|
|
66
67
|
- \`workspace.sourceMaterials\` and ingest task hints are candidate context, not proof.
|
|
@@ -81,6 +82,13 @@ Narrative questions to ask only when missing:
|
|
|
81
82
|
- Which sources or findings support those claims?
|
|
82
83
|
- What objections, risks, assumptions, or caveats could break the argument?
|
|
83
84
|
|
|
85
|
+
Init completion rules:
|
|
86
|
+
- Before ending \`/revela init\`, either use the question tool (AskQuestion) for at least one useful clarification or explicitly state that no clarification is needed now.
|
|
87
|
+
- Ask only narrative-startup questions during init: audience, decision/action, scope, source priority, missing internal data, or whether external research is allowed for public evidence gaps.
|
|
88
|
+
- Do not ask for slide count, design choice, layout choice, visual style, output path, PDF/PPTX export, or component preferences during init.
|
|
89
|
+
- Always surface open gaps. Classify them as evidence gaps, research gaps, internal-data-needed, source-quality limits, or user-intent questions when possible.
|
|
90
|
+
- Always recommend the next command: \`/revela research\` when evidence gaps need support, \`/revela story\` when the graph is ready to inspect, and \`/revela make --deck\` only when the user is ready to render from the current story.
|
|
91
|
+
|
|
84
92
|
Memory rules:
|
|
85
93
|
- Only write facts supported by workspace files or explicit user statements into file-native narrative/source files or, when ${DECKS_STATE_FILE} already exists, conservative compatibility metadata such as source materials, deck memory, and open questions.
|
|
86
94
|
- Only write user preferences if the user explicitly stated that Revela should remember them.
|
|
@@ -2,11 +2,10 @@ import { mkdirSync, writeFileSync } from "fs"
|
|
|
2
2
|
import { tmpdir } from "os"
|
|
3
3
|
import { join } from "path"
|
|
4
4
|
import { openUrl as defaultOpenUrl } from "../edit/open"
|
|
5
|
-
import {
|
|
5
|
+
import { createEmptyDecksState } 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
9
|
import { compileNarrativeVault, formatVaultDiagnosticMarkdown, formatVaultDiagnosticReport, hasNarrativeVault } from "../narrative-vault"
|
|
11
10
|
|
|
12
11
|
export interface NarrativeArgs {
|
|
@@ -18,6 +17,10 @@ export interface StoryArgs {
|
|
|
18
17
|
language: NarrativeViewLanguage
|
|
19
18
|
}
|
|
20
19
|
|
|
20
|
+
export type StoryMapLoadResult =
|
|
21
|
+
| { ok: true; map: ReturnType<typeof buildNarrativeMap>; diagnosticsMarkdown: string; diagnosticsReport: ReturnType<typeof formatVaultDiagnosticReport> }
|
|
22
|
+
| { ok: false; error: string; diagnosticsMarkdown: string; diagnosticsReport?: ReturnType<typeof formatVaultDiagnosticReport> }
|
|
23
|
+
|
|
21
24
|
export type ParseNarrativeArgsResult = { ok: true; args: NarrativeArgs } | { ok: false; error: string }
|
|
22
25
|
export type ParseStoryArgsResult = { ok: true; args: StoryArgs } | { ok: false; error: string }
|
|
23
26
|
|
|
@@ -77,14 +80,14 @@ export async function handleNarrative(
|
|
|
77
80
|
send: (text: string) => Promise<void>,
|
|
78
81
|
): Promise<void> {
|
|
79
82
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
const loaded = loadStoryMap(options.workspaceRoot)
|
|
84
|
+
if (!loaded.ok) {
|
|
85
|
+
await send([loaded.error, loaded.diagnosticsMarkdown].filter(Boolean).join("\n\n"))
|
|
82
86
|
return
|
|
83
87
|
}
|
|
84
88
|
|
|
85
|
-
const
|
|
86
|
-
const
|
|
87
|
-
const diagnosticsMarkdown = vaultDiagnosticsMarkdown(options.workspaceRoot, state.narrative?.approvals ?? [])
|
|
89
|
+
const map = loaded.map
|
|
90
|
+
const diagnosticsMarkdown = loaded.diagnosticsMarkdown
|
|
88
91
|
const markdown = [diagnosticsMarkdown, formatNarrativeMap(map)].filter(Boolean).join("\n\n")
|
|
89
92
|
|
|
90
93
|
if (options.openBrowser) {
|
|
@@ -105,22 +108,40 @@ export async function handleNarrative(
|
|
|
105
108
|
}
|
|
106
109
|
}
|
|
107
110
|
|
|
108
|
-
function
|
|
109
|
-
if (!hasNarrativeVault(workspaceRoot))
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
export function loadStoryMap(workspaceRoot: string): StoryMapLoadResult {
|
|
112
|
+
if (!hasNarrativeVault(workspaceRoot)) {
|
|
113
|
+
return {
|
|
114
|
+
ok: false,
|
|
115
|
+
error: "No `revela-narrative/` vault found. Run `/revela init` first to initialize the narrative workspace.",
|
|
116
|
+
diagnosticsMarkdown: "",
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const result = compileNarrativeVault(workspaceRoot)
|
|
121
|
+
const diagnosticsReport = formatVaultDiagnosticReport(result.diagnostics)
|
|
122
|
+
const diagnosticsMarkdown = formatVaultDiagnosticMarkdown(diagnosticsReport)
|
|
123
|
+
if (!result.narrative) {
|
|
124
|
+
return {
|
|
125
|
+
ok: false,
|
|
126
|
+
error: "The `revela-narrative/` vault could not be compiled into a narrative map.",
|
|
127
|
+
diagnosticsMarkdown,
|
|
128
|
+
diagnosticsReport,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const state = createEmptyDecksState()
|
|
133
|
+
state.narrative = result.narrative
|
|
134
|
+
return { ok: true, map: buildNarrativeMap(state), diagnosticsMarkdown, diagnosticsReport }
|
|
112
135
|
}
|
|
113
136
|
|
|
114
137
|
export function buildNarrativeViewPrompt(options: { workspaceRoot: string; language: NarrativeViewLanguage }): string {
|
|
115
|
-
|
|
116
|
-
|
|
138
|
+
const loaded = loadStoryMap(options.workspaceRoot)
|
|
139
|
+
if (!loaded.ok) {
|
|
140
|
+
return `${loaded.error}\n\n${loaded.diagnosticsMarkdown}\n\nDo not call any tool.`
|
|
117
141
|
}
|
|
118
142
|
|
|
119
|
-
const
|
|
120
|
-
const
|
|
121
|
-
const vaultDiagnostics = hasNarrativeVault(options.workspaceRoot)
|
|
122
|
-
? formatVaultDiagnosticReport(compileNarrativeVault(options.workspaceRoot, { fallbackApprovals: state.narrative?.approvals ?? [] }).diagnostics)
|
|
123
|
-
: undefined
|
|
143
|
+
const map = loaded.map
|
|
144
|
+
const vaultDiagnostics = loaded.diagnosticsReport
|
|
124
145
|
const projection = {
|
|
125
146
|
narrativeHash: map.snapshot.narrativeHash,
|
|
126
147
|
language: options.language,
|
|
@@ -161,7 +182,7 @@ Target language request: ${options.language}
|
|
|
161
182
|
You must call the \`revela-narrative-view\` tool exactly once.
|
|
162
183
|
|
|
163
184
|
Hard rules:
|
|
164
|
-
- Do not mutate
|
|
185
|
+
- Do not mutate narrative files, deck HTML, evidence, claims, relations, approvals, or artifacts.
|
|
165
186
|
- Do not invent new claims, evidence, relations, slide coverage, source paths, findings files, quotes, or caveats.
|
|
166
187
|
- Preserve every claimId exactly.
|
|
167
188
|
- Preserve every relation endpoint exactly: fromClaimId, toClaimId, relation.
|
package/package.json
CHANGED
package/skill/NARRATIVE_SKILL.md
CHANGED
|
@@ -16,7 +16,7 @@ Default mode is narrative-first. Do not generate HTML slides, choose layouts, fe
|
|
|
16
16
|
|
|
17
17
|
Use the same phase semantics whether the user invokes a slash command or asks in normal chat:
|
|
18
18
|
|
|
19
|
-
- `Init`
|
|
19
|
+
- `Init` starts Revela on the current workspace: discover local materials, capture missing intent, refresh the narrative graph, surface gaps, and recommend the next command.
|
|
20
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
21
|
- `Story` opens the read-only story workspace UI for inspecting claim flow, evidence strength, unsupported scope, caveats, objections, risks, research gaps, diagnostics, and affected artifacts.
|
|
22
22
|
- `Make` renders an artifact from canonical narrative state and current diagnostics. Supported targets are deck and executive brief.
|
|
@@ -74,6 +74,9 @@ During init:
|
|
|
74
74
|
- derive claims, evidence bindings, caveats, unsupported scope, source paths, quotes/snippets, pages, sheets, or slide references only when explicit support exists; distill ingested files by writing Markdown nodes under `revela-narrative/` even when the narrative is incomplete, and represent missing information as research gaps or caveats
|
|
75
75
|
- write `## Relations` sections with plain node-id wikilinks such as `- supports: [[claim-example]]`, `- depends_on: [[evidence-example]]`, `- answers: [[claim-example]]`, or `- constrains: [[claim-example]]` when the relation is explicit; do not use typed wikilinks or hand-written relation ids; compile and fix diagnostics after editing Markdown
|
|
76
76
|
- ask the smallest missing intent questions after local evidence has been considered
|
|
77
|
+
- before ending `/revela init`, either use the question tool (AskQuestion) for a useful clarification or explicitly state that no clarification is needed now
|
|
78
|
+
- always report local discovery status, narrative graph status, open evidence/research gaps, Markdown QA status, and recommended next commands
|
|
79
|
+
- recommend `/revela research` when gaps need evidence, `/revela story` when the graph is ready to inspect, and `/revela make --deck` only when the user is ready to render
|
|
77
80
|
- do not require slide count, design choice, layout choice, output path, or visual style unless the user explicitly asks to make an artifact immediately
|
|
78
81
|
- when exporting a vault, say that any legacy render targets, reviews, artifact coverage, actions, deck specs, and source material records in `DECKS.json` are cache/provenance only
|
|
79
82
|
|
package/tools/narrative-view.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { tool } from "@opencode-ai/plugin"
|
|
2
|
-
import { hasDecksState, readDecksState } from "../lib/decks-state"
|
|
3
|
-
import { buildNarrativeMap } from "../lib/narrative-state/map"
|
|
4
2
|
import { validateNarrativeDisplayModel, type NarrativeDisplayModel, type NarrativeViewLanguage } from "../lib/narrative-state/display"
|
|
5
|
-
import { writeNarrativeMapHtml } from "../lib/commands/narrative"
|
|
3
|
+
import { loadStoryMap, writeNarrativeMapHtml } from "../lib/commands/narrative"
|
|
6
4
|
import { openUrl } from "../lib/edit/open"
|
|
7
5
|
|
|
8
6
|
export default tool({
|
|
9
7
|
description:
|
|
10
8
|
"Render Revela's read-only narrative claim-flow UI from the current deterministic narrative map plus an optional localized display model. " +
|
|
11
|
-
"This tool validates display IDs against
|
|
9
|
+
"This tool validates display IDs against the file-native narrative vault, opens a local HTML view, and never mutates workspace state.",
|
|
12
10
|
args: {
|
|
13
11
|
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
12
|
narrativeHash: tool.schema.string().optional().describe("Narrative hash from the prompt projection. Used to detect stale display prompts."),
|
|
@@ -79,11 +77,10 @@ export default tool({
|
|
|
79
77
|
async execute(args, context) {
|
|
80
78
|
const workspaceRoot = context.directory ?? process.cwd()
|
|
81
79
|
try {
|
|
82
|
-
if (!hasDecksState(workspaceRoot)) {
|
|
83
|
-
return JSON.stringify({ ok: false, error: "No DECKS.json found. Run /revela init first." })
|
|
84
|
-
}
|
|
85
80
|
const language = args.language as NarrativeViewLanguage
|
|
86
|
-
const
|
|
81
|
+
const loaded = loadStoryMap(workspaceRoot)
|
|
82
|
+
if (!loaded.ok) return JSON.stringify({ ok: false, error: loaded.error, diagnostics: loaded.diagnosticsReport, diagnosticsMarkdown: loaded.diagnosticsMarkdown })
|
|
83
|
+
const map = loaded.map
|
|
87
84
|
const stalePrompt = Boolean(args.narrativeHash && args.narrativeHash !== map.snapshot.narrativeHash)
|
|
88
85
|
const display = validateNarrativeDisplayModel(map, args.displayModel as NarrativeDisplayModel | undefined, language)
|
|
89
86
|
const htmlPath = writeNarrativeMapHtml(map, display)
|
|
@@ -92,8 +89,9 @@ export default tool({
|
|
|
92
89
|
return JSON.stringify({ ok: true, url, path: htmlPath, narrativeHash: map.snapshot.narrativeHash, stalePrompt, fallback: false }, null, 2)
|
|
93
90
|
} catch (e: any) {
|
|
94
91
|
try {
|
|
95
|
-
const
|
|
96
|
-
|
|
92
|
+
const loaded = loadStoryMap(workspaceRoot)
|
|
93
|
+
if (!loaded.ok) return JSON.stringify({ ok: false, fallback: false, error: e.message || String(e), fallbackError: loaded.error, diagnostics: loaded.diagnosticsReport, diagnosticsMarkdown: loaded.diagnosticsMarkdown })
|
|
94
|
+
const map = loaded.map
|
|
97
95
|
const htmlPath = writeNarrativeMapHtml(map)
|
|
98
96
|
const url = `file://${htmlPath}`
|
|
99
97
|
openUrl(url)
|