@cyber-dash-tech/revela 0.15.3 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -15
- package/README.zh-CN.md +15 -15
- package/lib/commands/edit.ts +1 -1
- package/lib/commands/help.ts +2 -2
- package/lib/commands/inspect.ts +1 -1
- package/lib/commands/narrative.ts +9 -3
- package/lib/commands/refine.ts +3 -3
- package/lib/commands/review.ts +4 -3
- package/lib/decks-state.ts +142 -4
- package/lib/edit/deck-state.ts +1 -1
- package/lib/edit/resolve-deck.ts +1 -1
- package/lib/inspect/server.ts +2 -2
- package/lib/narrative-state/display.ts +40 -0
- package/lib/narrative-state/map-html.ts +133 -6
- package/lib/narrative-state/map.ts +333 -16
- package/lib/narrative-state/render-plan.ts +254 -84
- package/lib/refine/server.ts +50 -33
- package/package.json +1 -1
- package/plugin.ts +10 -1
- package/skill/NARRATIVE_SKILL.md +5 -5
- package/skill/SKILL.md +2 -2
- package/tools/edit.ts +6 -6
- package/tools/inspection-result.ts +1 -1
- package/tools/narrative-view.ts +11 -1
|
@@ -29,6 +29,16 @@ export interface NarrativeDisplayLabels {
|
|
|
29
29
|
risks: string
|
|
30
30
|
researchGaps: string
|
|
31
31
|
coveredSlides: string
|
|
32
|
+
storyWorkbench: string
|
|
33
|
+
workbenchNote: string
|
|
34
|
+
artifactCoverage: string
|
|
35
|
+
noRenderTargets: string
|
|
36
|
+
nextActions: string
|
|
37
|
+
missingClaims: string
|
|
38
|
+
affectedClaims: string
|
|
39
|
+
affectedSlides: string
|
|
40
|
+
notes: string
|
|
41
|
+
recommendedNextCommand: string
|
|
32
42
|
noClaims: string
|
|
33
43
|
none: string
|
|
34
44
|
}
|
|
@@ -79,6 +89,16 @@ export function defaultNarrativeDisplayLabels(language: NarrativeViewLanguage):
|
|
|
79
89
|
risks: "风险",
|
|
80
90
|
researchGaps: "研究缺口",
|
|
81
91
|
coveredSlides: "已覆盖页面",
|
|
92
|
+
storyWorkbench: "Story 工作台",
|
|
93
|
+
workbenchNote: "按证据缺口、风险、异议和产物覆盖过滤主张;这里只读展示下一步命令,不修改叙事状态。",
|
|
94
|
+
artifactCoverage: "产物覆盖",
|
|
95
|
+
noRenderTargets: "未记录 render target",
|
|
96
|
+
nextActions: "下一步",
|
|
97
|
+
missingClaims: "缺失主张",
|
|
98
|
+
affectedClaims: "受影响主张",
|
|
99
|
+
affectedSlides: "受影响页面",
|
|
100
|
+
notes: "说明",
|
|
101
|
+
recommendedNextCommand: "建议命令",
|
|
82
102
|
noClaims: "没有记录主张",
|
|
83
103
|
none: "无",
|
|
84
104
|
}
|
|
@@ -101,6 +121,16 @@ export function defaultNarrativeDisplayLabels(language: NarrativeViewLanguage):
|
|
|
101
121
|
risks: "リスク",
|
|
102
122
|
researchGaps: "調査ギャップ",
|
|
103
123
|
coveredSlides: "対応スライド",
|
|
124
|
+
storyWorkbench: "Story ワークベンチ",
|
|
125
|
+
workbenchNote: "根拠ギャップ、リスク、反論、成果物カバレッジでクレームを絞り込みます。ここでは次のコマンドだけを読み取り専用で示し、ナラティブ状態は変更しません。",
|
|
126
|
+
artifactCoverage: "成果物カバレッジ",
|
|
127
|
+
noRenderTargets: "render target は記録されていません",
|
|
128
|
+
nextActions: "次のアクション",
|
|
129
|
+
missingClaims: "不足クレーム",
|
|
130
|
+
affectedClaims: "影響クレーム",
|
|
131
|
+
affectedSlides: "影響スライド",
|
|
132
|
+
notes: "メモ",
|
|
133
|
+
recommendedNextCommand: "推奨コマンド",
|
|
104
134
|
noClaims: "クレームは記録されていません",
|
|
105
135
|
none: "なし",
|
|
106
136
|
}
|
|
@@ -122,6 +152,16 @@ export function defaultNarrativeDisplayLabels(language: NarrativeViewLanguage):
|
|
|
122
152
|
risks: "Risks",
|
|
123
153
|
researchGaps: "Research gaps",
|
|
124
154
|
coveredSlides: "Covered slides",
|
|
155
|
+
storyWorkbench: "Story workbench",
|
|
156
|
+
workbenchNote: "Filter claims by evidence gaps, risks, objections, and artifact coverage. This view only suggests next commands; it does not mutate narrative state.",
|
|
157
|
+
artifactCoverage: "Artifact coverage",
|
|
158
|
+
noRenderTargets: "No render targets recorded",
|
|
159
|
+
nextActions: "Next actions",
|
|
160
|
+
missingClaims: "Missing claims",
|
|
161
|
+
affectedClaims: "Affected claims",
|
|
162
|
+
affectedSlides: "Affected slides",
|
|
163
|
+
notes: "Notes",
|
|
164
|
+
recommendedNextCommand: "Recommended next command",
|
|
125
165
|
noClaims: "No claims recorded",
|
|
126
166
|
none: "None",
|
|
127
167
|
}
|
|
@@ -44,6 +44,23 @@ export function renderNarrativeMapHtmlWithDisplay(map: NarrativeMap, display: Va
|
|
|
44
44
|
.layout { display:grid; grid-template-columns:minmax(0,1fr) minmax(360px,430px); gap:18px; margin-top:18px; align-items:start; }
|
|
45
45
|
.flow,.detail-panel { background:rgba(255,253,248,.92); border:1px solid var(--line); border-radius:24px; box-shadow:var(--shadow); }
|
|
46
46
|
.flow { padding:20px; }
|
|
47
|
+
.workbench { margin-top:18px; background:rgba(255,253,248,.92); border:1px solid var(--line); border-radius:24px; box-shadow:var(--shadow); padding:18px 20px; }
|
|
48
|
+
.workbench h2 { margin:0; font-size:18px; letter-spacing:-.025em; }
|
|
49
|
+
.workbench-summary { display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:10px; margin-top:14px; }
|
|
50
|
+
.summary-item { border:1px solid var(--line); border-radius:14px; background:#fff; padding:11px 12px; }
|
|
51
|
+
.summary-label { display:block; color:var(--muted); font-size:11px; font-weight:850; letter-spacing:.05em; text-transform:uppercase; }
|
|
52
|
+
.summary-value { display:block; margin-top:4px; color:#51483f; font-size:14px; font-weight:850; }
|
|
53
|
+
.filter-row { display:flex; flex-wrap:wrap; gap:8px; margin-top:14px; }
|
|
54
|
+
.filter-button { cursor:pointer; border:1px solid var(--line); border-radius:999px; background:#fff; color:var(--muted); padding:8px 11px; font-size:12px; font-weight:850; }
|
|
55
|
+
.filter-button.active { border-color:var(--accent); color:var(--accent); background:#fff4ea; }
|
|
56
|
+
.filter-status { margin:10px 0 0; color:var(--muted); font-size:12px; font-weight:780; }
|
|
57
|
+
.filter-empty { display:none; margin-top:10px; border:1px dashed var(--line); border-radius:14px; padding:12px; color:var(--muted); background:#fffaf3; font-size:13px; }
|
|
58
|
+
.coverage-grid { margin-top:16px; display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:10px; }
|
|
59
|
+
.coverage-item { border:1px solid var(--line); border-radius:16px; background:#fff; padding:13px; }
|
|
60
|
+
.coverage-item h3 { margin:0; font-size:14px; line-height:1.2; }
|
|
61
|
+
.coverage-meta { display:flex; flex-wrap:wrap; gap:6px; margin-top:9px; }
|
|
62
|
+
.coverage-detail { margin:9px 0 0; color:var(--muted); font-size:12px; line-height:1.45; }
|
|
63
|
+
.coverage-detail strong { color:#51483f; }
|
|
47
64
|
.flow-head { display:flex; justify-content:space-between; gap:14px; align-items:flex-start; margin-bottom:18px; }
|
|
48
65
|
.flow-head h2 { margin:0; font-size:18px; letter-spacing:-.025em; }
|
|
49
66
|
.flow-note { margin:4px 0 0; color:var(--muted); font-size:13px; line-height:1.45; }
|
|
@@ -64,6 +81,10 @@ export function renderNarrativeMapHtmlWithDisplay(map: NarrativeMap, display: Va
|
|
|
64
81
|
.claim-section { border-top:1px solid #eee4d8; padding-top:9px; }
|
|
65
82
|
.section-label { display:block; margin-bottom:3px; color:var(--accent); font-size:10px; font-weight:900; letter-spacing:.08em; text-transform:uppercase; }
|
|
66
83
|
.section-text { display:block; color:#51483f; font-size:13px; line-height:1.46; white-space:pre-line; }
|
|
84
|
+
.next-actions { display:flex; flex-direction:column; gap:8px; }
|
|
85
|
+
.next-action { border:1px solid #eee4d8; border-radius:12px; padding:9px; background:#fffaf3; }
|
|
86
|
+
.next-action strong { display:block; color:#51483f; font-size:13px; }
|
|
87
|
+
.next-action code { display:inline-block; margin-top:5px; color:#9c4d1d; font-size:12px; }
|
|
67
88
|
.relation-strip { margin-top:12px; display:grid; gap:7px; }
|
|
68
89
|
.relation { display:grid; grid-template-columns:auto minmax(0,1fr); gap:8px; align-items:flex-start; color:var(--muted); font-size:13px; line-height:1.35; }
|
|
69
90
|
.relation-badge { flex:0 0 auto; border-radius:999px; padding:3px 7px; background:#fff4e8; color:#9c4d1d; border:1px solid #efcfb8; font-size:10px; font-weight:850; text-transform:uppercase; letter-spacing:.04em; }
|
|
@@ -121,12 +142,16 @@ export function renderNarrativeMapHtmlWithDisplay(map: NarrativeMap, display: Va
|
|
|
121
142
|
<div class="detail-body" id="detail-body">${initial?.detailHtml ?? emptyCard(display.labels.claimFlow, display.labels.noClaims)}</div>
|
|
122
143
|
</aside>
|
|
123
144
|
</div>
|
|
145
|
+
${renderWorkbench(map, display)}
|
|
124
146
|
</main>
|
|
125
147
|
<div class="hidden-detail">
|
|
126
148
|
${nodes.map((node) => `<template id="detail-${escapeAttr(node.id)}" data-title="${escapeHtml(node.title)}" data-subtitle="${escapeHtml(claimSubtitle(node.claim, display))}">${node.detailHtml}</template>`).join("")}
|
|
127
149
|
</div>
|
|
128
150
|
<script>
|
|
129
151
|
const buttons = Array.from(document.querySelectorAll('.claim-card'));
|
|
152
|
+
const filters = Array.from(document.querySelectorAll('.filter-button'));
|
|
153
|
+
const filterStatus = document.getElementById('filter-status');
|
|
154
|
+
const filterEmpty = document.getElementById('filter-empty');
|
|
130
155
|
const title = document.getElementById('detail-title');
|
|
131
156
|
const sub = document.getElementById('detail-sub');
|
|
132
157
|
const body = document.getElementById('detail-body');
|
|
@@ -139,6 +164,19 @@ export function renderNarrativeMapHtmlWithDisplay(map: NarrativeMap, display: Va
|
|
|
139
164
|
buttons.forEach((button) => button.classList.toggle('active', button.dataset.nodeId === id));
|
|
140
165
|
}
|
|
141
166
|
buttons.forEach((button) => button.addEventListener('click', () => selectClaim(button.dataset.nodeId)));
|
|
167
|
+
filters.forEach((button) => button.addEventListener('click', () => {
|
|
168
|
+
const filter = button.dataset.filterId || 'all';
|
|
169
|
+
filters.forEach((item) => item.classList.toggle('active', item === button));
|
|
170
|
+
buttons.forEach((claimButton) => {
|
|
171
|
+
const flags = (claimButton.dataset.filters || '').split(' ');
|
|
172
|
+
claimButton.closest('.claim-step').style.display = filter === 'all' || flags.includes(filter) ? '' : 'none';
|
|
173
|
+
});
|
|
174
|
+
const visibleButtons = buttons.filter((claimButton) => claimButton.closest('.claim-step').style.display !== 'none');
|
|
175
|
+
const activeButton = buttons.find((claimButton) => claimButton.classList.contains('active'));
|
|
176
|
+
if (visibleButtons.length > 0 && (!activeButton || activeButton.closest('.claim-step').style.display === 'none')) selectClaim(visibleButtons[0].dataset.nodeId);
|
|
177
|
+
if (filterStatus) filterStatus.textContent = (button.dataset.filterLabel || filter) + ': ' + visibleButtons.length;
|
|
178
|
+
if (filterEmpty) filterEmpty.style.display = visibleButtons.length === 0 ? 'block' : 'none';
|
|
179
|
+
}));
|
|
142
180
|
</script>
|
|
143
181
|
</body>
|
|
144
182
|
</html>`
|
|
@@ -158,7 +196,7 @@ function renderStep(node: FlowNode, map: NarrativeMap, display: ValidatedNarrati
|
|
|
158
196
|
const outgoing = map.claimRelations.filter((relation) => relation.fromClaimId === node.claim.id)
|
|
159
197
|
return `<div class="claim-step">
|
|
160
198
|
<div class="step-rail"><div class="step-dot">${index + 1}</div><div class="step-line"></div></div>
|
|
161
|
-
<button class="claim-card ${escapeAttr(node.claim.evidenceStatus)}${active ? " active" : ""}" data-node-id="${escapeAttr(node.id)}" type="button">
|
|
199
|
+
<button class="claim-card ${escapeAttr(node.claim.evidenceStatus)}${active ? " active" : ""}" data-node-id="${escapeAttr(node.id)}" data-filters="${escapeHtml(node.claim.workbenchFlags.join(" "))}" type="button">
|
|
162
200
|
<span class="claim-title">${escapeHtml(node.title)}</span>
|
|
163
201
|
<span class="claim-meta"><span class="tag">${escapeHtml(localizeValue(node.claim.kind, display))}</span><span class="tag">${escapeHtml(localizeValue(node.claim.importance, display))}</span><span class="tag">${escapeHtml(localizeValue(node.claim.evidenceStatus, display))}</span><span class="tag">${escapeHtml(node.claim.id)}</span></span>
|
|
164
202
|
${renderDisplayCardSummary(node.displayCard, display)}
|
|
@@ -213,9 +251,66 @@ function claimDetail(claim: NarrativeMapClaim, map: NarrativeMap, display: Valid
|
|
|
213
251
|
...(gaps.length ? [[display.labels.researchGaps, gaps.map((item) => `${item.question} [${item.status}/${item.priority}]`).join("<br>")] as [string, string]] : []),
|
|
214
252
|
...(slideRefs.length ? [[display.labels.coveredSlides, slideRefs.map((ref) => localizeSlideRef(ref, display)).join("<br>")] as [string, string]] : []),
|
|
215
253
|
...(coverageGaps.length ? [[systemTerm("artifactCoverage", display), coverageGaps.map((artifact) => `${artifact.type}: ${artifact.coverageStatus}${artifact.staleReasons.length ? ` - ${artifact.staleReasons.join("; ")}` : ""}`).join("<br>")] as [string, string]] : []),
|
|
254
|
+
...(claim.nextActions.length ? [[systemTerm("nextActions", display), renderNextActions(claim, display), true] as [string, string, boolean]] : []),
|
|
216
255
|
])
|
|
217
256
|
}
|
|
218
257
|
|
|
258
|
+
function renderWorkbench(map: NarrativeMap, display: ValidatedNarrativeDisplayModel): string {
|
|
259
|
+
return `<section class="workbench" aria-label="Story workbench">
|
|
260
|
+
<h2>${escapeHtml(systemTerm("storyWorkbench", display))}</h2>
|
|
261
|
+
<p class="flow-note">${escapeHtml(workbenchNote(display))}</p>
|
|
262
|
+
${renderWorkbenchSummary(map, display)}
|
|
263
|
+
<div class="filter-row" aria-label="Story filters">
|
|
264
|
+
${map.workbench.filters.map((filter, index) => `<button type="button" class="filter-button${index === 0 ? " active" : ""}" data-filter-id="${escapeAttr(filter.id)}" data-filter-label="${escapeHtml(localizeFilter(filter.label, display))}">${escapeHtml(localizeFilter(filter.label, display))} (${filter.count})</button>`).join("")}
|
|
265
|
+
</div>
|
|
266
|
+
<p class="filter-status" id="filter-status">${escapeHtml(localizeFilter(map.workbench.filters[0]?.label ?? "All claims", display))}: ${map.workbench.filters[0]?.count ?? 0}</p>
|
|
267
|
+
<div class="filter-empty" id="filter-empty">${escapeHtml(noClaimsMatchFilter(display))}</div>
|
|
268
|
+
<div class="coverage-grid">
|
|
269
|
+
${map.workbench.artifactCoverage.length ? map.workbench.artifactCoverage.map((item) => renderCoverageItem(item, display)).join("") : renderNoRenderTargetCard(map, display)}
|
|
270
|
+
</div>
|
|
271
|
+
</section>`
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function renderWorkbenchSummary(map: NarrativeMap, display: ValidatedNarrativeDisplayModel): string {
|
|
275
|
+
const summary = map.workbench.summary
|
|
276
|
+
return `<div class="workbench-summary" aria-label="Story readiness summary">
|
|
277
|
+
<div class="summary-item"><span class="summary-label">${escapeHtml(systemTerm("approval", display))}</span><span class="summary-value">${escapeHtml(localizeValue(summary.approval, display))}</span></div>
|
|
278
|
+
<div class="summary-item"><span class="summary-label">${escapeHtml(readinessSummaryTerm("evidenceBlockers", display))}</span><span class="summary-value">${summary.evidenceBlockersCount}</span></div>
|
|
279
|
+
<div class="summary-item"><span class="summary-label">${escapeHtml(readinessSummaryTerm("artifactStatus", display))}</span><span class="summary-value">${escapeHtml(localizeValue(summary.artifactStatus, display))}</span></div>
|
|
280
|
+
<div class="summary-item"><span class="summary-label">${escapeHtml(readinessSummaryTerm("primaryNextCommand", display))}</span><span class="summary-value"><code>${escapeHtml(summary.primaryNextCommand)}</code></span></div>
|
|
281
|
+
<div class="summary-item"><span class="summary-label">${escapeHtml(readinessSummaryTerm("primaryNextReason", display))}</span><span class="summary-value">${escapeHtml(summary.primaryNextReason)}</span></div>
|
|
282
|
+
</div>`
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function renderNoRenderTargetCard(map: NarrativeMap, display: ValidatedNarrativeDisplayModel): string {
|
|
286
|
+
const action = map.workbench.renderTargetAction
|
|
287
|
+
if (!action) return emptyCard(systemTerm("artifactCoverage", display), systemTerm("noRenderTargets", display))
|
|
288
|
+
return `<article class="coverage-item">
|
|
289
|
+
<h3>${escapeHtml(systemTerm("artifactCoverage", display))}</h3>
|
|
290
|
+
<p class="coverage-detail">${escapeHtml(systemTerm("noRenderTargets", display))}</p>
|
|
291
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("notes", display))}:</strong> ${escapeHtml(localizeAction(action.label, display))} - ${escapeHtml(action.reason)}</p>
|
|
292
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("recommendedNextCommand", display))}:</strong> <code>${escapeHtml(action.command)}</code></p>
|
|
293
|
+
</article>`
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function renderCoverageItem(item: NarrativeMap["workbench"]["artifactCoverage"][number], display: ValidatedNarrativeDisplayModel): string {
|
|
297
|
+
const title = item.outputPath ?? item.artifactId
|
|
298
|
+
const slides = item.affectedSlides.map((slide) => `${localizeSlideRef(`slide ${slide.slideIndex}`, display)}: ${slide.slideTitle} (${slide.claimId}, ${slide.role}/${slide.location})`).join("<br>")
|
|
299
|
+
return `<article class="coverage-item">
|
|
300
|
+
<h3>${escapeHtml(title)}</h3>
|
|
301
|
+
<div class="coverage-meta"><span class="pill ${escapeAttr(item.coverageStatus)}">${escapeHtml(localizeValue(item.coverageStatus, display))}</span><span class="tag">${escapeHtml(item.type)}</span>${item.contractStatus ? `<span class="tag">${escapeHtml(item.contractStatus)}</span>` : ""}</div>
|
|
302
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("missingClaims", display))}:</strong> ${escapeHtml(item.missingClaimIds.join(", ") || systemTerm("none", display))}</p>
|
|
303
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("affectedClaims", display))}:</strong> ${escapeHtml(item.affectedClaimIds.join(", ") || systemTerm("none", display))}</p>
|
|
304
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("affectedSlides", display))}:</strong> ${slides ? allowBreaks(slides) : escapeHtml(systemTerm("none", display))}</p>
|
|
305
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("notes", display))}:</strong> ${escapeHtml([item.statusNote, ...item.staleReasons].filter(Boolean).join("; ") || systemTerm("none", display))}</p>
|
|
306
|
+
<p class="coverage-detail"><strong>${escapeHtml(systemTerm("recommendedNextCommand", display))}:</strong> <code>${escapeHtml(item.recommendedNextCommand)}</code></p>
|
|
307
|
+
</article>`
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function renderNextActions(claim: NarrativeMapClaim, display: ValidatedNarrativeDisplayModel): string {
|
|
311
|
+
return `<span class="next-actions">${claim.nextActions.map((action) => `<span class="next-action"><strong>${escapeHtml(localizeAction(action.label, display))}</strong>${escapeHtml(action.reason)}<br><code>${escapeHtml(action.command)}</code></span>`).join("")}</span>`
|
|
312
|
+
}
|
|
313
|
+
|
|
219
314
|
function relationText(relation: NarrativeMapClaimRelation, display: ValidatedNarrativeDisplayModel): string {
|
|
220
315
|
const from = displayClaimText(relation.fromClaimId, relation.fromClaimText, display)
|
|
221
316
|
const to = displayClaimText(relation.toClaimId, relation.toClaimText, display)
|
|
@@ -259,8 +354,8 @@ function missingRationale(display: ValidatedNarrativeDisplayModel): string {
|
|
|
259
354
|
return "Causal rationale is not recorded."
|
|
260
355
|
}
|
|
261
356
|
|
|
262
|
-
function detailCards(rows: Array<[string, string]>): string {
|
|
263
|
-
return rows.map(([label, value]) => `<div class="detail-card"><h3>${escapeHtml(label)}</h3><p>${allowBreaks(value)}</p></div>`).join("")
|
|
357
|
+
function detailCards(rows: Array<[string, string] | [string, string, boolean]>): string {
|
|
358
|
+
return rows.map(([label, value, raw]) => `<div class="detail-card"><h3>${escapeHtml(label)}</h3><p>${raw ? value : allowBreaks(value)}</p></div>`).join("")
|
|
264
359
|
}
|
|
265
360
|
|
|
266
361
|
function emptyCard(label: string, value: string): string {
|
|
@@ -292,14 +387,46 @@ function sectionLabels(display: ValidatedNarrativeDisplayModel): Record<string,
|
|
|
292
387
|
return { role: "Role", narrativeJob: "Narrative job", evidenceSummary: "Evidence summary", riskOrGapSummary: "Risk / gap" }
|
|
293
388
|
}
|
|
294
389
|
|
|
390
|
+
function workbenchNote(display: ValidatedNarrativeDisplayModel): string {
|
|
391
|
+
return display.labels.workbenchNote
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function localizeFilter(value: string, display: ValidatedNarrativeDisplayModel): string {
|
|
395
|
+
const zh: Record<string, string> = { "All claims": "全部主张", "Missing evidence": "证据缺失", "Partial evidence": "部分证据", "Stale artifacts": "过期产物", "Open gaps": "开放缺口", Risks: "风险", "High-priority objections": "高优先级异议" }
|
|
396
|
+
const ja: Record<string, string> = { "All claims": "すべてのクレーム", "Missing evidence": "根拠不足", "Partial evidence": "一部根拠", "Stale artifacts": "古い成果物", "Open gaps": "未解決ギャップ", Risks: "リスク", "High-priority objections": "高優先度の反論" }
|
|
397
|
+
const table = isChineseLanguage(display.language) ? zh : isJapaneseLanguage(display.language) ? ja : {}
|
|
398
|
+
return table[value] ?? value
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function localizeAction(value: string, display: ValidatedNarrativeDisplayModel): string {
|
|
402
|
+
const zh: Record<string, string> = { "Research this gap": "研究这个缺口", "Attach findings": "附加研究发现", "Narrow claim": "收窄主张", "Approve narrative": "批准叙事", "Make deck": "制作 deck", "Remake stale artifact": "重新生成过期产物" }
|
|
403
|
+
const ja: Record<string, string> = { "Research this gap": "このギャップを調査", "Attach findings": "調査結果を紐付け", "Narrow claim": "クレームを絞る", "Approve narrative": "ナラティブを承認", "Make deck": "デッキを作成", "Remake stale artifact": "古い成果物を再生成" }
|
|
404
|
+
const table = isChineseLanguage(display.language) ? zh : isJapaneseLanguage(display.language) ? ja : {}
|
|
405
|
+
return table[value] ?? value
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function readinessSummaryTerm(value: string, display: ValidatedNarrativeDisplayModel): string {
|
|
409
|
+
const zh: Record<string, string> = { evidenceBlockers: "证据阻塞", artifactStatus: "产物状态", primaryNextCommand: "首要建议命令", primaryNextReason: "首要建议原因" }
|
|
410
|
+
const ja: Record<string, string> = { evidenceBlockers: "根拠ブロッカー", artifactStatus: "成果物ステータス", primaryNextCommand: "最優先コマンド", primaryNextReason: "最優先理由" }
|
|
411
|
+
const en: Record<string, string> = { evidenceBlockers: "Evidence blockers", artifactStatus: "Artifact status", primaryNextCommand: "Primary next command", primaryNextReason: "Primary next reason" }
|
|
412
|
+
return (isChineseLanguage(display.language) ? zh : isJapaneseLanguage(display.language) ? ja : en)[value] ?? value
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function noClaimsMatchFilter(display: ValidatedNarrativeDisplayModel): string {
|
|
416
|
+
if (isChineseLanguage(display.language)) return "没有主张匹配这个过滤器。"
|
|
417
|
+
if (isJapaneseLanguage(display.language)) return "このフィルターに一致するクレームはありません。"
|
|
418
|
+
return "No claims match this filter."
|
|
419
|
+
}
|
|
420
|
+
|
|
295
421
|
function systemTerm(term: string, display: ValidatedNarrativeDisplayModel): string {
|
|
296
|
-
const zh: Record<string, string> = { approval: "审批", claims: "主张", relations: "关系", inferred: "未确认", relation: "关系", from: "来自", to: "指向", rationale: "说明", strength: "强度", findingsFile: "研究文件", location: "位置", quote: "引用", caveat: "注意事项", artifacts: "产物", attention: "需关注", artifactCoverage:
|
|
297
|
-
const ja: Record<string, string> = { approval: "承認", claims: "クレーム", relations: "関係", inferred: "未確認", relation: "関係", from: "起点", to: "終点", rationale: "理由", strength: "強度", findingsFile: "調査ファイル", location: "場所", quote: "引用", caveat: "留意点", artifacts: "成果物", attention: "要確認", artifactCoverage:
|
|
298
|
-
const en: Record<string, string> = { approval: "approval", claims: "claims", relations: "relations", inferred: "unconfirmed", relation: "relation", from: "from", to: "to", rationale: "rationale", strength: "strength", findingsFile: "findings file", location: "location", quote: "quote", caveat: "caveat", artifacts: "artifacts", attention: "need attention", artifactCoverage:
|
|
422
|
+
const zh: Record<string, string> = { approval: "审批", claims: "主张", relations: "关系", inferred: "未确认", relation: "关系", from: "来自", to: "指向", rationale: "说明", strength: "强度", findingsFile: "研究文件", location: "位置", quote: "引用", caveat: "注意事项", artifacts: "产物", attention: "需关注", artifactCoverage: display.labels.artifactCoverage, storyWorkbench: display.labels.storyWorkbench, noRenderTargets: display.labels.noRenderTargets, nextActions: display.labels.nextActions, missingClaims: display.labels.missingClaims, affectedClaims: display.labels.affectedClaims, affectedSlides: display.labels.affectedSlides, notes: display.labels.notes, recommendedNextCommand: display.labels.recommendedNextCommand, none: display.labels.none }
|
|
423
|
+
const ja: Record<string, string> = { approval: "承認", claims: "クレーム", relations: "関係", inferred: "未確認", relation: "関係", from: "起点", to: "終点", rationale: "理由", strength: "強度", findingsFile: "調査ファイル", location: "場所", quote: "引用", caveat: "留意点", artifacts: "成果物", attention: "要確認", artifactCoverage: display.labels.artifactCoverage, storyWorkbench: display.labels.storyWorkbench, noRenderTargets: display.labels.noRenderTargets, nextActions: display.labels.nextActions, missingClaims: display.labels.missingClaims, affectedClaims: display.labels.affectedClaims, affectedSlides: display.labels.affectedSlides, notes: display.labels.notes, recommendedNextCommand: display.labels.recommendedNextCommand, none: display.labels.none }
|
|
424
|
+
const en: Record<string, string> = { approval: "approval", claims: "claims", relations: "relations", inferred: "unconfirmed", relation: "relation", from: "from", to: "to", rationale: "rationale", strength: "strength", findingsFile: "findings file", location: "location", quote: "quote", caveat: "caveat", artifacts: "artifacts", attention: "need attention", artifactCoverage: display.labels.artifactCoverage, storyWorkbench: display.labels.storyWorkbench, noRenderTargets: display.labels.noRenderTargets, nextActions: display.labels.nextActions, missingClaims: display.labels.missingClaims, affectedClaims: display.labels.affectedClaims, affectedSlides: display.labels.affectedSlides, notes: display.labels.notes, recommendedNextCommand: display.labels.recommendedNextCommand, none: display.labels.none }
|
|
299
425
|
return (isChineseLanguage(display.language) ? zh : isJapaneseLanguage(display.language) ? ja : en)[term] ?? term
|
|
300
426
|
}
|
|
301
427
|
|
|
302
428
|
function localizeValue(value: string, display: ValidatedNarrativeDisplayModel): string {
|
|
429
|
+
if (value === "no_target") return isChineseLanguage(display.language) ? "无 render target" : isJapaneseLanguage(display.language) ? "render target なし" : "no target"
|
|
303
430
|
const zh: Record<string, string> = {
|
|
304
431
|
current: "当前", stale: "已过期", missing: "缺失", approved: "已批准", ready_for_approval: "待批准", needs_research: "需要研究", needs_user_confirmation: "需要用户确认", blocked: "受阻", draft: "草稿",
|
|
305
432
|
supported: "已支持", partial: "部分支持", weak: "弱支持", not_required: "无需证据", central: "核心", supporting: "支撑", background: "背景",
|