@cyber-dash-tech/revela 0.17.23 → 0.18.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 +24 -25
- package/README.zh-CN.md +25 -26
- package/bin/revela.ts +2 -4
- package/lib/commands/help.ts +13 -13
- package/lib/commands/init.ts +24 -0
- package/lib/commands/png.ts +29 -0
- package/lib/commands/refine.ts +1 -1
- package/lib/commands/research.ts +24 -0
- package/lib/commands/review.ts +92 -14
- package/lib/decks-state.ts +7 -7
- package/lib/design/designs.ts +44 -0
- package/lib/narrative-state/deck-plan-artifact.ts +849 -19
- package/lib/narrative-state/render-plan.ts +13 -14
- package/lib/pdf/export.ts +84 -24
- package/lib/refine/server.ts +4 -3
- package/lib/runtime/index.ts +52 -7
- package/lib/runtime/review.ts +4 -104
- package/lib/workspace-state/render-targets.ts +2 -2
- package/lib/workspace-state/rendered-artifacts.ts +1 -1
- package/lib/workspace-state/types.ts +1 -1
- package/package.json +1 -1
- package/plugin.ts +31 -42
- package/plugins/revela/.codex-plugin/plugin.json +2 -2
- package/plugins/revela/.mcp.json +1 -1
- package/plugins/revela/mcp/revela-server.ts +118 -58
- package/plugins/revela/skills/revela-design/SKILL.md +9 -1
- package/plugins/revela/skills/revela-domain/SKILL.md +1 -1
- package/plugins/revela/skills/revela-export/SKILL.md +4 -5
- package/plugins/revela/skills/revela-init/SKILL.md +19 -34
- package/plugins/revela/skills/revela-make-deck/SKILL.md +15 -34
- package/plugins/revela/skills/revela-research/SKILL.md +17 -26
- package/plugins/revela/skills/revela-review-deck/SKILL.md +11 -29
- package/skill/SKILL.md +22 -19
- package/plugins/revela/skills/revela-story/SKILL.md +0 -24
|
@@ -207,7 +207,7 @@ export function compileDeckPlanFromNarrative(state: DecksState, options: Compile
|
|
|
207
207
|
compiled: true,
|
|
208
208
|
skipped: false,
|
|
209
209
|
narrativeHash,
|
|
210
|
-
planArtifactPath: "deck-plan
|
|
210
|
+
planArtifactPath: "deck-plan.md",
|
|
211
211
|
slideCount: 0,
|
|
212
212
|
slides: [],
|
|
213
213
|
chapters: [],
|
|
@@ -236,8 +236,8 @@ function buildDeckPlanningPacket(narrative: NarrativeStateV1, narrativeHash: str
|
|
|
236
236
|
|
|
237
237
|
function buildDeckPlanRequirements(narrativeHash: string): DeckPlanRequirements {
|
|
238
238
|
return {
|
|
239
|
-
planArtifactPath: "deck-plan
|
|
240
|
-
slidePlanDir: "
|
|
239
|
+
planArtifactPath: "deck-plan.md",
|
|
240
|
+
slidePlanDir: "",
|
|
241
241
|
defaultProfile: "executive decision deck, usually 12-18 slides unless the user confirms otherwise",
|
|
242
242
|
userConfirmations: [
|
|
243
243
|
"Confirm target slide count or acceptable range when it is unclear.",
|
|
@@ -245,7 +245,7 @@ function buildDeckPlanRequirements(narrativeHash: string): DeckPlanRequirements
|
|
|
245
245
|
"Confirm language, emphasis, or visual style only when needed before writing the plan.",
|
|
246
246
|
],
|
|
247
247
|
authoringRules: [
|
|
248
|
-
"LLM writes deck-plan
|
|
248
|
+
"LLM writes canonical deck-plan.md from the planning packet; compileDeckPlan does not generate the final slide list.",
|
|
249
249
|
"Use 3-5 chapters for normal executive decks.",
|
|
250
250
|
"Cover every central claim, but group related central claims into chapters instead of giving each claim its own chapter.",
|
|
251
251
|
"Each substantive chapter should have framing, proof, and implication/boundary coverage.",
|
|
@@ -254,18 +254,17 @@ function buildDeckPlanRequirements(narrativeHash: string): DeckPlanRequirements
|
|
|
254
254
|
"Preserve evidence ids, source trace, supported scope, unsupported scope, caveats, and strength where available.",
|
|
255
255
|
"Do not render internal labels such as Evidence gap:, Unsupported scope:, Caveat:, Missing Data, or Evidence Boundary in executive body copy.",
|
|
256
256
|
"Do not infer plan structure from DECKS.json slides[]; it is compatibility cache only.",
|
|
257
|
-
"Use
|
|
257
|
+
"Use sourceLinks in slide blocks for materials, findings, assets, URLs, and caveats; do not use canonical ## Relations in deck-plan files.",
|
|
258
258
|
],
|
|
259
259
|
requiredSections: [
|
|
260
|
+
"Goal",
|
|
261
|
+
"Audience",
|
|
262
|
+
"Design",
|
|
260
263
|
"Source Authority",
|
|
261
|
-
"Audience / Goal / Decision",
|
|
262
|
-
"Deck Parameters",
|
|
263
264
|
"Chapter Map",
|
|
264
|
-
"
|
|
265
|
-
"
|
|
266
|
-
"
|
|
267
|
-
"Chapter Writing Batches",
|
|
268
|
-
"HTML Identity Contract",
|
|
265
|
+
"Slides",
|
|
266
|
+
"Unresolved Inputs",
|
|
267
|
+
"HTML Contract",
|
|
269
268
|
],
|
|
270
269
|
}
|
|
271
270
|
}
|
|
@@ -274,13 +273,13 @@ export function buildRenderPlanContract(deck: DeckSpec, chapters: DeckPlanChapte
|
|
|
274
273
|
return {
|
|
275
274
|
sourceAuthority: {
|
|
276
275
|
meaning: "revela-narrative/ canonical narrative state",
|
|
277
|
-
renderPlan: "deck-plan
|
|
276
|
+
renderPlan: "deck-plan.md plus compileDeckPlan planning packet",
|
|
278
277
|
state: "DECKS.json compatibility/render state only; slides[] is cached projection data",
|
|
279
278
|
htmlIdentity: "positive 1-based data-slide-index values, unique and strictly increasing in DOM order",
|
|
280
279
|
},
|
|
281
280
|
renderRules: [
|
|
282
281
|
"Do not infer deck structure, slide count, or chapter substance from DECKS.json slides[].",
|
|
283
|
-
"Use the compileDeckPlan planning packet plus deck-plan
|
|
282
|
+
"Use the compileDeckPlan planning packet plus deck-plan.md as the render-plan contract.",
|
|
284
283
|
"Render chapter divider slides with the toc component when slideKind is chapter-divider.",
|
|
285
284
|
"Chapter divider and global TOC slides are structural wayfinding and do not count toward central-claim substance.",
|
|
286
285
|
"Each central claim chapter needs non-structural framing, proof, and implication/boundary slides unless the current deck-plan projection explicitly says otherwise.",
|
package/lib/pdf/export.ts
CHANGED
|
@@ -226,6 +226,18 @@ export interface ExportResult {
|
|
|
226
226
|
warnings?: string[]
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
export interface ExportPngResult {
|
|
230
|
+
outputDir: string
|
|
231
|
+
files: string[]
|
|
232
|
+
slideCount: number
|
|
233
|
+
durationMs: number
|
|
234
|
+
exportMode: "deck"
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface ExportPngOptions {
|
|
238
|
+
outputDir?: string
|
|
239
|
+
}
|
|
240
|
+
|
|
229
241
|
/**
|
|
230
242
|
* Export an HTML slide deck to PDF.
|
|
231
243
|
*
|
|
@@ -268,8 +280,78 @@ export async function exportDeckToPdf(htmlFilePath: string): Promise<Omit<Export
|
|
|
268
280
|
|
|
269
281
|
const outputPath = derivePdfPath(abs)
|
|
270
282
|
|
|
283
|
+
const screenshots = await screenshotDeckSlides(abs, "pdf")
|
|
284
|
+
|
|
285
|
+
// ── Step 3: Assemble PDF with pdf-lib ─────────────────────────────────────
|
|
286
|
+
const pdfDoc = await PDFDocument.create()
|
|
287
|
+
|
|
288
|
+
for (const pngBuf of screenshots) {
|
|
289
|
+
const pngImage = await pdfDoc.embedPng(new Uint8Array(pngBuf))
|
|
290
|
+
// Each page is exactly the canvas size (points = pixels at 1:1 for screen PDF)
|
|
291
|
+
const page = pdfDoc.addPage([CANVAS_W, CANVAS_H])
|
|
292
|
+
page.drawImage(pngImage, {
|
|
293
|
+
x: 0,
|
|
294
|
+
y: 0,
|
|
295
|
+
width: CANVAS_W,
|
|
296
|
+
height: CANVAS_H,
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const pdfBytes = await pdfDoc.save()
|
|
301
|
+
writeFileSync(outputPath, pdfBytes)
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
outputPath,
|
|
305
|
+
slideCount: screenshots.length,
|
|
306
|
+
durationMs: Date.now() - startMs,
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export async function exportDeckToPng(htmlFilePath: string, options: ExportPngOptions = {}): Promise<ExportPngResult> {
|
|
311
|
+
const startMs = Date.now()
|
|
312
|
+
const abs = resolve(htmlFilePath)
|
|
313
|
+
|
|
314
|
+
if (!existsSync(abs)) {
|
|
315
|
+
throw new Error(`File not found: ${abs}`)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (!/\.html?$/i.test(abs)) {
|
|
319
|
+
throw new Error(`Not an HTML file: ${abs}`)
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const outputDir = options.outputDir ?? join(dirname(abs), `${basename(abs).replace(/\.html?$/i, "")}-png`)
|
|
323
|
+
mkdirSync(outputDir, { recursive: true })
|
|
324
|
+
const screenshots = await screenshotDeckSlides(abs, "png")
|
|
325
|
+
const files: string[] = []
|
|
326
|
+
|
|
327
|
+
screenshots.forEach((pngBuf, index) => {
|
|
328
|
+
const outputPath = join(outputDir, `slide-${String(index + 1).padStart(3, "0")}.png`)
|
|
329
|
+
writeFileSync(outputPath, new Uint8Array(pngBuf))
|
|
330
|
+
files.push(outputPath)
|
|
331
|
+
})
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
outputDir,
|
|
335
|
+
files,
|
|
336
|
+
slideCount: screenshots.length,
|
|
337
|
+
durationMs: Date.now() - startMs,
|
|
338
|
+
exportMode: "deck",
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
async function screenshotDeckSlides(htmlFilePath: string, label: "pdf" | "png"): Promise<Buffer[]> {
|
|
343
|
+
const abs = resolve(htmlFilePath)
|
|
344
|
+
|
|
345
|
+
if (!existsSync(abs)) {
|
|
346
|
+
throw new Error(`File not found: ${abs}`)
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (!/\.html?$/i.test(abs)) {
|
|
350
|
+
throw new Error(`Not an HTML file: ${abs}`)
|
|
351
|
+
}
|
|
352
|
+
|
|
271
353
|
// ── Step 1: Download external images and rewrite HTML ─────────────────────
|
|
272
|
-
const tmpDir = join("/tmp", `revela
|
|
354
|
+
const tmpDir = join("/tmp", `revela-${label}-${randomBytes(6).toString("hex")}`)
|
|
273
355
|
mkdirSync(tmpDir, { recursive: true })
|
|
274
356
|
|
|
275
357
|
let tmpHtmlPath: string
|
|
@@ -373,27 +455,5 @@ export async function exportDeckToPdf(htmlFilePath: string): Promise<Omit<Export
|
|
|
373
455
|
}
|
|
374
456
|
}
|
|
375
457
|
|
|
376
|
-
|
|
377
|
-
const pdfDoc = await PDFDocument.create()
|
|
378
|
-
|
|
379
|
-
for (const pngBuf of screenshots) {
|
|
380
|
-
const pngImage = await pdfDoc.embedPng(new Uint8Array(pngBuf))
|
|
381
|
-
// Each page is exactly the canvas size (points = pixels at 1:1 for screen PDF)
|
|
382
|
-
const page = pdfDoc.addPage([CANVAS_W, CANVAS_H])
|
|
383
|
-
page.drawImage(pngImage, {
|
|
384
|
-
x: 0,
|
|
385
|
-
y: 0,
|
|
386
|
-
width: CANVAS_W,
|
|
387
|
-
height: CANVAS_H,
|
|
388
|
-
})
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
const pdfBytes = await pdfDoc.save()
|
|
392
|
-
writeFileSync(outputPath, pdfBytes)
|
|
393
|
-
|
|
394
|
-
return {
|
|
395
|
-
outputPath,
|
|
396
|
-
slideCount: screenshots.length,
|
|
397
|
-
durationMs: Date.now() - startMs,
|
|
398
|
-
}
|
|
458
|
+
return screenshots
|
|
399
459
|
}
|
package/lib/refine/server.ts
CHANGED
|
@@ -217,19 +217,19 @@ async function handleRequest(req: Request): Promise<Response> {
|
|
|
217
217
|
if (url.pathname === "/api/inspect" && req.method === "POST") {
|
|
218
218
|
const session = validateSession(url.searchParams.get("token"))
|
|
219
219
|
if (!session.ok) return session.response
|
|
220
|
-
return
|
|
220
|
+
return jsonResponse({ ok: false, error: "Review Insight/Inspect was removed in Revela 0.18. Use Comment for deck edits." }, 410)
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
if (url.pathname === "/api/inspect-result" && req.method === "GET") {
|
|
224
224
|
const session = validateSession(url.searchParams.get("token"))
|
|
225
225
|
if (!session.ok) return session.response
|
|
226
|
-
return
|
|
226
|
+
return jsonResponse({ ok: false, error: "Review Insight/Inspect was removed in Revela 0.18." }, 410)
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
if (url.pathname === "/api/inspect-events" && req.method === "GET") {
|
|
230
230
|
const session = validateSession(url.searchParams.get("token"))
|
|
231
231
|
if (!session.ok) return session.response
|
|
232
|
-
return
|
|
232
|
+
return jsonResponse({ ok: false, error: "Review Insight/Inspect was removed in Revela 0.18." }, 410)
|
|
233
233
|
}
|
|
234
234
|
|
|
235
235
|
if (url.pathname === "/api/deck-version" && req.method === "GET") {
|
|
@@ -1133,6 +1133,7 @@ export function renderRefineShell(token: string, defaultMode: RefineMode = "edit
|
|
|
1133
1133
|
.tab.active { position: relative; top: 1px; background: #fbfaf7; border-color: #d8d2c6; color: #111827; box-shadow: 0 -7px 16px rgba(31,41,51,.05); }
|
|
1134
1134
|
.tab-panel { display: none; flex-direction: column; gap: 12px; padding-top: 12px; }
|
|
1135
1135
|
.tab-panel.active { display: flex; }
|
|
1136
|
+
#inspectTab, #inspectPanel { display: none !important; }
|
|
1136
1137
|
.sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
|
|
1137
1138
|
.selection-summary { padding: 10px 12px; border: 1px solid #d8d2c6; border-radius: 14px; background: #fbfaf7; color: #3f3a33; font-size: 13px; line-height: 1.45; box-shadow: 0 8px 22px rgba(31,41,51,.05); }
|
|
1138
1139
|
.selection-summary strong { display: block; margin-bottom: 7px; color: #756f66; font-size: 11px; letter-spacing: .09em; text-transform: uppercase; }
|
package/lib/runtime/index.ts
CHANGED
|
@@ -19,13 +19,12 @@ import {
|
|
|
19
19
|
} from "../design/designs"
|
|
20
20
|
import { createDeckFoundation as createDeckFoundationShell } from "../deck-html/foundation"
|
|
21
21
|
import { activeDomain, activateDomain, createDomainDraftPackage, createDomainPackage, getDomainSkillMd, installDomainDraftPackage, listDomains, seedBuiltinDomains, validateDomainDraftPackage, validateDomainPackage } from "../domain/domains"
|
|
22
|
-
import { computeNarrativeHash } from "../narrative-state/hash"
|
|
23
22
|
import { compileNarrativeVault } from "../narrative-vault/compile"
|
|
24
23
|
import { autoCompileNarrativeVault } from "../narrative-vault/auto-compile"
|
|
25
24
|
import { extractNarrativeVaultMarkdownTargetsFromPatch } from "../narrative-vault/hook-targets"
|
|
26
25
|
import { runNarrativeMarkdownQa, type MarkdownQaOptions } from "../narrative-vault/markdown-qa"
|
|
27
26
|
import { formatArtifactQaUserNotice, formatMarkdownQaUserNotice } from "../hook-notifications"
|
|
28
|
-
import { readDeckPlanArtifact } from "../narrative-state/deck-plan-artifact"
|
|
27
|
+
import { deckPlanDesignDiagnostics, readDeckPlanArtifact, upsertDeckPlanSlideArtifact, type DeckPlanSlideUpsertInput } from "../narrative-state/deck-plan-artifact"
|
|
29
28
|
import { extractDesignClasses } from "../design/designs"
|
|
30
29
|
import { recordRenderedArtifact, workspaceRelative } from "../workspace-state/rendered-artifacts"
|
|
31
30
|
import { checkMaterialIntake, extractMaterial, materialIntakeNoticeForCommand, prepareLocalMaterials, recordMaterialReview } from "../material-intake"
|
|
@@ -76,6 +75,10 @@ export interface RuntimeDesignComponentReadInput {
|
|
|
76
75
|
component: string | string[]
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
export interface RuntimeDeckPlanSlideUpsertInput extends RuntimeWorkspaceInput, DeckPlanSlideUpsertInput {
|
|
79
|
+
designName?: string
|
|
80
|
+
}
|
|
81
|
+
|
|
79
82
|
export interface RuntimeDesignCreateInput {
|
|
80
83
|
name: string
|
|
81
84
|
base?: string
|
|
@@ -147,12 +150,39 @@ export { formatArtifactQaUserNotice, formatMarkdownQaUserNotice }
|
|
|
147
150
|
|
|
148
151
|
export function readDeckPlan(input: RuntimeWorkspaceInput = {}) {
|
|
149
152
|
const workspaceRoot = root(input.workspaceRoot)
|
|
150
|
-
const
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
const read = readDeckPlanArtifact(workspaceRoot)
|
|
154
|
+
if (read.projection) {
|
|
155
|
+
try {
|
|
156
|
+
const inventory = getDesignInventory(read.projection.designName || activeDesign())
|
|
157
|
+
const diagnostics = deckPlanDesignDiagnostics(read.projection, {
|
|
158
|
+
layouts: inventory.layouts.map((layout) => layout.name),
|
|
159
|
+
components: inventory.components.map((component) => component.name),
|
|
160
|
+
layoutSlots: Object.fromEntries(inventory.layouts.map((layout) => [layout.name, layout.slots])),
|
|
161
|
+
componentNesting: Object.fromEntries(inventory.components.map((component) => [component.name, component.nesting])),
|
|
162
|
+
})
|
|
163
|
+
read.projection.diagnostics.push(...diagnostics)
|
|
164
|
+
read.warnings.push(...diagnostics.map((diagnostic) => diagnostic.message))
|
|
165
|
+
} catch {
|
|
166
|
+
// Design diagnostics are advisory; deck-plan reading remains available.
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return read
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function upsertDeckPlanSlide(input: RuntimeDeckPlanSlideUpsertInput) {
|
|
173
|
+
const workspaceRoot = root(input.workspaceRoot)
|
|
174
|
+
const designName = input.designName || activeDesign()
|
|
175
|
+
const inventory = getDesignInventory(designName)
|
|
176
|
+
const result = upsertDeckPlanSlideArtifact(workspaceRoot, input, {
|
|
177
|
+
designLayouts: inventory.layouts.map((layout) => layout.name),
|
|
178
|
+
designComponents: inventory.components.map((component) => component.name),
|
|
179
|
+
layoutSlots: Object.fromEntries(inventory.layouts.map((layout) => [layout.name, layout.slots])),
|
|
180
|
+
componentNesting: Object.fromEntries(inventory.components.map((component) => [component.name, component.nesting])),
|
|
155
181
|
})
|
|
182
|
+
return {
|
|
183
|
+
...result,
|
|
184
|
+
designName,
|
|
185
|
+
}
|
|
156
186
|
}
|
|
157
187
|
|
|
158
188
|
export function createDeckFoundation(input: RuntimeDeckFoundationInput) {
|
|
@@ -218,6 +248,21 @@ export async function exportPptx(input: RuntimeFileInput & { speakerNotes?: Arra
|
|
|
218
248
|
return { ok: true, ...result }
|
|
219
249
|
}
|
|
220
250
|
|
|
251
|
+
export async function exportPng(input: RuntimeFileInput & { outputDir?: string }) {
|
|
252
|
+
const { exportDeckToPng } = await import("../pdf/export")
|
|
253
|
+
const workspaceRoot = root(input.workspaceRoot)
|
|
254
|
+
const filePath = resolve(workspaceRoot, input.file)
|
|
255
|
+
const outputDir = input.outputDir ? resolve(workspaceRoot, input.outputDir) : undefined
|
|
256
|
+
const result = await exportDeckToPng(filePath, { outputDir })
|
|
257
|
+
recordRenderedArtifact(workspaceRoot, {
|
|
258
|
+
sourceHtmlPath: workspaceRelative(resolve(workspaceRoot), filePath),
|
|
259
|
+
outputPath: result.outputDir,
|
|
260
|
+
type: "png",
|
|
261
|
+
actor: "revela-codex-mcp",
|
|
262
|
+
})
|
|
263
|
+
return { ok: true, ...result }
|
|
264
|
+
}
|
|
265
|
+
|
|
221
266
|
export async function reviewDeckRead(input: ReviewDeckReadInput) {
|
|
222
267
|
const review = await import("./review")
|
|
223
268
|
return review.reviewDeckRead(input)
|
package/lib/runtime/review.ts
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { existsSync } from "fs"
|
|
2
2
|
import { resolve } from "path"
|
|
3
|
-
import { DECKS_STATE_FILE, hasDecksState, normalizeWorkspaceDeckState, readDecksState } from "../decks-state"
|
|
4
3
|
import { extractDesignClasses } from "../design/designs"
|
|
5
|
-
import { compileInspectionContext, type InspectionContext } from "../inspection-context/compile"
|
|
6
|
-
import { computeNarrativeHash } from "../narrative-state/hash"
|
|
7
4
|
import { readDeckPlanArtifact } from "../narrative-state/deck-plan-artifact"
|
|
8
|
-
import { compileNarrativeVault } from "../narrative-vault/compile"
|
|
9
|
-
import { formatVaultDiagnosticMarkdown, formatVaultDiagnosticReport } from "../narrative-vault/diagnostic-report"
|
|
10
5
|
import { formatArtifactQAReport, runArtifactQA } from "../qa/artifact"
|
|
11
6
|
import { openRefineDeck } from "../refine/open"
|
|
12
7
|
import { createCodexExecReviewPromptBridge } from "../refine/prompt-bridge"
|
|
@@ -24,13 +19,6 @@ export interface ReviewDeckOpenInput extends ReviewDeckReadInput {
|
|
|
24
19
|
openUrl?: (url: string) => void
|
|
25
20
|
}
|
|
26
21
|
|
|
27
|
-
export interface ReviewDeckInspectionContextResult {
|
|
28
|
-
ok: boolean
|
|
29
|
-
skipped: boolean
|
|
30
|
-
reason?: string
|
|
31
|
-
context?: InspectionContext
|
|
32
|
-
}
|
|
33
|
-
|
|
34
22
|
export async function reviewDeckRead(input: ReviewDeckReadInput): Promise<any> {
|
|
35
23
|
const workspaceRoot = root(input.workspaceRoot)
|
|
36
24
|
const requestedFile = input.file?.trim()
|
|
@@ -55,20 +43,13 @@ export async function reviewDeckRead(input: ReviewDeckReadInput): Promise<any> {
|
|
|
55
43
|
}
|
|
56
44
|
|
|
57
45
|
const artifactQa = await readArtifactQa(workspaceRoot, filePath)
|
|
58
|
-
const
|
|
59
|
-
const deckPlan = readDeckPlan(workspaceRoot, narrativeRead.knownNodeIds, narrativeRead.narrativeHash)
|
|
60
|
-
const { knownNodeIds: _knownNodeIds, ...narrative } = narrativeRead
|
|
61
|
-
const inspectionContext = readInspectionContext(workspaceRoot, file)
|
|
46
|
+
const deckPlan = readDeckPlan(workspaceRoot)
|
|
62
47
|
const diagnostics = {
|
|
63
48
|
artifactQa: artifactQa.summary,
|
|
64
49
|
deckPlan: summarizeDeckPlan(deckPlan),
|
|
65
|
-
narrative: narrative.summary,
|
|
66
|
-
inspectionContext: inspectionContext.ok
|
|
67
|
-
? { ok: true, skipped: false }
|
|
68
|
-
: { ok: false, skipped: true, reason: inspectionContext.reason },
|
|
69
50
|
}
|
|
70
51
|
const markdown = input.format === "markdown"
|
|
71
|
-
? formatReviewDeckReadMarkdown({ file, artifactQa, deckPlan
|
|
52
|
+
? formatReviewDeckReadMarkdown({ file, artifactQa, deckPlan })
|
|
72
53
|
: undefined
|
|
73
54
|
|
|
74
55
|
return {
|
|
@@ -76,11 +57,7 @@ export async function reviewDeckRead(input: ReviewDeckReadInput): Promise<any> {
|
|
|
76
57
|
file,
|
|
77
58
|
artifactQa,
|
|
78
59
|
deckPlan,
|
|
79
|
-
narrative,
|
|
80
60
|
diagnostics,
|
|
81
|
-
inspectionContext,
|
|
82
|
-
artifactCoverage: inspectionContext.context?.artifactCoverage ?? [],
|
|
83
|
-
evidenceTrace: inspectionContext.context?.slides.flatMap((slide) => slide.evidence) ?? narrative.evidenceTrace,
|
|
84
61
|
markdown,
|
|
85
62
|
}
|
|
86
63
|
}
|
|
@@ -158,76 +135,8 @@ async function readArtifactQa(workspaceRoot: string, filePath: string) {
|
|
|
158
135
|
}
|
|
159
136
|
}
|
|
160
137
|
|
|
161
|
-
function
|
|
162
|
-
|
|
163
|
-
return {
|
|
164
|
-
ok: false,
|
|
165
|
-
skipped: true,
|
|
166
|
-
reason: "No revela-narrative/ vault exists; narrative diagnostics skipped.",
|
|
167
|
-
summary: { ok: false, skipped: true, reason: "No revela-narrative/ vault exists; narrative diagnostics skipped." },
|
|
168
|
-
evidenceTrace: [],
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const compiled = compileNarrativeVault(workspaceRoot)
|
|
173
|
-
const report = formatVaultDiagnosticReport(compiled.diagnostics)
|
|
174
|
-
const narrative = compiled.narrative
|
|
175
|
-
return {
|
|
176
|
-
ok: compiled.ok,
|
|
177
|
-
skipped: false,
|
|
178
|
-
narrativeHash: narrative ? computeNarrativeHash(narrative) : undefined,
|
|
179
|
-
summary: report,
|
|
180
|
-
diagnostics: compiled.diagnostics,
|
|
181
|
-
diagnosticsMarkdown: formatVaultDiagnosticMarkdown(report),
|
|
182
|
-
evidenceTrace: narrative?.evidenceBindings.map((binding) => ({
|
|
183
|
-
id: binding.id,
|
|
184
|
-
claimId: binding.claimId,
|
|
185
|
-
source: binding.source,
|
|
186
|
-
sourcePath: binding.sourcePath,
|
|
187
|
-
findingsFile: binding.findingsFile,
|
|
188
|
-
quote: binding.quote,
|
|
189
|
-
location: binding.location,
|
|
190
|
-
url: binding.url,
|
|
191
|
-
supportScope: binding.supportScope,
|
|
192
|
-
unsupportedScope: binding.unsupportedScope,
|
|
193
|
-
caveat: binding.caveat,
|
|
194
|
-
strength: binding.strength,
|
|
195
|
-
})) ?? [],
|
|
196
|
-
knownNodeIds: compiled.graph ? new Set(compiled.graph.nodes.map((node) => node.id)) : undefined,
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function readDeckPlan(workspaceRoot: string, knownNodeIds: Set<string> | undefined, narrativeHash: string | undefined) {
|
|
201
|
-
return readDeckPlanArtifact(workspaceRoot, { knownNodeIds, narrativeHash })
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function readInspectionContext(workspaceRoot: string, file: string): ReviewDeckInspectionContextResult {
|
|
205
|
-
if (!hasDecksState(workspaceRoot)) {
|
|
206
|
-
return {
|
|
207
|
-
ok: false,
|
|
208
|
-
skipped: true,
|
|
209
|
-
reason: `No ${DECKS_STATE_FILE} exists; legacy inspection context skipped for file-native deck.`,
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
try {
|
|
214
|
-
const state = normalizeWorkspaceDeckState(readDecksState(workspaceRoot), workspaceRoot)
|
|
215
|
-
const slug = Object.entries(state.decks).find(([, deck]) => normalizePath(deck.outputPath) === normalizePath(file))?.[0]
|
|
216
|
-
if (!slug) {
|
|
217
|
-
return {
|
|
218
|
-
ok: false,
|
|
219
|
-
skipped: true,
|
|
220
|
-
reason: `No ${DECKS_STATE_FILE} deck outputPath matches ${file}; legacy inspection context skipped.`,
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
return { ok: true, skipped: false, context: compileInspectionContext(state, slug) }
|
|
224
|
-
} catch (e) {
|
|
225
|
-
return {
|
|
226
|
-
ok: false,
|
|
227
|
-
skipped: true,
|
|
228
|
-
reason: `Could not compile legacy inspection context: ${e instanceof Error ? e.message : String(e)}`,
|
|
229
|
-
}
|
|
230
|
-
}
|
|
138
|
+
function readDeckPlan(workspaceRoot: string) {
|
|
139
|
+
return readDeckPlanArtifact(workspaceRoot)
|
|
231
140
|
}
|
|
232
141
|
|
|
233
142
|
function summarizeDeckPlan(deckPlan: ReturnType<typeof readDeckPlanArtifact>) {
|
|
@@ -243,8 +152,6 @@ function formatReviewDeckReadMarkdown(input: {
|
|
|
243
152
|
file: string
|
|
244
153
|
artifactQa: Awaited<ReturnType<typeof readArtifactQa>>
|
|
245
154
|
deckPlan: ReturnType<typeof readDeckPlanArtifact>
|
|
246
|
-
narrative: ReturnType<typeof readNarrative>
|
|
247
|
-
inspectionContext: ReviewDeckInspectionContextResult
|
|
248
155
|
}): string {
|
|
249
156
|
const lines = [
|
|
250
157
|
"# Review Deck Read",
|
|
@@ -253,19 +160,12 @@ function formatReviewDeckReadMarkdown(input: {
|
|
|
253
160
|
"",
|
|
254
161
|
`Artifact QA: ${input.artifactQa.summary.passed ? "passed" : "failed"} (${input.artifactQa.summary.errors} hard error(s), ${input.artifactQa.summary.warnings} warning(s))`,
|
|
255
162
|
`Deck-plan: ${input.deckPlan.ok ? "read" : `skipped/diagnostic - ${input.deckPlan.reason ?? "not available"}`}`,
|
|
256
|
-
`Narrative: ${input.narrative.skipped ? input.narrative.reason : input.narrative.summary.summary}`,
|
|
257
|
-
`Inspection context: ${input.inspectionContext.ok ? "read" : `skipped - ${input.inspectionContext.reason}`}`,
|
|
258
163
|
"",
|
|
259
164
|
input.artifactQa.markdown,
|
|
260
165
|
]
|
|
261
|
-
if (!input.narrative.skipped && input.narrative.diagnosticsMarkdown) lines.push("", input.narrative.diagnosticsMarkdown)
|
|
262
166
|
return lines.join("\n")
|
|
263
167
|
}
|
|
264
168
|
|
|
265
|
-
function normalizePath(value: string): string {
|
|
266
|
-
return value.replace(/\\/g, "/").replace(/^\.\/+/, "")
|
|
267
|
-
}
|
|
268
|
-
|
|
269
169
|
function root(workspaceRoot: string | undefined): string {
|
|
270
170
|
return resolve(workspaceRoot || process.cwd())
|
|
271
171
|
}
|
|
@@ -47,7 +47,7 @@ export function upsertRenderTarget(state: DecksState, target: RenderTarget): Dec
|
|
|
47
47
|
return state
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
export function deriveExportRenderTarget(htmlTarget: RenderTarget, type: "pdf" | "pptx", outputPath: string): RenderTarget {
|
|
50
|
+
export function deriveExportRenderTarget(htmlTarget: RenderTarget, type: "pdf" | "pptx" | "png", outputPath: string): RenderTarget {
|
|
51
51
|
const normalizedOutput = normalizeWorkspacePath(outputPath)
|
|
52
52
|
return cleanRenderTarget({
|
|
53
53
|
id: renderTargetId(type, normalizedOutput),
|
|
@@ -64,7 +64,7 @@ export function deriveExportRenderTarget(htmlTarget: RenderTarget, type: "pdf" |
|
|
|
64
64
|
|
|
65
65
|
export function recordArtifactRenderTarget(
|
|
66
66
|
state: DecksState,
|
|
67
|
-
input: { sourceHtmlPath: string; type: "pdf" | "pptx"; outputPath: string; artifactVersion?: string },
|
|
67
|
+
input: { sourceHtmlPath: string; type: "pdf" | "pptx" | "png"; outputPath: string; artifactVersion?: string },
|
|
68
68
|
): RenderTarget {
|
|
69
69
|
const normalizedSource = normalizeWorkspacePath(input.sourceHtmlPath)
|
|
70
70
|
const activeTarget = ensureActiveHtmlDeckRenderTarget(state)
|
|
@@ -108,7 +108,7 @@ export type WorkspaceActionType =
|
|
|
108
108
|
|
|
109
109
|
export interface RenderTarget {
|
|
110
110
|
id: string
|
|
111
|
-
type: "html_deck" | "pdf" | "pptx" | "brief" | "executive_brief" | "appendix" | "qa_view" | "interactive_page"
|
|
111
|
+
type: "html_deck" | "pdf" | "pptx" | "png" | "brief" | "executive_brief" | "appendix" | "qa_view" | "interactive_page"
|
|
112
112
|
outputPath?: string
|
|
113
113
|
sourceNodeIds: string[]
|
|
114
114
|
artifactVersion?: string
|
package/package.json
CHANGED