@cyber-dash-tech/revela 0.16.2 → 0.16.4
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/lib/agents/research-prompt.ts +7 -7
- package/lib/commands/narrative.ts +6 -8
- package/lib/commands/research.ts +3 -2
- package/lib/narrative-state/display.ts +12 -40
- package/lib/narrative-state/map-html.ts +23 -137
- package/lib/narrative-state/map.ts +2 -320
- package/lib/refine/server.ts +472 -5
- package/lib/refine/visual-targets.ts +295 -0
- package/package.json +1 -1
- package/plugin.ts +3 -0
- package/tools/narrative-view.ts +6 -10
|
@@ -23,8 +23,6 @@ export interface NarrativeMap {
|
|
|
23
23
|
risks: NarrativeMapRisk[]
|
|
24
24
|
researchGaps: NarrativeMapResearchGap[]
|
|
25
25
|
artifactCoverage: NarrativeMapArtifact[]
|
|
26
|
-
workbench: NarrativeMapWorkbench
|
|
27
|
-
nextActions: string[]
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
export interface NarrativeMapSnapshot {
|
|
@@ -39,60 +37,7 @@ export interface NarrativeMapSnapshot {
|
|
|
39
37
|
approval: "current" | "stale" | "missing"
|
|
40
38
|
}
|
|
41
39
|
|
|
42
|
-
export interface NarrativeMapClaim extends ClaimEvidenceRecord {
|
|
43
|
-
nextActions: NarrativeMapNextAction[]
|
|
44
|
-
workbenchFlags: NarrativeMapFilterId[]
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export type NarrativeMapActionKind = "research" | "attach_findings" | "narrow_claim" | "approve_narrative" | "make_deck" | "remake_artifact"
|
|
48
|
-
|
|
49
|
-
export type NarrativeMapArtifactStatus = "current" | "stale" | "partial" | "missing" | "no_target"
|
|
50
|
-
|
|
51
|
-
export interface NarrativeMapNextAction {
|
|
52
|
-
kind: NarrativeMapActionKind
|
|
53
|
-
label: string
|
|
54
|
-
command: string
|
|
55
|
-
reason: string
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type NarrativeMapFilterId = "all" | "missing_evidence" | "partial_evidence" | "stale_artifacts" | "open_gaps" | "risks" | "high_priority_objections"
|
|
59
|
-
|
|
60
|
-
export interface NarrativeMapWorkbenchFilter {
|
|
61
|
-
id: NarrativeMapFilterId
|
|
62
|
-
label: string
|
|
63
|
-
count: number
|
|
64
|
-
claimIds: string[]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export interface NarrativeMapArtifactWorkItem {
|
|
68
|
-
artifactId: string
|
|
69
|
-
type: RenderTarget["type"]
|
|
70
|
-
outputPath?: string
|
|
71
|
-
coverageStatus: NarrativeMapArtifact["coverageStatus"]
|
|
72
|
-
contractStatus?: RenderTarget["contractStatus"]
|
|
73
|
-
affectedClaimIds: string[]
|
|
74
|
-
missingClaimIds: string[]
|
|
75
|
-
affectedSlides: Array<{ claimId: string; slideIndex: number; slideTitle: string; role: string; location: string }>
|
|
76
|
-
staleReasons: string[]
|
|
77
|
-
statusNote: string
|
|
78
|
-
recommendedNextCommand: string
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface NarrativeMapWorkbenchSummary {
|
|
82
|
-
approval: NarrativeMapSnapshot["approval"]
|
|
83
|
-
evidenceBlockersCount: number
|
|
84
|
-
artifactStatus: NarrativeMapArtifactStatus
|
|
85
|
-
primaryNextCommand: string
|
|
86
|
-
primaryNextReason: string
|
|
87
|
-
readinessNextActions: string[]
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface NarrativeMapWorkbench {
|
|
91
|
-
summary: NarrativeMapWorkbenchSummary
|
|
92
|
-
filters: NarrativeMapWorkbenchFilter[]
|
|
93
|
-
artifactCoverage: NarrativeMapArtifactWorkItem[]
|
|
94
|
-
renderTargetAction?: NarrativeMapNextAction
|
|
95
|
-
}
|
|
40
|
+
export interface NarrativeMapClaim extends ClaimEvidenceRecord {}
|
|
96
41
|
|
|
97
42
|
export type NarrativeMapEvidence = ClaimEvidenceBindingRecord
|
|
98
43
|
|
|
@@ -165,7 +110,7 @@ export function buildNarrativeMap(state: DecksState): NarrativeMap {
|
|
|
165
110
|
staleReason: artifact.staleReason,
|
|
166
111
|
note: artifact.note,
|
|
167
112
|
}))
|
|
168
|
-
const claims =
|
|
113
|
+
const claims = rawBoard.claims as Record<NarrativeClaim["evidenceStatus"], NarrativeMapClaim[]>
|
|
169
114
|
const claimFlow = claimRecordsInNarrativeOrder(narrative, claims)
|
|
170
115
|
|
|
171
116
|
return {
|
|
@@ -188,250 +133,7 @@ export function buildNarrativeMap(state: DecksState): NarrativeMap {
|
|
|
188
133
|
risks: objectionRisk.risks,
|
|
189
134
|
researchGaps,
|
|
190
135
|
artifactCoverage,
|
|
191
|
-
workbench: buildWorkbench(claimFlow, artifactCoverage, readiness.approval?.current === true, readiness.nextActions, readiness.approval?.current ? "current" : readiness.approval?.stale ? "stale" : "missing"),
|
|
192
|
-
nextActions: readiness.nextActions,
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function withWorkbenchClaimData(
|
|
197
|
-
claimsByStatus: Record<NarrativeClaim["evidenceStatus"], ClaimEvidenceRecord[]>,
|
|
198
|
-
narrative: NarrativeStateV1,
|
|
199
|
-
approved: boolean,
|
|
200
|
-
objectionRisk: ReturnType<typeof getObjectionRiskClaimIndex>,
|
|
201
|
-
researchGaps: NarrativeMapResearchGap[],
|
|
202
|
-
artifacts: NarrativeMapArtifact[],
|
|
203
|
-
): Record<NarrativeClaim["evidenceStatus"], NarrativeMapClaim[]> {
|
|
204
|
-
return Object.fromEntries(Object.entries(claimsByStatus).map(([status, claims]) => [
|
|
205
|
-
status,
|
|
206
|
-
claims.map((claim) => ({
|
|
207
|
-
...claim,
|
|
208
|
-
nextActions: claimNextActions(claim, narrative, approved, objectionRisk, researchGaps, artifacts),
|
|
209
|
-
workbenchFlags: claimWorkbenchFlags(claim, objectionRisk, researchGaps, artifacts),
|
|
210
|
-
})),
|
|
211
|
-
])) as Record<NarrativeClaim["evidenceStatus"], NarrativeMapClaim[]>
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function claimNextActions(
|
|
215
|
-
claim: ClaimEvidenceRecord,
|
|
216
|
-
narrative: NarrativeStateV1,
|
|
217
|
-
approved: boolean,
|
|
218
|
-
objectionRisk: ReturnType<typeof getObjectionRiskClaimIndex>,
|
|
219
|
-
researchGaps: NarrativeMapResearchGap[],
|
|
220
|
-
artifacts: NarrativeMapArtifact[],
|
|
221
|
-
): NarrativeMapNextAction[] {
|
|
222
|
-
const actions: NarrativeMapNextAction[] = []
|
|
223
|
-
const claimGaps = researchGaps.filter((gap) => gap.targetType === "claim" && gap.targetId === claim.id)
|
|
224
|
-
const hasSavedFindings = claimGaps.some((gap) => gap.status === "findings_saved" || gap.status === "attached")
|
|
225
|
-
const needsEvidence = claim.evidenceRequired && (claim.evidenceStatus === "missing" || claim.evidenceStatus === "weak")
|
|
226
|
-
const partialEvidence = claim.evidenceRequired && claim.evidenceStatus === "partial"
|
|
227
|
-
const affectedArtifacts = artifacts.filter((artifact) => artifact.coverageStatus !== "current" && (artifact.affectedClaimIds.includes(claim.id) || artifact.missingClaimIds.includes(claim.id) || artifact.claimIds.includes(claim.id)))
|
|
228
|
-
|
|
229
|
-
if (needsEvidence || claimGaps.some((gap) => gap.status === "open" || gap.status === "in_progress")) actions.push({
|
|
230
|
-
kind: "research",
|
|
231
|
-
label: "Research this gap",
|
|
232
|
-
command: "/revela research",
|
|
233
|
-
reason: needsEvidence ? "Required evidence is missing or weak for this claim." : "An open research gap targets this claim.",
|
|
234
|
-
})
|
|
235
|
-
if (hasSavedFindings) actions.push({
|
|
236
|
-
kind: "attach_findings",
|
|
237
|
-
label: "Attach findings",
|
|
238
|
-
command: "/revela research",
|
|
239
|
-
reason: "Saved or attached findings still need canonical evidence binding.",
|
|
240
|
-
})
|
|
241
|
-
if (partialEvidence || Boolean(claim.unsupportedScope)) actions.push({
|
|
242
|
-
kind: "narrow_claim",
|
|
243
|
-
label: "Narrow claim",
|
|
244
|
-
command: "/revela story",
|
|
245
|
-
reason: claim.unsupportedScope || "Evidence only partially supports the claim scope.",
|
|
246
|
-
})
|
|
247
|
-
if (!approved) actions.push({
|
|
248
|
-
kind: "approve_narrative",
|
|
249
|
-
label: "Approve narrative",
|
|
250
|
-
command: "/revela story",
|
|
251
|
-
reason: "The current narrative is not approved for artifact rendering.",
|
|
252
|
-
})
|
|
253
|
-
if (approved && artifacts.length === 0) actions.push({
|
|
254
|
-
kind: "make_deck",
|
|
255
|
-
label: "Make deck",
|
|
256
|
-
command: "/revela make --deck",
|
|
257
|
-
reason: "No render target is recorded for this approved narrative.",
|
|
258
|
-
})
|
|
259
|
-
if (approved && affectedArtifacts.length > 0) actions.push({
|
|
260
|
-
kind: "remake_artifact",
|
|
261
|
-
label: "Remake stale artifact",
|
|
262
|
-
command: "/revela make --deck",
|
|
263
|
-
reason: "Artifact coverage is stale, partial, or missing for this claim.",
|
|
264
|
-
})
|
|
265
|
-
if (approved && actions.length === 0 && claim.importance === "central") actions.push({
|
|
266
|
-
kind: "make_deck",
|
|
267
|
-
label: "Make deck",
|
|
268
|
-
command: "/revela make --deck",
|
|
269
|
-
reason: "Central claim is ready to hand off to an artifact.",
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
return dedupeActions(actions)
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function claimWorkbenchFlags(
|
|
276
|
-
claim: ClaimEvidenceRecord,
|
|
277
|
-
objectionRisk: ReturnType<typeof getObjectionRiskClaimIndex>,
|
|
278
|
-
researchGaps: NarrativeMapResearchGap[],
|
|
279
|
-
artifacts: NarrativeMapArtifact[],
|
|
280
|
-
): NarrativeMapFilterId[] {
|
|
281
|
-
const flags: NarrativeMapFilterId[] = ["all"]
|
|
282
|
-
if (claim.evidenceRequired && claim.evidenceStatus === "missing") flags.push("missing_evidence")
|
|
283
|
-
if (claim.evidenceRequired && (claim.evidenceStatus === "partial" || claim.evidenceStatus === "weak")) flags.push("partial_evidence")
|
|
284
|
-
if (researchGaps.some((gap) => gap.targetType === "claim" && gap.targetId === claim.id && (gap.status === "open" || gap.status === "in_progress" || gap.status === "findings_saved"))) flags.push("open_gaps")
|
|
285
|
-
if (objectionRisk.risks.some((risk) => risk.claimId === claim.id)) flags.push("risks")
|
|
286
|
-
if (objectionRisk.objections.some((objection) => objection.claimId === claim.id && objection.priority === "high")) flags.push("high_priority_objections")
|
|
287
|
-
if (artifacts.some((artifact) => artifact.coverageStatus !== "current" && (artifact.affectedClaimIds.includes(claim.id) || artifact.missingClaimIds.includes(claim.id) || artifact.claimIds.includes(claim.id)))) flags.push("stale_artifacts")
|
|
288
|
-
return [...new Set(flags)]
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
function buildWorkbench(
|
|
292
|
-
claims: NarrativeMapClaim[],
|
|
293
|
-
artifacts: NarrativeMapArtifact[],
|
|
294
|
-
approved: boolean,
|
|
295
|
-
readinessNextActions: string[],
|
|
296
|
-
approval: NarrativeMapSnapshot["approval"],
|
|
297
|
-
): NarrativeMapWorkbench {
|
|
298
|
-
const filterLabels: Record<NarrativeMapFilterId, string> = {
|
|
299
|
-
all: "All claims",
|
|
300
|
-
missing_evidence: "Missing evidence",
|
|
301
|
-
partial_evidence: "Partial evidence",
|
|
302
|
-
stale_artifacts: "Stale artifacts",
|
|
303
|
-
open_gaps: "Open gaps",
|
|
304
|
-
risks: "Risks",
|
|
305
|
-
high_priority_objections: "High-priority objections",
|
|
306
136
|
}
|
|
307
|
-
const filterIds: NarrativeMapFilterId[] = ["all", "missing_evidence", "partial_evidence", "stale_artifacts", "open_gaps", "risks", "high_priority_objections"]
|
|
308
|
-
const renderTargetAction = artifacts.length === 0 ? {
|
|
309
|
-
kind: approved ? "make_deck" as const : "approve_narrative" as const,
|
|
310
|
-
label: approved ? "Make deck" : "Approve narrative",
|
|
311
|
-
command: approved ? "/revela make --deck" : "/revela story",
|
|
312
|
-
reason: approved ? "No render target is recorded for this approved narrative." : "Narrative approval is required before rendering artifacts.",
|
|
313
|
-
} : undefined
|
|
314
|
-
return {
|
|
315
|
-
summary: buildWorkbenchSummary(claims, artifacts, approval, readinessNextActions, renderTargetAction?.command),
|
|
316
|
-
filters: filterIds.map((id) => {
|
|
317
|
-
const claimIds = claims.filter((claim) => claim.workbenchFlags.includes(id)).map((claim) => claim.id)
|
|
318
|
-
return { id, label: filterLabels[id], count: claimIds.length, claimIds }
|
|
319
|
-
}),
|
|
320
|
-
artifactCoverage: artifacts.map((artifact) => ({
|
|
321
|
-
artifactId: artifact.id,
|
|
322
|
-
type: artifact.type,
|
|
323
|
-
outputPath: artifact.outputPath,
|
|
324
|
-
coverageStatus: artifact.coverageStatus,
|
|
325
|
-
contractStatus: artifact.contractStatus,
|
|
326
|
-
affectedClaimIds: artifact.affectedClaimIds,
|
|
327
|
-
missingClaimIds: artifact.missingClaimIds,
|
|
328
|
-
affectedSlides: artifact.slideRefs
|
|
329
|
-
.filter((ref) => artifact.affectedClaimIds.includes(ref.claimId) || artifact.missingClaimIds.includes(ref.claimId) || artifact.coverageStatus !== "current")
|
|
330
|
-
.map((ref) => ({ claimId: ref.claimId, slideIndex: ref.slideIndex, slideTitle: ref.slideTitle, role: ref.role, location: ref.location })),
|
|
331
|
-
staleReasons: artifact.staleReasons,
|
|
332
|
-
statusNote: artifactStatusNote(artifact, artifacts),
|
|
333
|
-
recommendedNextCommand: recommendedArtifactCommand(artifact, artifacts),
|
|
334
|
-
})),
|
|
335
|
-
renderTargetAction,
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
function buildWorkbenchSummary(
|
|
340
|
-
claims: NarrativeMapClaim[],
|
|
341
|
-
artifacts: NarrativeMapArtifact[],
|
|
342
|
-
approval: NarrativeMapSnapshot["approval"],
|
|
343
|
-
readinessNextActions: string[],
|
|
344
|
-
renderTargetCommand?: string,
|
|
345
|
-
): NarrativeMapWorkbenchSummary {
|
|
346
|
-
const evidenceBlockersCount = claims.filter((claim) => claim.evidenceRequired && (claim.evidenceStatus === "missing" || claim.evidenceStatus === "weak" || claim.evidenceStatus === "partial")).length
|
|
347
|
-
const artifactStatus = aggregateArtifactStatus(artifacts)
|
|
348
|
-
const primaryNext = primaryNextDecision({ approval, evidenceBlockersCount, artifactStatus, artifacts, renderTargetCommand })
|
|
349
|
-
return {
|
|
350
|
-
approval,
|
|
351
|
-
evidenceBlockersCount,
|
|
352
|
-
artifactStatus,
|
|
353
|
-
primaryNextCommand: primaryNext.command,
|
|
354
|
-
primaryNextReason: primaryNext.reason,
|
|
355
|
-
readinessNextActions,
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
function primaryNextDecision(input: { approval: NarrativeMapSnapshot["approval"]; evidenceBlockersCount: number; artifactStatus: NarrativeMapArtifactStatus; artifacts: NarrativeMapArtifact[]; renderTargetCommand?: string }): { command: string; reason: string } {
|
|
360
|
-
if (input.evidenceBlockersCount > 0) return {
|
|
361
|
-
command: "/revela research",
|
|
362
|
-
reason: `${input.evidenceBlockersCount} evidence-required claim${input.evidenceBlockersCount === 1 ? "" : "s"} still need stronger support before artifact handoff.`,
|
|
363
|
-
}
|
|
364
|
-
if (input.approval !== "current") return {
|
|
365
|
-
command: "/revela story",
|
|
366
|
-
reason: input.approval === "stale" ? "Narrative approval is stale after meaning changed." : "Narrative approval is missing before artifact rendering.",
|
|
367
|
-
}
|
|
368
|
-
if (input.artifactStatus === "no_target") return {
|
|
369
|
-
command: input.renderTargetCommand ?? "/revela make --deck",
|
|
370
|
-
reason: "Approved narrative has no recorded render target yet.",
|
|
371
|
-
}
|
|
372
|
-
if (input.artifactStatus !== "current") {
|
|
373
|
-
const command = input.artifacts.map((artifact) => recommendedArtifactCommand(artifact, input.artifacts)).find((item) => item !== "/revela review --deck") ?? "/revela make --deck"
|
|
374
|
-
return {
|
|
375
|
-
command,
|
|
376
|
-
reason: artifactStatusReason(input.artifactStatus, command),
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
return {
|
|
380
|
-
command: "/revela review --deck",
|
|
381
|
-
reason: "Current HTML deck coverage is recorded; review is the next read-only workspace.",
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function aggregateArtifactStatus(artifacts: NarrativeMapArtifact[]): NarrativeMapArtifactStatus {
|
|
386
|
-
if (artifacts.length === 0) return "no_target"
|
|
387
|
-
if (artifacts.some((artifact) => artifact.coverageStatus === "stale")) return "stale"
|
|
388
|
-
if (artifacts.some((artifact) => artifact.coverageStatus === "missing")) return "missing"
|
|
389
|
-
if (artifacts.some((artifact) => artifact.coverageStatus === "partial")) return "partial"
|
|
390
|
-
return "current"
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
function recommendedArtifactCommand(artifact: NarrativeMapArtifact, artifacts: NarrativeMapArtifact[]): string {
|
|
394
|
-
if (artifact.coverageStatus === "current") return artifact.type === "html_deck" ? "/revela review --deck" : exportCommand(artifact.type) ?? "/revela review --deck"
|
|
395
|
-
if (artifact.type === "html_deck") return "/revela make --deck"
|
|
396
|
-
if ((artifact.type === "pdf" || artifact.type === "pptx") && activeHtmlIsCurrent(artifact, artifacts)) return exportCommand(artifact.type) ?? "/revela make --deck"
|
|
397
|
-
return "/revela make --deck"
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
function artifactStatusNote(artifact: NarrativeMapArtifact, artifacts: NarrativeMapArtifact[]): string {
|
|
401
|
-
if (artifact.coverageStatus === "current") return artifact.type === "html_deck" ? "Current HTML deck is ready for review or export." : `Current ${artifact.type.toUpperCase()} export is recorded.`
|
|
402
|
-
const command = recommendedArtifactCommand(artifact, artifacts)
|
|
403
|
-
if ((artifact.type === "pdf" || artifact.type === "pptx") && command.startsWith("/revela export")) return `HTML deck is current; refresh the ${artifact.type.toUpperCase()} export.`
|
|
404
|
-
if (artifact.coverageStatus === "partial") return "Artifact is partial; remake the deck so all central or evidence-required claims are covered."
|
|
405
|
-
if (artifact.coverageStatus === "missing") return "Artifact is missing required narrative coverage; remake the deck from the approved narrative."
|
|
406
|
-
return "Artifact is stale relative to the current narrative; remake the deck from the approved narrative."
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
function artifactStatusReason(status: Exclude<NarrativeMapArtifactStatus, "current" | "no_target">, command: string): string {
|
|
410
|
-
if (command.startsWith("/revela export")) return "HTML deck coverage is current, but a derived export is stale and should be refreshed."
|
|
411
|
-
if (status === "partial") return "At least one render target only partially covers central or evidence-required claims."
|
|
412
|
-
if (status === "missing") return "At least one render target is missing required narrative coverage."
|
|
413
|
-
return "At least one render target is stale relative to the current narrative."
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
function activeHtmlIsCurrent(artifact: NarrativeMapArtifact, artifacts: NarrativeMapArtifact[]): boolean {
|
|
417
|
-
const expectedHtmlPath = artifact.outputPath?.replace(/\.(pdf|pptx)$/i, ".html")
|
|
418
|
-
return artifacts.some((item) => item.type === "html_deck" && item.coverageStatus === "current" && (!expectedHtmlPath || item.outputPath === expectedHtmlPath))
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
function exportCommand(type: RenderTarget["type"]): string | undefined {
|
|
422
|
-
if (type === "pdf") return "/revela export --deck pdf"
|
|
423
|
-
if (type === "pptx") return "/revela export --deck pptx"
|
|
424
|
-
return undefined
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
function dedupeActions(actions: NarrativeMapNextAction[]): NarrativeMapNextAction[] {
|
|
428
|
-
const seen = new Set<string>()
|
|
429
|
-
return actions.filter((action) => {
|
|
430
|
-
const key = `${action.kind}:${action.command}`
|
|
431
|
-
if (seen.has(key)) return false
|
|
432
|
-
seen.add(key)
|
|
433
|
-
return true
|
|
434
|
-
})
|
|
435
137
|
}
|
|
436
138
|
|
|
437
139
|
function claimRecordsInNarrativeOrder(narrative: NarrativeStateV1, claimsByStatus: Record<NarrativeClaim["evidenceStatus"], NarrativeMapClaim[]>): NarrativeMapClaim[] {
|
|
@@ -497,7 +199,6 @@ export function formatNarrativeMap(map: NarrativeMap): string {
|
|
|
497
199
|
for (const evidence of claim.evidence) {
|
|
498
200
|
lines.push(` Evidence: ${evidenceLine(evidence)}`)
|
|
499
201
|
}
|
|
500
|
-
if (claim.nextActions.length > 0) lines.push(` Next actions: ${claim.nextActions.map((action) => `${action.label} (${action.command})`).join("; ")}`)
|
|
501
202
|
}
|
|
502
203
|
}
|
|
503
204
|
|
|
@@ -546,25 +247,6 @@ export function formatNarrativeMap(map: NarrativeMap): string {
|
|
|
546
247
|
if (artifact.note) lines.push(` Note: ${artifact.note}`)
|
|
547
248
|
}
|
|
548
249
|
|
|
549
|
-
lines.push("", "## Story Workbench")
|
|
550
|
-
lines.push(`- Summary approval: ${map.workbench.summary.approval}`)
|
|
551
|
-
lines.push(`- Summary evidence blockers: ${map.workbench.summary.evidenceBlockersCount}`)
|
|
552
|
-
lines.push(`- Summary artifact status: ${map.workbench.summary.artifactStatus}`)
|
|
553
|
-
lines.push(`- Summary primary next command: ${map.workbench.summary.primaryNextCommand}`)
|
|
554
|
-
lines.push(`- Summary primary next reason: ${map.workbench.summary.primaryNextReason}`)
|
|
555
|
-
for (const filter of map.workbench.filters) lines.push(`- Filter ${filter.id}: ${filter.count}${filter.claimIds.length ? ` (${filter.claimIds.join(", ")})` : ""}`)
|
|
556
|
-
if (map.workbench.renderTargetAction) lines.push(`- Render target action: ${map.workbench.renderTargetAction.label} (${map.workbench.renderTargetAction.command})`)
|
|
557
|
-
for (const item of map.workbench.artifactCoverage) {
|
|
558
|
-
lines.push(`- Artifact work item: ${item.type}: ${item.outputPath ?? item.artifactId} [${item.coverageStatus}] -> ${item.recommendedNextCommand}`)
|
|
559
|
-
lines.push(` Status note: ${item.statusNote}`)
|
|
560
|
-
if (item.missingClaimIds.length) lines.push(` Missing claims: ${item.missingClaimIds.join(", ")}`)
|
|
561
|
-
if (item.affectedClaimIds.length) lines.push(` Affected claims: ${item.affectedClaimIds.join(", ")}`)
|
|
562
|
-
if (item.affectedSlides.length) lines.push(` Affected slides: ${item.affectedSlides.map((slide) => `${slide.slideIndex}:${slide.claimId}`).join(", ")}`)
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
lines.push("", "## Next Actions")
|
|
566
|
-
if (map.nextActions.length === 0) lines.push("- None")
|
|
567
|
-
else for (const action of map.nextActions) lines.push(`- ${action}`)
|
|
568
250
|
return lines.join("\n")
|
|
569
251
|
}
|
|
570
252
|
|