@cyber-dash-tech/revela 0.17.0 → 0.17.2
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 +45 -567
- package/README.zh-CN.md +47 -535
- package/designs/monet/DESIGN.md +1 -1
- package/designs/starter/DESIGN.md +1 -1
- package/designs/summit/DESIGN.md +1 -1
- package/lib/commands/help.ts +4 -4
- package/lib/commands/init.ts +9 -7
- package/lib/commands/narrative.ts +13 -4
- package/lib/commands/pdf.ts +24 -15
- package/lib/commands/pptx.ts +2 -16
- package/lib/commands/research.ts +2 -0
- package/lib/commands/review.ts +81 -93
- package/lib/deck-html/contract.ts +26 -10
- package/lib/decks-state.ts +75 -86
- package/lib/edit/deck-state.ts +3 -111
- package/lib/edit/open.ts +2 -2
- package/lib/edit/resolve-deck.ts +14 -24
- package/lib/inspect/open.ts +2 -2
- 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/deck-plan-artifact.ts +584 -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 +649 -44
- package/lib/narrative-state/research-gaps.ts +5 -2
- package/lib/narrative-vault/compile.ts +16 -1
- package/lib/narrative-vault/types.ts +4 -2
- package/lib/qa/checks.ts +206 -5
- package/lib/qa/measure.ts +63 -1
- package/lib/refine/open.ts +2 -2
- package/lib/refine/server.ts +157 -20
- package/package.json +1 -1
- package/plugin.ts +2 -2
- package/skill/NARRATIVE_SKILL.md +19 -19
- package/skill/SKILL.md +99 -35
- package/tools/decks.ts +83 -51
- package/tools/narrative-view.ts +16 -0
package/designs/summit/DESIGN.md
CHANGED
|
@@ -470,7 +470,7 @@ These rules are mandatory for Summit.
|
|
|
470
470
|
|
|
471
471
|
### Layout Types
|
|
472
472
|
|
|
473
|
-
Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. It must also set `data-slide-index="N"`, where `N` is the 1-based
|
|
473
|
+
Each `<section class="slide">` must set `slide-qa="true"` or `slide-qa="false"`. It must also set `data-slide-index="N"`, where `N` is the canonical positive 1-based artifact slide identity from the approved deck plan or DOM order. Indexes must be unique and strictly increase. Use the QA column to decide which `slide-qa` value to write. Fetch any layout with the `revela-designs` tool (`action: "read"`, `layout: "<name>"`).
|
|
474
474
|
|
|
475
475
|
Normal `qa=true` content layouts should start with a slide-level title block unless the layout marker explicitly says otherwise. Use an eyebrow for chapter/section context, then an `h2` that states the slide's claim or takeaway. Body boxes, charts, media, tables, and text panels should sit below or beside that title region rather than replacing it.
|
|
476
476
|
|
package/lib/commands/help.ts
CHANGED
|
@@ -29,8 +29,8 @@ export async function handleHelp(
|
|
|
29
29
|
`**Workflow**\n\n` +
|
|
30
30
|
`1. \`init\` — discover workspace sources and capture intent\n` +
|
|
31
31
|
`2. \`research\` — close evidence gaps and bind support\n` +
|
|
32
|
-
`3. \`story\` — inspect audience, thesis, claims, evidence, risks, and
|
|
33
|
-
`4. \`make\` — generate deck or brief from
|
|
32
|
+
`3. \`story\` — inspect audience, thesis, claims, evidence, risks, and diagnostics\n` +
|
|
33
|
+
`4. \`make\` — generate deck or brief from canonical story state\n` +
|
|
34
34
|
`5. \`review\` — comment on and inspect rendered deck artifacts\n` +
|
|
35
35
|
`6. \`export\` — export deck artifacts to PDF or PPTX\n\n` +
|
|
36
36
|
`---\n\n` +
|
|
@@ -41,8 +41,8 @@ export async function handleHelp(
|
|
|
41
41
|
`\`/revela init\` — initialize or refresh workspace story state\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
|
-
`\`/revela make --deck\` — make a deck from
|
|
45
|
-
`\`/revela make --brief [file.md]\` — render executive brief from
|
|
44
|
+
`\`/revela make --deck\` — make a deck from story state and deck-plan/\n` +
|
|
45
|
+
`\`/revela make --brief [file.md]\` — render executive brief from story state\n` +
|
|
46
46
|
`\`/revela review --deck\` — open deck reading, insight, and comment workspace\n` +
|
|
47
47
|
`\`/revela export --deck pdf [file.html]\` — export HTML deck to PDF\n` +
|
|
48
48
|
`\`/revela export --deck pptx [file.html] [--notes]\` — export HTML deck to PPTX\n` +
|
package/lib/commands/init.ts
CHANGED
|
@@ -8,16 +8,17 @@ export function buildInitPrompt({
|
|
|
8
8
|
workspaceRoot?: string
|
|
9
9
|
}): string {
|
|
10
10
|
const mode = exists
|
|
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.
|
|
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
|
+
: `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
14
|
return `Initialize Revela narrative workspace state.
|
|
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
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.
|
|
21
|
+
- 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.
|
|
21
22
|
|
|
22
23
|
Current state:
|
|
23
24
|
- ${mode}
|
|
@@ -32,7 +33,7 @@ Workspace boundary rules:
|
|
|
32
33
|
- 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.
|
|
33
34
|
|
|
34
35
|
Expected tool use during init:
|
|
35
|
-
- \`revela-decks init\` and \`revela-decks initNarrativeVault\` are expected controlled
|
|
36
|
+
- \`revela-decks init\` and \`revela-decks initNarrativeVault\` are expected controlled file-native/vault boundaries. In fresh workspaces they must not create ${DECKS_STATE_FILE}; if legacy state already exists, they may update compatibility metadata conservatively. Empty-looking optional fields in tool UI are a schema display artifact, not user-provided evidence.
|
|
36
37
|
- 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
38
|
- 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
39
|
- 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.
|
|
@@ -58,7 +59,7 @@ Required workflow:
|
|
|
58
59
|
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
60
|
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
61
|
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
|
|
62
|
+
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.
|
|
62
63
|
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
|
|
|
64
65
|
Evidence boundary:
|
|
@@ -67,6 +68,7 @@ Evidence boundary:
|
|
|
67
68
|
- 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
69
|
- 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
70
|
- 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.
|
|
71
|
+
- If a central claim cannot yet sustain a future claim-led chapter, keep the insufficiency visible through evidence status, unsupported scope, caveats, or a research gap rather than padding the future deck with generic slides.
|
|
70
72
|
- A successful vault compile means the vault is structurally valid. It is not evidence readiness, narrative approval, or permission to make a deck/brief.
|
|
71
73
|
|
|
72
74
|
Narrative questions to ask only when missing:
|
|
@@ -80,11 +82,11 @@ Narrative questions to ask only when missing:
|
|
|
80
82
|
- What objections, risks, assumptions, or caveats could break the argument?
|
|
81
83
|
|
|
82
84
|
Memory rules:
|
|
83
|
-
- Only write facts supported by workspace files or explicit user statements into ${DECKS_STATE_FILE}
|
|
85
|
+
- 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.
|
|
84
86
|
- Only write user preferences if the user explicitly stated that Revela should remember them.
|
|
85
87
|
- Do not infer personal preferences from one-off requests.
|
|
86
88
|
- Do not store secrets, credentials, API keys, tokens, account details, or sensitive personal information.
|
|
87
|
-
- Do not
|
|
89
|
+
- Do not create or update approval, render override, or writeReadiness workflow state during init.
|
|
88
90
|
- Treat this workspace as a single deck project. If the user wants another deck, guide them to create another workspace/folder rather than adding a second deck record.
|
|
89
91
|
- If new evidence conflicts with existing memory, preserve both briefly and add an Open Question instead of silently overwriting.
|
|
90
92
|
|
|
@@ -147,7 +147,7 @@ export function buildNarrativeViewPrompt(options: { workspaceRoot: string; langu
|
|
|
147
147
|
relations: map.claimRelations.map((relation) => ({ id: relation.id, fromClaimId: relation.fromClaimId, toClaimId: relation.toClaimId, relation: relation.relation, rationale: relation.rationale, inferred: relation.inferred })),
|
|
148
148
|
objections: map.objections.map((objection) => ({ id: objection.id, claimId: objection.claimId, priority: objection.priority, text: objection.text, response: objection.response })),
|
|
149
149
|
risks: map.risks.map((risk) => ({ id: risk.id, claimId: risk.claimId, severity: risk.severity, text: risk.text, mitigation: risk.mitigation })),
|
|
150
|
-
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 })),
|
|
151
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 })) })),
|
|
152
152
|
}
|
|
153
153
|
|
|
@@ -165,18 +165,27 @@ Hard rules:
|
|
|
165
165
|
- Do not invent new claims, evidence, relations, slide coverage, source paths, findings files, quotes, or caveats.
|
|
166
166
|
- Preserve every claimId exactly.
|
|
167
167
|
- Preserve every relation endpoint exactly: fromClaimId, toClaimId, relation.
|
|
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, 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.
|
|
169
169
|
- For inferred relations, do not provide relation displayLabel or displayRationale; inferred relations are unconfirmed order notes, not causal/support/dependency judgments.
|
|
170
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.
|
|
171
171
|
- Keep source paths, findings files, claim IDs, narrative hash, and numbers unchanged.
|
|
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, 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.
|
|
173
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.
|
|
174
|
-
- 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.
|
|
175
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.
|
|
176
177
|
- Use natural business and manufacturing terminology in the target language, not word-by-word machine translation.
|
|
177
178
|
- If a fact is missing, describe it as missing instead of filling it in.
|
|
178
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.
|
|
179
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.
|
|
180
189
|
|
|
181
190
|
Chinese localization rules when the target language request is Chinese, zh, zh-CN, --cn, 中文, or Simplified Chinese:
|
|
182
191
|
- Use natural business/manufacturing Chinese, not word-by-word machine translation.
|
package/lib/commands/pdf.ts
CHANGED
|
@@ -7,12 +7,11 @@
|
|
|
7
7
|
* Example: decks/my-deck.html → decks/my-deck.pdf
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { existsSync, readdirSync } from "fs"
|
|
10
11
|
import { resolve } from "path"
|
|
11
|
-
import { hasDecksState, readDecksState } from "../decks-state"
|
|
12
12
|
import { exportToPdf } from "../pdf/export"
|
|
13
13
|
import { assertExportQAPassed } from "../qa/export-gate"
|
|
14
14
|
import { recordRenderedArtifact, workspaceRelative } from "../workspace-state/rendered-artifacts"
|
|
15
|
-
import { resolveActiveHtmlDeckPath } from "../workspace-state/render-targets"
|
|
16
15
|
|
|
17
16
|
export async function handlePdf(
|
|
18
17
|
filePath: string,
|
|
@@ -22,15 +21,15 @@ export async function handlePdf(
|
|
|
22
21
|
const root = resolve(workspaceRoot)
|
|
23
22
|
const resolvedFile = resolvePdfDeckFile(root, filePath)
|
|
24
23
|
|
|
25
|
-
if (!resolvedFile) {
|
|
24
|
+
if (!resolvedFile.ok) {
|
|
26
25
|
await send(
|
|
27
|
-
|
|
28
|
-
"
|
|
26
|
+
`**PDF export cannot start**\n\n${resolvedFile.error}\n\n` +
|
|
27
|
+
"Usage: `/revela export --deck pdf [file_path]`"
|
|
29
28
|
)
|
|
30
29
|
return
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
const abs = resolvedFile.absoluteFile
|
|
32
|
+
const abs = resolvedFile.deck.absoluteFile
|
|
34
33
|
await send(`Running pre-export QA for \`${abs}\`...`)
|
|
35
34
|
|
|
36
35
|
try {
|
|
@@ -38,7 +37,7 @@ export async function handlePdf(
|
|
|
38
37
|
await send(`Exporting \`${abs}\` to PDF...`)
|
|
39
38
|
const result = await exportToPdf(abs)
|
|
40
39
|
recordRenderedArtifact(root, {
|
|
41
|
-
sourceHtmlPath: resolvedFile.file,
|
|
40
|
+
sourceHtmlPath: resolvedFile.deck.file,
|
|
42
41
|
outputPath: result.outputPath,
|
|
43
42
|
type: "pdf",
|
|
44
43
|
actor: "revela-pdf",
|
|
@@ -56,17 +55,27 @@ export async function handlePdf(
|
|
|
56
55
|
}
|
|
57
56
|
}
|
|
58
57
|
|
|
59
|
-
function resolvePdfDeckFile(workspaceRoot: string, filePath: string): { file: string; absoluteFile: string } |
|
|
58
|
+
function resolvePdfDeckFile(workspaceRoot: string, filePath: string): { ok: true; deck: { file: string; absoluteFile: string } } | { ok: false; error: string } {
|
|
60
59
|
const explicit = filePath.trim()
|
|
61
60
|
if (explicit) {
|
|
62
61
|
const absoluteFile = resolve(workspaceRoot, explicit)
|
|
63
|
-
return {
|
|
62
|
+
if (!existsSync(absoluteFile)) return { ok: false, error: `Deck HTML not found: ${explicit}` }
|
|
63
|
+
if (!/\.html?$/i.test(absoluteFile)) return { ok: false, error: `File must be an HTML file: ${explicit}` }
|
|
64
|
+
return { ok: true, deck: { file: workspaceRelative(workspaceRoot, absoluteFile), absoluteFile } }
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
const htmlFiles = listDeckHtmlFiles(workspaceRoot)
|
|
68
|
+
if (htmlFiles.length === 0) return { ok: false, error: "No deck HTML found in decks/. Pass a file path or generate a deck first." }
|
|
69
|
+
if (htmlFiles.length > 1) return { ok: false, error: `Multiple deck HTML files found in decks/: ${htmlFiles.join(", ")}. Pass the deck path explicitly.` }
|
|
70
|
+
const absoluteFile = resolve(workspaceRoot, htmlFiles[0])
|
|
71
|
+
return { ok: true, deck: { file: workspaceRelative(workspaceRoot, absoluteFile), absoluteFile } }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function listDeckHtmlFiles(workspaceRoot: string): string[] {
|
|
75
|
+
const dir = resolve(workspaceRoot, "decks")
|
|
76
|
+
if (!existsSync(dir)) return []
|
|
77
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
78
|
+
.filter((entry) => entry.isFile() && entry.name.toLowerCase().endsWith(".html"))
|
|
79
|
+
.map((entry) => `decks/${entry.name}`)
|
|
80
|
+
.sort((a, b) => a.localeCompare(b))
|
|
72
81
|
}
|
package/lib/commands/pptx.ts
CHANGED
|
@@ -9,11 +9,9 @@
|
|
|
9
9
|
|
|
10
10
|
import { existsSync, readdirSync } from "fs"
|
|
11
11
|
import { relative, resolve, sep } from "path"
|
|
12
|
-
import { hasDecksState, isDeckHtmlPath, readDecksState } from "../decks-state"
|
|
13
12
|
import { assertDeckHtmlContractValid } from "../deck-html/contract"
|
|
14
13
|
import { exportToPptx } from "../pptx/export"
|
|
15
14
|
import { recordRenderedArtifact } from "../workspace-state/rendered-artifacts"
|
|
16
|
-
import { resolveActiveHtmlDeckPath } from "../workspace-state/render-targets"
|
|
17
15
|
|
|
18
16
|
export interface PptxArgs {
|
|
19
17
|
filePath: string
|
|
@@ -23,7 +21,7 @@ export interface PptxArgs {
|
|
|
23
21
|
export interface ResolvedPptxDeck {
|
|
24
22
|
file: string
|
|
25
23
|
absoluteFile: string
|
|
26
|
-
source: "
|
|
24
|
+
source: "discovered" | "file-path"
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
function formatSecs(ms: number): string {
|
|
@@ -47,18 +45,6 @@ export function resolvePptxDeck(workspaceRoot: string, filePath = ""): ResolvedP
|
|
|
47
45
|
return { file: workspaceRelative(root, absoluteFile), absoluteFile, source: "file-path" }
|
|
48
46
|
}
|
|
49
47
|
|
|
50
|
-
if (hasDecksState(root)) {
|
|
51
|
-
const state = readDecksState(root)
|
|
52
|
-
const outputPath = resolveActiveHtmlDeckPath(state)
|
|
53
|
-
if (outputPath && isDeckHtmlPath(outputPath)) {
|
|
54
|
-
const absoluteFile = resolve(root, outputPath)
|
|
55
|
-
if (existsSync(absoluteFile)) {
|
|
56
|
-
const source = state.renderTargets.some((target) => target.type === "html_deck" && target.outputPath === outputPath) ? "render-target" : "decks-state"
|
|
57
|
-
return { file: workspaceRelative(root, absoluteFile), absoluteFile, source }
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
48
|
const htmlFiles = listDeckHtmlFiles(root)
|
|
63
49
|
if (htmlFiles.length === 0) {
|
|
64
50
|
throw new Error("No deck HTML found in decks/. Generate a deck first or pass a file path.")
|
|
@@ -68,7 +54,7 @@ export function resolvePptxDeck(workspaceRoot: string, filePath = ""): ResolvedP
|
|
|
68
54
|
}
|
|
69
55
|
|
|
70
56
|
const absoluteFile = resolve(root, htmlFiles[0])
|
|
71
|
-
return { file: workspaceRelative(root, absoluteFile), absoluteFile, source: "
|
|
57
|
+
return { file: workspaceRelative(root, absoluteFile), absoluteFile, source: "discovered" }
|
|
72
58
|
}
|
|
73
59
|
|
|
74
60
|
export function buildPptxNotesPrompt(deck: ResolvedPptxDeck): string {
|
package/lib/commands/research.ts
CHANGED
|
@@ -16,6 +16,7 @@ export function buildResearchPrompt({
|
|
|
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
|
+
- Drive research from central-claim chapter sufficiency, not only missing proof. Each central claim should aim for framing/background support, one or two bound evidence items or cases/quantitative signals, and implication/risk/boundary material before it is treated as deck-ready.
|
|
19
20
|
- Treat /revela research as authorization to bind clearly supported findings through the safe \`bindResearchFindings\` boundary without asking for item-by-item user confirmation.
|
|
20
21
|
- Preserve evidence boundaries: eliminate caveats only when evidence or narrower wording actually resolves them; otherwise keep precise caveats visible.
|
|
21
22
|
- Do not write decks, briefs, or design artifacts during research.
|
|
@@ -50,6 +51,7 @@ Allowed mutations:
|
|
|
50
51
|
|
|
51
52
|
Binding criteria:
|
|
52
53
|
- 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.
|
|
54
|
+
- For central claims, prefer evidence that helps one of the future chapter jobs: framing/background, proof/case/quantitative signal, or implication/risk/boundary. If research only finds a weak context fact, bind or record it narrowly and keep the chapter sufficiency gap open.
|
|
53
55
|
|
|
54
56
|
Stop conditions:
|
|
55
57
|
- No open externally researchable gaps remain.
|