@trohde/earos 1.1.2 → 1.3.0
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/assets/init/docs/getting-started.md +1 -1
- package/assets/init/docs/onboarding/agent-assisted.md +19 -19
- package/assets/init/docs/onboarding/first-assessment.md +18 -18
- package/assets/init/docs/onboarding/governed-review.md +10 -10
- package/assets/init/docs/onboarding/overview.md +15 -15
- package/assets/init/docs/onboarding/scaling-optimization.md +13 -13
- package/assets/init/docs/plans/2026-03-23-001-refactor-site-review-findings-plan.md +195 -0
- package/assets/init/docs/plans/2026-03-23-002-refactor-cli-review-findings-plan.md +736 -0
- package/assets/init/docs/profile-authoring-guide.md +5 -9
- package/assets/init/docs/terminology.md +1 -1
- package/bin.js +156 -36
- package/dist/assets/{_basePickBy-PmSUrUsK.js → _basePickBy-BlC_TeV6.js} +1 -1
- package/dist/assets/{_baseUniq-HuZouVIz.js → _baseUniq-CVy7rcC1.js} +1 -1
- package/dist/assets/{arc-CJFxtF3d.js → arc-Cd8wvd7z.js} +1 -1
- package/dist/assets/{architectureDiagram-2XIMDMQ5-XA-oU2UG.js → architectureDiagram-2XIMDMQ5-D_f4_aMp.js} +1 -1
- package/dist/assets/{blockDiagram-WCTKOSBZ-Oxp-wAST.js → blockDiagram-WCTKOSBZ-B-y6N5--.js} +1 -1
- package/dist/assets/{c4Diagram-IC4MRINW-D8m5hQH9.js → c4Diagram-IC4MRINW-C3-v3oNT.js} +1 -1
- package/dist/assets/channel-BSC0F15G.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-D2kBTn2O.js → chunk-4BX2VUAB-CMPwQN83.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-Dxqrf5oZ.js → chunk-55IACEB6-Bdkfhvrr.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-DoOEFFQC.js → chunk-FMBD7UC4-ptKQX5uF.js} +1 -1
- package/dist/assets/{chunk-JSJVCQXG-BerphV2K.js → chunk-JSJVCQXG-DO0UU_OX.js} +1 -1
- package/dist/assets/{chunk-KX2RTZJC-CxUAqT05.js → chunk-KX2RTZJC-DRj2OZnD.js} +1 -1
- package/dist/assets/{chunk-NQ4KR5QH-fCqZgFkU.js → chunk-NQ4KR5QH-C4Nsf7ww.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-HlpHnJEy.js → chunk-QZHKN3VN-B1GO0Nwy.js} +1 -1
- package/dist/assets/{chunk-WL4C6EOR-D9yxAHyd.js → chunk-WL4C6EOR-lFR6fjR8.js} +1 -1
- package/dist/assets/classDiagram-VBA2DB6C-BHDWMOEz.js +1 -0
- package/dist/assets/classDiagram-v2-RAHNMMFH-BHDWMOEz.js +1 -0
- package/dist/assets/clone-BdN-3iAD.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-F5xOBvqW.js → cose-bilkent-S5V4N54A-IpR9mVIO.js} +1 -1
- package/dist/assets/{dagre-KLK3FWXG-CD3BTpHv.js → dagre-KLK3FWXG-B4YA6T7N.js} +1 -1
- package/dist/assets/{diagram-E7M64L7V-C3D9MCay.js → diagram-E7M64L7V-Do5l6es_.js} +1 -1
- package/dist/assets/{diagram-IFDJBPK2-zJBVM-GK.js → diagram-IFDJBPK2-D5MxfKVv.js} +1 -1
- package/dist/assets/{diagram-P4PSJMXO-BrmFZOLB.js → diagram-P4PSJMXO-Djr28EgW.js} +1 -1
- package/dist/assets/{erDiagram-INFDFZHY-aSMhKiV2.js → erDiagram-INFDFZHY-BuM-rbCL.js} +1 -1
- package/dist/assets/{flowDiagram-PKNHOUZH-DwgX7l8F.js → flowDiagram-PKNHOUZH-By3WGI7Q.js} +1 -1
- package/dist/assets/{ganttDiagram-A5KZAMGK-C57Hz6QW.js → ganttDiagram-A5KZAMGK-GLmBfK72.js} +1 -1
- package/dist/assets/{gitGraphDiagram-K3NZZRJ6-CuchqqGh.js → gitGraphDiagram-K3NZZRJ6-BN0iXeIv.js} +1 -1
- package/dist/assets/{graph-CPFGBV5J.js → graph-CDzuMtjV.js} +1 -1
- package/dist/assets/{index-DMt1cpG6.js → index-DoeSN_Oe.js} +130 -130
- package/dist/assets/{infoDiagram-LFFYTUFH-Dd_5tfX7.js → infoDiagram-LFFYTUFH-C888gaFw.js} +1 -1
- package/dist/assets/{ishikawaDiagram-PHBUUO56-DwosSEvT.js → ishikawaDiagram-PHBUUO56-ChIO9DG-.js} +1 -1
- package/dist/assets/{journeyDiagram-4ABVD52K-BuCxcsX0.js → journeyDiagram-4ABVD52K-CufMUDcs.js} +1 -1
- package/dist/assets/{kanban-definition-K7BYSVSG-DF_1UCkW.js → kanban-definition-K7BYSVSG-BpsSVpX8.js} +1 -1
- package/dist/assets/{layout-DIcS6m1g.js → layout-B8RWVBSF.js} +1 -1
- package/dist/assets/{linear-BXkwBhoJ.js → linear-BJwxtq9r.js} +1 -1
- package/dist/assets/{mindmap-definition-YRQLILUH-DcDvYagd.js → mindmap-definition-YRQLILUH-C6WPimbf.js} +1 -1
- package/dist/assets/{pieDiagram-SKSYHLDU-BmeDeWDM.js → pieDiagram-SKSYHLDU-DeCGMWf8.js} +1 -1
- package/dist/assets/{quadrantDiagram-337W2JSQ-3zfjULUM.js → quadrantDiagram-337W2JSQ-D9TWaS83.js} +1 -1
- package/dist/assets/{requirementDiagram-Z7DCOOCP-B2wQMJpq.js → requirementDiagram-Z7DCOOCP-DTnuXlAq.js} +1 -1
- package/dist/assets/{sankeyDiagram-WA2Y5GQK-__kKlCTq.js → sankeyDiagram-WA2Y5GQK-B2dplCgD.js} +1 -1
- package/dist/assets/{sequenceDiagram-2WXFIKYE-B7O81Vih.js → sequenceDiagram-2WXFIKYE-cBvgSSju.js} +1 -1
- package/dist/assets/{stateDiagram-RAJIS63D-CcJaDrAK.js → stateDiagram-RAJIS63D-Cwr7VtSX.js} +1 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-B59h7VTZ.js +1 -0
- package/dist/assets/{timeline-definition-YZTLITO2-DSaQQqIU.js → timeline-definition-YZTLITO2-Dkp163fK.js} +1 -1
- package/dist/assets/{treemap-KZPCXAKY-9Hcrd8XD.js → treemap-KZPCXAKY-BUWHa5xU.js} +1 -1
- package/dist/assets/{vennDiagram-LZ73GAT5-BqHNyca2.js → vennDiagram-LZ73GAT5-BihD66ma.js} +1 -1
- package/dist/assets/{xychartDiagram-JWTSCODW-BqeYf6Fk.js → xychartDiagram-JWTSCODW-Cw4lPbuZ.js} +1 -1
- package/dist/index.html +1 -1
- package/export-docx.js +12 -4
- package/init.js +19 -14
- package/manifest-cli.mjs +32 -3
- package/package.json +3 -2
- package/serve.js +44 -19
- package/utils/export-markdown.js +486 -0
- package/dist/assets/channel-SoktpVBQ.js +0 -1
- package/dist/assets/classDiagram-VBA2DB6C-BT2AdZTe.js +0 -1
- package/dist/assets/classDiagram-v2-RAHNMMFH-BT2AdZTe.js +0 -1
- package/dist/assets/clone-DOjIfi5r.js +0 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-B2goOPt-.js +0 -1
|
@@ -0,0 +1,486 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EaROS — Markdown export utilities for artifacts, rubrics, and evaluations.
|
|
3
|
+
*
|
|
4
|
+
* Pure client-side functions that convert structured data objects to Markdown strings.
|
|
5
|
+
*/
|
|
6
|
+
// ─── Shared helpers ──────────────────────────────────────────────────────────
|
|
7
|
+
function humanize(key) {
|
|
8
|
+
return key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase());
|
|
9
|
+
}
|
|
10
|
+
function str(v) {
|
|
11
|
+
if (v == null)
|
|
12
|
+
return '';
|
|
13
|
+
if (typeof v === 'string')
|
|
14
|
+
return v.trim();
|
|
15
|
+
if (typeof v === 'number' || typeof v === 'boolean')
|
|
16
|
+
return String(v);
|
|
17
|
+
return '';
|
|
18
|
+
}
|
|
19
|
+
function mdTable(headers, rows) {
|
|
20
|
+
if (rows.length === 0)
|
|
21
|
+
return '';
|
|
22
|
+
const sep = headers.map(() => '---');
|
|
23
|
+
const lines = [
|
|
24
|
+
`| ${headers.join(' | ')} |`,
|
|
25
|
+
`| ${sep.join(' | ')} |`,
|
|
26
|
+
...rows.map((r) => `| ${r.map((c) => c.replace(/\|/g, '\\|').replace(/\n/g, ' ')).join(' | ')} |`),
|
|
27
|
+
];
|
|
28
|
+
return lines.join('\n');
|
|
29
|
+
}
|
|
30
|
+
function mdList(items) {
|
|
31
|
+
return items.map((i) => `- ${i}`).join('\n');
|
|
32
|
+
}
|
|
33
|
+
function isPlainObject(v) {
|
|
34
|
+
return !!v && typeof v === 'object' && !Array.isArray(v);
|
|
35
|
+
}
|
|
36
|
+
export function downloadAsFile(content, filename, mimeType) {
|
|
37
|
+
if (typeof document === 'undefined')
|
|
38
|
+
return; // Node.js — no browser download
|
|
39
|
+
const blob = new Blob([content], { type: mimeType });
|
|
40
|
+
const url = URL.createObjectURL(blob);
|
|
41
|
+
const a = document.createElement('a');
|
|
42
|
+
a.href = url;
|
|
43
|
+
a.download = filename;
|
|
44
|
+
a.click();
|
|
45
|
+
URL.revokeObjectURL(url);
|
|
46
|
+
}
|
|
47
|
+
// ─── Artifact Markdown ───────────────────────────────────────────────────────
|
|
48
|
+
const SECTION_ORDER = [
|
|
49
|
+
'reading_guide',
|
|
50
|
+
'scope',
|
|
51
|
+
'drivers_and_principles',
|
|
52
|
+
'architecture_views',
|
|
53
|
+
'crosscutting_concerns',
|
|
54
|
+
'component_classification',
|
|
55
|
+
'components',
|
|
56
|
+
'decisions',
|
|
57
|
+
'architecture_decisions',
|
|
58
|
+
'quality_attributes',
|
|
59
|
+
'operational_model',
|
|
60
|
+
'implementation_guidance',
|
|
61
|
+
'implementation_artifacts',
|
|
62
|
+
'governance',
|
|
63
|
+
'raid',
|
|
64
|
+
'decisions_and_actions',
|
|
65
|
+
'getting_started',
|
|
66
|
+
'evolution',
|
|
67
|
+
'glossary',
|
|
68
|
+
];
|
|
69
|
+
function renderMetadataMd(meta) {
|
|
70
|
+
const lines = [];
|
|
71
|
+
const skip = new Set(['title', 'artifact_type']);
|
|
72
|
+
for (const [key, value] of Object.entries(meta)) {
|
|
73
|
+
if (skip.has(key))
|
|
74
|
+
continue;
|
|
75
|
+
if (value == null)
|
|
76
|
+
continue;
|
|
77
|
+
if (Array.isArray(value)) {
|
|
78
|
+
if (value.length === 0)
|
|
79
|
+
continue;
|
|
80
|
+
if (isPlainObject(value[0])) {
|
|
81
|
+
lines.push(`\n**${humanize(key)}:**\n`);
|
|
82
|
+
const keys = Object.keys(value[0]);
|
|
83
|
+
lines.push(mdTable(keys.map(humanize), value.map((item) => keys.map((k) => str(item[k])))));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
lines.push(`**${humanize(key)}:** ${value.map(str).join(', ')}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
else if (isPlainObject(value)) {
|
|
90
|
+
lines.push(`**${humanize(key)}:**`);
|
|
91
|
+
for (const [k, v] of Object.entries(value)) {
|
|
92
|
+
lines.push(`- ${humanize(k)}: ${str(v)}`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
lines.push(`**${humanize(key)}:** ${str(value)}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return lines.join('\n');
|
|
100
|
+
}
|
|
101
|
+
function renderValueMd(value, level) {
|
|
102
|
+
const lines = [];
|
|
103
|
+
const hl = '#'.repeat(Math.min(level, 6));
|
|
104
|
+
if (typeof value === 'string') {
|
|
105
|
+
// Check for Mermaid diagram source
|
|
106
|
+
if (value.trim().startsWith('graph ') || value.trim().startsWith('flowchart ') ||
|
|
107
|
+
value.trim().startsWith('sequenceDiagram') || value.trim().startsWith('classDiagram') ||
|
|
108
|
+
value.trim().startsWith('stateDiagram') || value.trim().startsWith('erDiagram') ||
|
|
109
|
+
value.trim().startsWith('gantt') || value.trim().startsWith('pie') ||
|
|
110
|
+
value.trim().startsWith('journey') || value.trim().startsWith('C4') ||
|
|
111
|
+
value.trim().startsWith('mindmap') || value.trim().startsWith('timeline') ||
|
|
112
|
+
value.trim().startsWith('block-beta') || value.trim().startsWith('architecture-beta')) {
|
|
113
|
+
lines.push('```mermaid', value.trim(), '```');
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
lines.push(value);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else if (Array.isArray(value)) {
|
|
120
|
+
if (value.length === 0)
|
|
121
|
+
return '';
|
|
122
|
+
if (typeof value[0] === 'string') {
|
|
123
|
+
lines.push(mdList(value.map(str)));
|
|
124
|
+
}
|
|
125
|
+
else if (isPlainObject(value[0])) {
|
|
126
|
+
const keys = Object.keys(value[0]);
|
|
127
|
+
lines.push(mdTable(keys.map(humanize), value.map((item) => keys.map((k) => str(item[k])))));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else if (isPlainObject(value)) {
|
|
131
|
+
for (const [key, child] of Object.entries(value)) {
|
|
132
|
+
if (child == null)
|
|
133
|
+
continue;
|
|
134
|
+
if (key === 'diagram_source' || key === 'mermaid_source') {
|
|
135
|
+
lines.push('```mermaid', str(child), '```');
|
|
136
|
+
}
|
|
137
|
+
else if (typeof child === 'string') {
|
|
138
|
+
lines.push(`**${humanize(key)}:** ${child}`);
|
|
139
|
+
}
|
|
140
|
+
else if (Array.isArray(child)) {
|
|
141
|
+
if (child.length === 0)
|
|
142
|
+
continue;
|
|
143
|
+
lines.push(`\n${hl}# ${humanize(key)}\n`);
|
|
144
|
+
lines.push(renderValueMd(child, level + 1));
|
|
145
|
+
}
|
|
146
|
+
else if (isPlainObject(child)) {
|
|
147
|
+
lines.push(`\n${hl}# ${humanize(key)}\n`);
|
|
148
|
+
lines.push(renderValueMd(child, level + 1));
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return lines.join('\n');
|
|
153
|
+
}
|
|
154
|
+
function renderSectionMd(key, value) {
|
|
155
|
+
const lines = [];
|
|
156
|
+
lines.push(`## ${humanize(key)}`);
|
|
157
|
+
lines.push('');
|
|
158
|
+
lines.push(renderValueMd(value, 3));
|
|
159
|
+
lines.push('');
|
|
160
|
+
return lines.join('\n');
|
|
161
|
+
}
|
|
162
|
+
export function exportArtifactToMarkdown(data) {
|
|
163
|
+
const lines = [];
|
|
164
|
+
const meta = data?.metadata ?? {};
|
|
165
|
+
const sections = data?.sections ?? {};
|
|
166
|
+
// Title
|
|
167
|
+
const title = str(meta.title) || 'Architecture Artifact';
|
|
168
|
+
const artifactType = str(data?.artifact_type ?? meta?.artifact_type ?? '');
|
|
169
|
+
lines.push(`# ${title}`);
|
|
170
|
+
if (artifactType) {
|
|
171
|
+
lines.push(`\n*${humanize(artifactType)}*`);
|
|
172
|
+
}
|
|
173
|
+
lines.push('');
|
|
174
|
+
// Metadata
|
|
175
|
+
const metaMd = renderMetadataMd(meta);
|
|
176
|
+
if (metaMd) {
|
|
177
|
+
lines.push(metaMd);
|
|
178
|
+
lines.push('\n---\n');
|
|
179
|
+
}
|
|
180
|
+
// Sections in preferred order
|
|
181
|
+
const rendered = new Set();
|
|
182
|
+
for (const key of SECTION_ORDER) {
|
|
183
|
+
if (key in sections) {
|
|
184
|
+
lines.push(renderSectionMd(key, sections[key]));
|
|
185
|
+
rendered.add(key);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Unknown sections
|
|
189
|
+
for (const [key, value] of Object.entries(sections)) {
|
|
190
|
+
if (!rendered.has(key)) {
|
|
191
|
+
lines.push(renderSectionMd(key, value));
|
|
192
|
+
rendered.add(key);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Top-level keys outside sections
|
|
196
|
+
const TOP_SKIP = new Set(['kind', 'artifact_type', 'metadata', 'sections']);
|
|
197
|
+
for (const [key, value] of Object.entries(data)) {
|
|
198
|
+
if (TOP_SKIP.has(key) || rendered.has(key))
|
|
199
|
+
continue;
|
|
200
|
+
lines.push(renderSectionMd(key, value));
|
|
201
|
+
}
|
|
202
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trim() + '\n';
|
|
203
|
+
}
|
|
204
|
+
// ─── Rubric Markdown ─────────────────────────────────────────────────────────
|
|
205
|
+
export function exportRubricToMarkdown(data) {
|
|
206
|
+
const lines = [];
|
|
207
|
+
// Title & metadata
|
|
208
|
+
const title = str(data?.title) || 'EaROS Rubric';
|
|
209
|
+
lines.push(`# ${title}`);
|
|
210
|
+
lines.push('');
|
|
211
|
+
const metaFields = [
|
|
212
|
+
['Rubric ID', data?.rubric_id],
|
|
213
|
+
['Version', data?.version],
|
|
214
|
+
['Kind', data?.kind],
|
|
215
|
+
['Status', data?.status],
|
|
216
|
+
['Artifact Type', data?.artifact_type],
|
|
217
|
+
['Design Method', data?.design_method],
|
|
218
|
+
['Owner', data?.owner],
|
|
219
|
+
['Effective Date', data?.effective_date],
|
|
220
|
+
];
|
|
221
|
+
if (data?.inherits?.length)
|
|
222
|
+
metaFields.push(['Inherits', data.inherits.join(', ')]);
|
|
223
|
+
const validMeta = metaFields.filter(([, v]) => v != null && v !== '');
|
|
224
|
+
if (validMeta.length) {
|
|
225
|
+
lines.push(mdTable(['Field', 'Value'], validMeta.map(([k, v]) => [k, str(v)])));
|
|
226
|
+
lines.push('\n---\n');
|
|
227
|
+
}
|
|
228
|
+
// Dimensions & criteria
|
|
229
|
+
const dimensions = data?.dimensions ?? [];
|
|
230
|
+
for (const dim of dimensions) {
|
|
231
|
+
const weight = dim.weight != null ? ` (weight: ${dim.weight})` : '';
|
|
232
|
+
lines.push(`## ${str(dim.name)}${weight}`);
|
|
233
|
+
lines.push('');
|
|
234
|
+
if (dim.description)
|
|
235
|
+
lines.push(`*${str(dim.description)}*\n`);
|
|
236
|
+
const criteria = dim.criteria ?? [];
|
|
237
|
+
for (const c of criteria) {
|
|
238
|
+
lines.push(`### ${str(c.id)}: ${str(c.question)}`);
|
|
239
|
+
lines.push('');
|
|
240
|
+
if (c.description)
|
|
241
|
+
lines.push(str(c.description) + '\n');
|
|
242
|
+
// Gate
|
|
243
|
+
if (c.gate && typeof c.gate === 'object' && c.gate.enabled) {
|
|
244
|
+
lines.push(`**Gate:** ${c.gate.severity ?? 'unknown'}${c.gate.failure_effect ? ` — ${c.gate.failure_effect}` : ''}`);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
lines.push('**Gate:** None');
|
|
248
|
+
}
|
|
249
|
+
lines.push('');
|
|
250
|
+
// Required evidence
|
|
251
|
+
if (c.required_evidence?.length) {
|
|
252
|
+
lines.push('**Required Evidence:**\n');
|
|
253
|
+
lines.push(mdList(c.required_evidence.map(str)));
|
|
254
|
+
lines.push('');
|
|
255
|
+
}
|
|
256
|
+
// Scoring guide
|
|
257
|
+
if (c.scoring_guide) {
|
|
258
|
+
lines.push('**Scoring Guide:**\n');
|
|
259
|
+
const sgRows = Object.entries(c.scoring_guide).map(([level, desc]) => [level, str(desc)]);
|
|
260
|
+
lines.push(mdTable(['Level', 'Description'], sgRows));
|
|
261
|
+
lines.push('');
|
|
262
|
+
}
|
|
263
|
+
// Anti-patterns
|
|
264
|
+
if (c.anti_patterns?.length) {
|
|
265
|
+
lines.push('**Anti-patterns:**\n');
|
|
266
|
+
lines.push(mdList(c.anti_patterns.map(str)));
|
|
267
|
+
lines.push('');
|
|
268
|
+
}
|
|
269
|
+
// Examples
|
|
270
|
+
if (c.examples) {
|
|
271
|
+
if (c.examples.good?.length) {
|
|
272
|
+
lines.push('**Good Examples:**\n');
|
|
273
|
+
lines.push(mdList(c.examples.good.map(str)));
|
|
274
|
+
lines.push('');
|
|
275
|
+
}
|
|
276
|
+
if (c.examples.bad?.length) {
|
|
277
|
+
lines.push('**Bad Examples:**\n');
|
|
278
|
+
lines.push(mdList(c.examples.bad.map(str)));
|
|
279
|
+
lines.push('');
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
// Decision tree
|
|
283
|
+
if (c.decision_tree) {
|
|
284
|
+
lines.push('**Decision Tree:**\n');
|
|
285
|
+
lines.push(`> ${str(c.decision_tree).replace(/\n/g, '\n> ')}`);
|
|
286
|
+
lines.push('');
|
|
287
|
+
}
|
|
288
|
+
// Remediation hints
|
|
289
|
+
if (c.remediation_hints?.length) {
|
|
290
|
+
lines.push('**Remediation Hints:**\n');
|
|
291
|
+
lines.push(mdList(c.remediation_hints.map(str)));
|
|
292
|
+
lines.push('');
|
|
293
|
+
}
|
|
294
|
+
lines.push('---\n');
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// Scoring section
|
|
298
|
+
if (data?.scoring) {
|
|
299
|
+
lines.push('## Scoring Model\n');
|
|
300
|
+
if (data.scoring.scale)
|
|
301
|
+
lines.push(`**Scale:** ${str(data.scoring.scale)}`);
|
|
302
|
+
if (data.scoring.method)
|
|
303
|
+
lines.push(`**Method:** ${str(data.scoring.method)}`);
|
|
304
|
+
if (data.scoring.thresholds) {
|
|
305
|
+
lines.push('\n**Thresholds:**\n');
|
|
306
|
+
for (const [k, v] of Object.entries(data.scoring.thresholds)) {
|
|
307
|
+
lines.push(`- **${humanize(k)}:** ${str(v)}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
lines.push('');
|
|
311
|
+
}
|
|
312
|
+
// Outputs section
|
|
313
|
+
if (data?.outputs) {
|
|
314
|
+
lines.push('## Outputs\n');
|
|
315
|
+
for (const [k, v] of Object.entries(data.outputs)) {
|
|
316
|
+
lines.push(`- **${humanize(k)}:** ${str(v)}`);
|
|
317
|
+
}
|
|
318
|
+
lines.push('');
|
|
319
|
+
}
|
|
320
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trim() + '\n';
|
|
321
|
+
}
|
|
322
|
+
function scoreEmoji(score) {
|
|
323
|
+
if (score === null || score === 'N/A')
|
|
324
|
+
return '';
|
|
325
|
+
if (score >= 3)
|
|
326
|
+
return '🟢';
|
|
327
|
+
if (score >= 2)
|
|
328
|
+
return '🟡';
|
|
329
|
+
if (score >= 1)
|
|
330
|
+
return '🟠';
|
|
331
|
+
return '🔴';
|
|
332
|
+
}
|
|
333
|
+
function statusLabel(status) {
|
|
334
|
+
const map = {
|
|
335
|
+
pass: 'Pass',
|
|
336
|
+
conditional_pass: 'Conditional Pass',
|
|
337
|
+
rework_required: 'Rework Required',
|
|
338
|
+
reject: 'Reject',
|
|
339
|
+
not_reviewable: 'Not Reviewable',
|
|
340
|
+
incomplete: 'Incomplete',
|
|
341
|
+
};
|
|
342
|
+
return map[status] ?? humanize(status);
|
|
343
|
+
}
|
|
344
|
+
export function exportEvaluationToMarkdown(meta, primaryRubricId, dimensions, results) {
|
|
345
|
+
const lines = [];
|
|
346
|
+
// Compute summary inline (same logic as computeSummary in AssessmentSummary)
|
|
347
|
+
const dimSummaries = dimensions.map((dim) => {
|
|
348
|
+
const scored = dim.criteria.filter((c) => {
|
|
349
|
+
const r = results[c.id];
|
|
350
|
+
return r && r.score !== null && r.score !== 'N/A';
|
|
351
|
+
});
|
|
352
|
+
const sum = scored.reduce((acc, c) => acc + results[c.id].score, 0);
|
|
353
|
+
const avg = scored.length > 0 ? sum / scored.length : null;
|
|
354
|
+
return { id: dim.id, name: dim.name, weight: dim.weight ?? 1.0, avgScore: avg };
|
|
355
|
+
});
|
|
356
|
+
const gateFailures = [];
|
|
357
|
+
for (const dim of dimensions) {
|
|
358
|
+
for (const c of dim.criteria) {
|
|
359
|
+
if (!c.gate || typeof c.gate !== 'object' || !c.gate.enabled)
|
|
360
|
+
continue;
|
|
361
|
+
const sev = c.gate.severity;
|
|
362
|
+
if (!sev || sev === 'none')
|
|
363
|
+
continue;
|
|
364
|
+
const r = results[c.id];
|
|
365
|
+
if (!r || r.score === null || r.score === 'N/A')
|
|
366
|
+
continue;
|
|
367
|
+
if (r.score < 2) {
|
|
368
|
+
gateFailures.push({ id: c.id, question: c.question, severity: sev, score: r.score, failure_effect: c.gate.failure_effect ?? '' });
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const criticalFailures = gateFailures.filter((g) => g.severity === 'critical');
|
|
373
|
+
const majorFailures = gateFailures.filter((g) => g.severity === 'major');
|
|
374
|
+
const scoredDims = dimSummaries.filter((d) => d.avgScore !== null);
|
|
375
|
+
const weightedSum = scoredDims.reduce((acc, d) => acc + d.avgScore * d.weight, 0);
|
|
376
|
+
const totalWeight = scoredDims.reduce((acc, d) => acc + d.weight, 0);
|
|
377
|
+
const overallScore = scoredDims.length > 0 ? weightedSum / totalWeight : null;
|
|
378
|
+
const totalCriteria = dimensions.reduce((acc, d) => acc + d.criteria.length, 0);
|
|
379
|
+
const scoredCriteria = dimensions.reduce((acc, d) => acc + d.criteria.filter((c) => results[c.id]?.score !== null).length, 0);
|
|
380
|
+
let status = 'incomplete';
|
|
381
|
+
if (overallScore !== null) {
|
|
382
|
+
const noLowDim = dimSummaries.every((d) => d.avgScore === null || d.avgScore >= 2.0);
|
|
383
|
+
if (criticalFailures.length > 0) {
|
|
384
|
+
const hasNotReviewable = criticalFailures.some((g) => {
|
|
385
|
+
const effect = g.failure_effect.toLowerCase();
|
|
386
|
+
return effect.includes('not_reviewable') || effect.includes('not reviewable');
|
|
387
|
+
});
|
|
388
|
+
status = hasNotReviewable ? 'not_reviewable' : 'reject';
|
|
389
|
+
}
|
|
390
|
+
else if (overallScore >= 3.2 && noLowDim && majorFailures.length === 0) {
|
|
391
|
+
status = 'pass';
|
|
392
|
+
}
|
|
393
|
+
else if (overallScore >= 2.4 || majorFailures.length > 0) {
|
|
394
|
+
status = 'conditional_pass';
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
status = 'rework_required';
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Title
|
|
401
|
+
lines.push('# EaROS Architecture Assessment Report');
|
|
402
|
+
lines.push('');
|
|
403
|
+
if (meta.title)
|
|
404
|
+
lines.push(`**Artifact:** ${meta.title}`);
|
|
405
|
+
if (meta.version)
|
|
406
|
+
lines.push(`**Artifact Version:** ${meta.version}`);
|
|
407
|
+
lines.push(`**Rubric:** ${primaryRubricId}`);
|
|
408
|
+
lines.push(`**Evaluation Date:** ${meta.date || new Date().toISOString().slice(0, 10)}`);
|
|
409
|
+
if (meta.author)
|
|
410
|
+
lines.push(`**Evaluator:** ${meta.author}`);
|
|
411
|
+
lines.push('');
|
|
412
|
+
lines.push('---\n');
|
|
413
|
+
// Executive Summary
|
|
414
|
+
lines.push('## Executive Summary\n');
|
|
415
|
+
lines.push(mdTable(['', ''], [
|
|
416
|
+
['**Overall Status**', `**${statusLabel(status).toUpperCase()}**`],
|
|
417
|
+
['**Overall Score**', overallScore !== null ? `**${overallScore.toFixed(2)} / 4.0**` : 'N/A'],
|
|
418
|
+
['**Pass Threshold**', '3.2 / 4.0'],
|
|
419
|
+
['**Gate Failures**', gateFailures.length > 0 ? `${gateFailures.length} (${criticalFailures.length} critical)` : 'None'],
|
|
420
|
+
['**Criteria Scored**', `${scoredCriteria} of ${totalCriteria}`],
|
|
421
|
+
]));
|
|
422
|
+
lines.push('\n---\n');
|
|
423
|
+
// Traffic-Light Dashboard
|
|
424
|
+
lines.push('## Traffic-Light Dashboard\n');
|
|
425
|
+
const dashRows = [];
|
|
426
|
+
for (const dim of dimensions) {
|
|
427
|
+
for (const c of dim.criteria) {
|
|
428
|
+
const r = results[c.id];
|
|
429
|
+
const score = r?.score;
|
|
430
|
+
const scoreStr = score !== null && score !== undefined ? `${score}` : '-';
|
|
431
|
+
const gateLabel = c.gate && typeof c.gate === 'object' && c.gate.enabled
|
|
432
|
+
? ` ⚠️ ${(c.gate.severity ?? '').toUpperCase()} GATE` : '';
|
|
433
|
+
dashRows.push([
|
|
434
|
+
str(c.id) + gateLabel,
|
|
435
|
+
str(c.question),
|
|
436
|
+
scoreStr === 'N/A' ? 'N/A' : `${scoreStr} / 4`,
|
|
437
|
+
score !== null && score !== 'N/A' ? scoreEmoji(score) : '',
|
|
438
|
+
]);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
lines.push(mdTable(['Criterion', 'Name', 'Score', 'Status'], dashRows));
|
|
442
|
+
lines.push('\n**Legend:** 🟢 Score ≥ 3 · 🟡 Score 2–2.9 · 🟠 Score 1–1.9 · 🔴 Score 0 or gate failure\n');
|
|
443
|
+
lines.push('---\n');
|
|
444
|
+
// Dimension Summary
|
|
445
|
+
lines.push('## Dimension Summary\n');
|
|
446
|
+
const dimRows = dimSummaries.map((d) => [
|
|
447
|
+
d.id,
|
|
448
|
+
d.name,
|
|
449
|
+
d.weight.toFixed(1),
|
|
450
|
+
d.avgScore !== null ? d.avgScore.toFixed(1) : '-',
|
|
451
|
+
d.avgScore !== null ? (d.avgScore * d.weight).toFixed(1) : '-',
|
|
452
|
+
]);
|
|
453
|
+
lines.push(mdTable(['Dimension', 'Name', 'Weight', 'Score', 'Weighted'], dimRows));
|
|
454
|
+
if (overallScore !== null) {
|
|
455
|
+
lines.push(`\n**Overall weighted score: ${overallScore.toFixed(2)} / 4.0**`);
|
|
456
|
+
}
|
|
457
|
+
lines.push('\n---\n');
|
|
458
|
+
// Gate Failures
|
|
459
|
+
if (gateFailures.length > 0) {
|
|
460
|
+
lines.push('## Gate Failures\n');
|
|
461
|
+
lines.push(mdTable(['Criterion', 'Question', 'Severity', 'Score', 'Effect'], gateFailures.map((g) => [g.id, g.question, g.severity, String(g.score), g.failure_effect || '\u2014'])));
|
|
462
|
+
lines.push('\n---\n');
|
|
463
|
+
}
|
|
464
|
+
// Per-criterion Evidence Details
|
|
465
|
+
const hasEvidence = dimensions.some((d) => d.criteria.some((c) => results[c.id]?.evidence));
|
|
466
|
+
if (hasEvidence) {
|
|
467
|
+
lines.push('## Criterion Details\n');
|
|
468
|
+
for (const dim of dimensions) {
|
|
469
|
+
for (const c of dim.criteria) {
|
|
470
|
+
const r = results[c.id];
|
|
471
|
+
if (!r || r.score === null)
|
|
472
|
+
continue;
|
|
473
|
+
lines.push(`### ${c.id}: ${c.question}\n`);
|
|
474
|
+
lines.push(`- **Score:** ${r.score}`);
|
|
475
|
+
if (r.confidence)
|
|
476
|
+
lines.push(`- **Confidence:** ${r.confidence}`);
|
|
477
|
+
if (r.evidence_class)
|
|
478
|
+
lines.push(`- **Evidence Class:** ${r.evidence_class}`);
|
|
479
|
+
if (r.evidence)
|
|
480
|
+
lines.push(`- **Evidence:** ${r.evidence}`);
|
|
481
|
+
lines.push('');
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return lines.join('\n').replace(/\n{3,}/g, '\n\n').trim() + '\n';
|
|
486
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{aq as o,ar as n}from"./index-DMt1cpG6.js";const t=(r,a)=>o.lang.round(n.parse(r)[a]);export{t as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-D9yxAHyd.js";import{_ as i}from"./index-DMt1cpG6.js";import"./chunk-FMBD7UC4-DoOEFFQC.js";import"./chunk-JSJVCQXG-BerphV2K.js";import"./chunk-55IACEB6-Dxqrf5oZ.js";import"./chunk-KX2RTZJC-CxUAqT05.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as a,c as s,a as e,C as t}from"./chunk-WL4C6EOR-D9yxAHyd.js";import{_ as i}from"./index-DMt1cpG6.js";import"./chunk-FMBD7UC4-DoOEFFQC.js";import"./chunk-JSJVCQXG-BerphV2K.js";import"./chunk-55IACEB6-Dxqrf5oZ.js";import"./chunk-KX2RTZJC-CxUAqT05.js";var u={parser:e,get db(){return new t},renderer:s,styles:a,init:i(r=>{r.class||(r.class={}),r.class.arrowMarkerAbsolute=r.arrowMarkerAbsolute},"init")};export{u as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as r}from"./_baseUniq-HuZouVIz.js";var e=4;function a(o){return r(o,e)}export{a as c};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{s as t,b as r,a,S as s}from"./chunk-NQ4KR5QH-fCqZgFkU.js";import{_ as i}from"./index-DMt1cpG6.js";import"./chunk-55IACEB6-Dxqrf5oZ.js";import"./chunk-KX2RTZJC-CxUAqT05.js";var l={parser:a,get db(){return new s(2)},renderer:r,styles:t,init:i(e=>{e.state||(e.state={}),e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},"init")};export{l as diagram};
|