@f5xc-salesdemos/xcsh 19.43.0 → 19.43.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/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "19.43.
|
|
4
|
+
"version": "19.43.2",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5xc-salesdemos/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -52,13 +52,13 @@
|
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
54
54
|
"@mozilla/readability": "^0.6",
|
|
55
|
-
"@f5xc-salesdemos/xcsh-stats": "19.43.
|
|
56
|
-
"@f5xc-salesdemos/pi-agent-core": "19.43.
|
|
57
|
-
"@f5xc-salesdemos/pi-ai": "19.43.
|
|
58
|
-
"@f5xc-salesdemos/pi-natives": "19.43.
|
|
59
|
-
"@f5xc-salesdemos/pi-resource-management": "19.43.
|
|
60
|
-
"@f5xc-salesdemos/pi-tui": "19.43.
|
|
61
|
-
"@f5xc-salesdemos/pi-utils": "19.43.
|
|
55
|
+
"@f5xc-salesdemos/xcsh-stats": "19.43.2",
|
|
56
|
+
"@f5xc-salesdemos/pi-agent-core": "19.43.2",
|
|
57
|
+
"@f5xc-salesdemos/pi-ai": "19.43.2",
|
|
58
|
+
"@f5xc-salesdemos/pi-natives": "19.43.2",
|
|
59
|
+
"@f5xc-salesdemos/pi-resource-management": "19.43.2",
|
|
60
|
+
"@f5xc-salesdemos/pi-tui": "19.43.2",
|
|
61
|
+
"@f5xc-salesdemos/pi-utils": "19.43.2",
|
|
62
62
|
"@sinclair/typebox": "^0.34",
|
|
63
63
|
"@xterm/headless": "^6.0",
|
|
64
64
|
"ajv": "^8.20",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "19.43.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "19.43.2",
|
|
21
|
+
"commit": "09742430243eddeb0ed597e94079c21ceca02d7f",
|
|
22
|
+
"shortCommit": "0974243",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v19.43.
|
|
25
|
-
"commitDate": "2026-06-
|
|
26
|
-
"buildDate": "2026-06-
|
|
24
|
+
"tag": "v19.43.2",
|
|
25
|
+
"commitDate": "2026-06-24T16:28:28Z",
|
|
26
|
+
"buildDate": "2026-06-24T16:56:22.826Z",
|
|
27
27
|
"dirty": true,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
|
|
30
30
|
"repoSlug": "f5xc-salesdemos/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.43.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/09742430243eddeb0ed597e94079c21ceca02d7f",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.43.2"
|
|
33
33
|
};
|
|
@@ -41,6 +41,33 @@ export interface RenderMermaidThemedOptions {
|
|
|
41
41
|
colorMode?: MermaidColorMode;
|
|
42
42
|
/** Extra layout options (padding, useAscii, …). */
|
|
43
43
|
render?: MermaidAsciiRenderOptions;
|
|
44
|
+
/**
|
|
45
|
+
* Available content width. When set (and paddingX isn't overridden), node spacing
|
|
46
|
+
* is expanded toward this width so the diagram uses the available space instead of
|
|
47
|
+
* rendering tiny — capped so small diagrams don't sprawl.
|
|
48
|
+
*/
|
|
49
|
+
targetWidth?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const DEFAULT_PADDING_X = 2;
|
|
53
|
+
const DEFAULT_PADDING_Y = 1;
|
|
54
|
+
// Candidate horizontal spacings (ascending). Widening paddingX grows width WITHOUT
|
|
55
|
+
// growing height, so we can use much of the terminal; capped so a tiny diagram
|
|
56
|
+
// doesn't sprawl into absurdly long edges on a very wide terminal.
|
|
57
|
+
const PADDING_X_CANDIDATES = [1, 2, 4, 6, 8, 10, 12, 16, 20, 24];
|
|
58
|
+
|
|
59
|
+
/** Largest candidate paddingX whose rendered width still fits targetWidth (>= smallest). */
|
|
60
|
+
function pickPaddingXForWidth(source: string, targetWidth: number): number {
|
|
61
|
+
let best = PADDING_X_CANDIDATES[0]!;
|
|
62
|
+
for (const px of PADDING_X_CANDIDATES) {
|
|
63
|
+
const out = renderMermaidAsciiSafe(source, { colorMode: "none", paddingX: px, paddingY: DEFAULT_PADDING_Y });
|
|
64
|
+
if (out == null) break;
|
|
65
|
+
let w = 0;
|
|
66
|
+
for (const line of out.split("\n")) w = Math.max(w, Bun.stringWidth(line));
|
|
67
|
+
if (w <= targetWidth) best = px;
|
|
68
|
+
else break; // wider candidates only grow; stop early (also avoids costly large-padding renders)
|
|
69
|
+
}
|
|
70
|
+
return best;
|
|
44
71
|
}
|
|
45
72
|
|
|
46
73
|
/**
|
|
@@ -54,25 +81,27 @@ export function renderMermaidThemed(source: string, theme: Theme, opts?: RenderM
|
|
|
54
81
|
if (mermaidSourceExceedsLimit(source)) return null;
|
|
55
82
|
|
|
56
83
|
const mode = colorModeFor(theme, opts?.colorMode);
|
|
57
|
-
|
|
58
|
-
//
|
|
59
|
-
// the
|
|
60
|
-
const
|
|
84
|
+
const baseRender = opts?.render ?? {};
|
|
85
|
+
// Resolve horizontal spacing: explicit override wins; else expand toward the target
|
|
86
|
+
// width (capped) so the diagram uses the space; else the compact default.
|
|
87
|
+
const paddingX =
|
|
88
|
+
baseRender.paddingX ??
|
|
89
|
+
(opts?.targetWidth !== undefined ? pickPaddingXForWidth(source, opts.targetWidth) : DEFAULT_PADDING_X);
|
|
90
|
+
const renderOpts: MermaidAsciiRenderOptions = { paddingY: DEFAULT_PADDING_Y, ...baseRender, paddingX };
|
|
91
|
+
|
|
92
|
+
// Layout options change the output, so they must be part of the key — but the
|
|
93
|
+
// compact DEFAULT is treated as "no options" so the key still matches
|
|
94
|
+
// mermaidThemeSignature()/getMermaidAscii() (the inline prerender/lookup path).
|
|
95
|
+
const sigObj: Record<string, unknown> = { ...renderOpts };
|
|
96
|
+
if (sigObj.paddingX === DEFAULT_PADDING_X) delete sigObj.paddingX;
|
|
97
|
+
if (sigObj.paddingY === DEFAULT_PADDING_Y) delete sigObj.paddingY;
|
|
98
|
+
const optsSig = Object.keys(sigObj).length > 0 ? `|${JSON.stringify(sigObj)}` : "";
|
|
61
99
|
const key = `${Bun.hash(source.trim())}|${mode}:${paletteSignature(theme)}${optsSig}`;
|
|
62
100
|
const cached = cache.get(key);
|
|
63
101
|
if (cached !== undefined) return cached;
|
|
64
102
|
|
|
65
103
|
const asciiTheme = buildMermaidAsciiTheme(theme);
|
|
66
|
-
|
|
67
|
-
// apart and bloats the diagram. Tighter spacing reads more elegantly and helps it
|
|
68
|
-
// fit the transcript width. Callers can still override via opts.render.
|
|
69
|
-
const colored = renderMermaidAsciiSafe(source, {
|
|
70
|
-
paddingX: 2,
|
|
71
|
-
paddingY: 1,
|
|
72
|
-
...opts?.render,
|
|
73
|
-
colorMode: mode,
|
|
74
|
-
theme: asciiTheme,
|
|
75
|
-
});
|
|
104
|
+
const colored = renderMermaidAsciiSafe(source, { ...renderOpts, colorMode: mode, theme: asciiTheme });
|
|
76
105
|
if (colored == null) {
|
|
77
106
|
cache.set(key, null);
|
|
78
107
|
return null;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Map the active xcsh UI theme onto a mermaid `AsciiTheme
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Map the active xcsh UI theme onto a mermaid `AsciiTheme`. The palette is
|
|
3
|
+
* deliberately restrained and professional: neutral gray structure with a single
|
|
4
|
+
* F5-brand accent on the arrowheads — no rainbow of per-node colors. Reading the
|
|
5
|
+
* theme keeps it dark/light adaptive and on-brand.
|
|
5
6
|
*/
|
|
6
7
|
import type { MermaidAsciiRenderOptions } from "@f5xc-salesdemos/pi-utils";
|
|
7
8
|
import type { Theme } from "./theme";
|
|
@@ -9,35 +10,30 @@ import type { Theme } from "./theme";
|
|
|
9
10
|
type AsciiTheme = NonNullable<MermaidAsciiRenderOptions["theme"]>;
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
13
|
+
* Restrained per-role palette — neutral grays for the diagram structure, with one
|
|
14
|
+
* brand accent on the arrowheads:
|
|
15
|
+
* labels → neutral text gray
|
|
16
|
+
* borders → soft gray
|
|
17
|
+
* edges → dim gray (recede behind the boxes)
|
|
18
|
+
* arrows → F5 brand accent (the single pop of color)
|
|
19
|
+
* Nodes render uniformly (see buildNodeAccents — no per-node tint).
|
|
15
20
|
*/
|
|
16
21
|
export function buildMermaidAsciiTheme(theme: Theme): AsciiTheme {
|
|
17
22
|
return {
|
|
18
|
-
fg: theme.getFgHex("
|
|
19
|
-
border: theme.getFgHex("
|
|
20
|
-
line: theme.getFgHex("
|
|
21
|
-
arrow: theme.getFgHex("
|
|
22
|
-
corner: theme.getFgHex("
|
|
23
|
-
junction: theme.getFgHex("
|
|
23
|
+
fg: theme.getFgHex("toolOutput", "#9ca3b0"), // node + edge labels
|
|
24
|
+
border: theme.getFgHex("muted", "#9ca3b0"), // node + subgraph borders
|
|
25
|
+
line: theme.getFgHex("dim", "#6b7280"), // edge lines — subtle
|
|
26
|
+
arrow: theme.getFgHex("accent", "#ca260a"), // arrowheads — single brand accent
|
|
27
|
+
corner: theme.getFgHex("dim", "#6b7280"),
|
|
28
|
+
junction: theme.getFgHex("muted", "#9ca3b0"),
|
|
24
29
|
};
|
|
25
30
|
}
|
|
26
31
|
|
|
27
32
|
/**
|
|
28
|
-
*
|
|
29
|
-
*
|
|
33
|
+
* Per-node accent colors for the tint pass. Intentionally EMPTY: a professional
|
|
34
|
+
* diagram reads as one consistent palette, not a different bright hue per box.
|
|
35
|
+
* With no accents, the tint pass is a no-op and nodes use the role colors above.
|
|
30
36
|
*/
|
|
31
|
-
export function buildNodeAccents(
|
|
32
|
-
|
|
33
|
-
const seen = new Set<string>();
|
|
34
|
-
const accents: string[] = [];
|
|
35
|
-
for (const role of roles) {
|
|
36
|
-
const ansi = theme.getFgAnsi(role);
|
|
37
|
-
if (!seen.has(ansi)) {
|
|
38
|
-
seen.add(ansi);
|
|
39
|
-
accents.push(ansi);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return accents;
|
|
37
|
+
export function buildNodeAccents(_theme: Theme): string[] {
|
|
38
|
+
return [];
|
|
43
39
|
}
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -10,13 +10,15 @@ import {
|
|
|
10
10
|
supportsLanguage as nativeSupportsLanguage,
|
|
11
11
|
} from "@f5xc-salesdemos/pi-natives";
|
|
12
12
|
import type { EditorTheme, MarkdownTheme, SelectListTheme, SymbolTheme } from "@f5xc-salesdemos/pi-tui";
|
|
13
|
-
import { adjustHsv, getCustomThemesDir, isEnoent, logger } from "@f5xc-salesdemos/pi-utils";
|
|
13
|
+
import { adjustHsv, detectDiagramType, getCustomThemesDir, isEnoent, logger } from "@f5xc-salesdemos/pi-utils";
|
|
14
14
|
import { type Static, Type } from "@sinclair/typebox";
|
|
15
15
|
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
16
16
|
import chalk from "chalk";
|
|
17
|
+
import { buildMermaidBlockOptions, diagramTypeLabel } from "../../tools/mermaid-renderer";
|
|
18
|
+
import { renderOutputBlock } from "../../tui";
|
|
17
19
|
// Embed theme JSON files at build time
|
|
18
20
|
import { defaultThemes } from "./defaults";
|
|
19
|
-
import { getMermaidAscii, mermaidThemeSignature } from "./mermaid-cache";
|
|
21
|
+
import { getMermaidAscii, mermaidThemeSignature, renderMermaidThemed } from "./mermaid-cache";
|
|
20
22
|
|
|
21
23
|
export { getLanguageFromPath } from "../../utils/lang-from-path";
|
|
22
24
|
|
|
@@ -2510,6 +2512,14 @@ export function getMarkdownTheme(): MarkdownTheme {
|
|
|
2510
2512
|
strikethrough: (text: string) => chalk.strikethrough(text),
|
|
2511
2513
|
symbols: getSymbolTheme(),
|
|
2512
2514
|
getMermaidAscii: (hash: bigint | number) => getMermaidAscii(hash, mermaidThemeSignature(theme)),
|
|
2515
|
+
renderMermaidBlock: (source: string, width: number): string[] | null => {
|
|
2516
|
+
const diagram = renderMermaidThemed(source, theme, { targetWidth: Math.max(20, width - 4) });
|
|
2517
|
+
if (!diagram) return null;
|
|
2518
|
+
return renderOutputBlock(
|
|
2519
|
+
buildMermaidBlockOptions(diagram, { width, theme, typeLabel: diagramTypeLabel(detectDiagramType(source)) }),
|
|
2520
|
+
theme,
|
|
2521
|
+
);
|
|
2522
|
+
},
|
|
2513
2523
|
highlightCode: (code: string, lang?: string): string[] => {
|
|
2514
2524
|
const validLang = lang && nativeSupportsLanguage(lang) ? lang : undefined;
|
|
2515
2525
|
try {
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
/** TUI renderer for the render_mermaid tool —
|
|
1
|
+
/** TUI renderer for the render_mermaid tool — single F5-framed, themed, colorized diagram. */
|
|
2
2
|
import type { Component } from "@f5xc-salesdemos/pi-tui";
|
|
3
|
-
import { Text } from "@f5xc-salesdemos/pi-tui";
|
|
3
|
+
import { Text, visibleWidth } from "@f5xc-salesdemos/pi-tui";
|
|
4
4
|
import { detectDiagramType, type MermaidDiagramType } from "@f5xc-salesdemos/pi-utils";
|
|
5
5
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
6
6
|
import { renderMermaidThemed } from "../modes/theme/mermaid-cache";
|
|
7
7
|
import type { Theme } from "../modes/theme/theme";
|
|
8
|
-
import { CachedOutputBlock, F5_TOOL_BORDER_COLOR, renderStatusLine } from "../tui";
|
|
8
|
+
import { CachedOutputBlock, F5_TOOL_BORDER_COLOR, type OutputBlockOptions, renderStatusLine } from "../tui";
|
|
9
9
|
import type { RenderMermaidToolDetails } from "./render-mermaid";
|
|
10
|
-
import {
|
|
10
|
+
import { formatErrorMessage, replaceTabs } from "./render-utils";
|
|
11
11
|
|
|
12
12
|
const TOOL_TITLE = "Mermaid";
|
|
13
13
|
|
|
14
|
-
/** Human-friendly caption for the diagram
|
|
15
|
-
function diagramTypeLabel(type: MermaidDiagramType): string {
|
|
14
|
+
/** Human-friendly caption for the diagram type, shown in the F5 frame header. */
|
|
15
|
+
export function diagramTypeLabel(type: MermaidDiagramType): string {
|
|
16
16
|
switch (type) {
|
|
17
17
|
case "flowchart":
|
|
18
18
|
return "flowchart";
|
|
@@ -31,6 +31,41 @@ function diagramTypeLabel(type: MermaidDiagramType): string {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Build the F5 output-block options that frame a themed/colored mermaid diagram.
|
|
36
|
+
* Shared by the render_mermaid tool result AND inline ```mermaid markdown blocks, so
|
|
37
|
+
* every mermaid render gets the SAME single F5 frame — and the diagram is clipped
|
|
38
|
+
* (wrapContent: false), never wrapped, so a wide diagram can't reflow or overflow.
|
|
39
|
+
*/
|
|
40
|
+
export function buildMermaidBlockOptions(
|
|
41
|
+
diagramText: string,
|
|
42
|
+
opts: { width: number; theme: Theme; typeLabel: string; artifactId?: string },
|
|
43
|
+
): OutputBlockOptions {
|
|
44
|
+
// Unlabeled section: the header already reads "Mermaid · <type>", so a "Diagram"
|
|
45
|
+
// bar would be redundant. The diagram keeps its own colors; we only normalize tabs.
|
|
46
|
+
const lines = diagramText.split("\n").map(line => replaceTabs(line));
|
|
47
|
+
const meta = opts.artifactId ? [opts.theme.fg("dim", `artifact:${opts.artifactId.slice(0, 8)}`)] : undefined;
|
|
48
|
+
const header = renderStatusLine(
|
|
49
|
+
{ title: TOOL_TITLE, titleColor: "dim", description: opts.theme.fg("muted", opts.typeLabel), meta },
|
|
50
|
+
opts.theme,
|
|
51
|
+
);
|
|
52
|
+
// Size the frame SNUGLY to the diagram (+ one space of padding each side), capped at
|
|
53
|
+
// the available width and kept wide enough for the header caption — so the diagram
|
|
54
|
+
// feels enclosed in a small padded frame instead of spanning the whole terminal
|
|
55
|
+
// (tiny diagram) or clipping against the right border (wide diagram).
|
|
56
|
+
const maxDiagramWidth = lines.reduce((max, line) => Math.max(max, visibleWidth(line)), 0);
|
|
57
|
+
const desired = Math.max(maxDiagramWidth + 4, visibleWidth(header) + 8);
|
|
58
|
+
const width = Math.min(opts.width, Math.max(1, desired));
|
|
59
|
+
return {
|
|
60
|
+
header,
|
|
61
|
+
state: "success",
|
|
62
|
+
sections: [{ lines }],
|
|
63
|
+
width,
|
|
64
|
+
borderColor: F5_TOOL_BORDER_COLOR,
|
|
65
|
+
wrapContent: false,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
34
69
|
type MermaidRenderArgs = {
|
|
35
70
|
mermaid?: string;
|
|
36
71
|
};
|
|
@@ -50,63 +85,39 @@ export const mermaidRenderer = {
|
|
|
50
85
|
details?: RenderMermaidToolDetails;
|
|
51
86
|
isError?: boolean;
|
|
52
87
|
},
|
|
53
|
-
|
|
88
|
+
_options: RenderResultOptions,
|
|
54
89
|
uiTheme: Theme,
|
|
55
90
|
args?: MermaidRenderArgs,
|
|
56
91
|
): Component {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
if (isError) {
|
|
92
|
+
if (result.isError === true) {
|
|
60
93
|
const errorText = result.content?.find(c => c.type === "text")?.text;
|
|
61
94
|
return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
|
|
62
95
|
}
|
|
63
96
|
|
|
64
|
-
const sections: Array<{ label?: string; lines: string[] }> = [];
|
|
65
|
-
const meta: string[] = [];
|
|
66
97
|
const rawText = result.content?.find(c => c.type === "text")?.text ?? "";
|
|
67
|
-
|
|
68
98
|
// Strip artifact reference from the plain result text (fallback path).
|
|
69
99
|
const artifactIdx = rawText.indexOf("\n\nSaved artifact:");
|
|
70
100
|
const plainText = artifactIdx >= 0 ? rawText.slice(0, artifactIdx) : rawText;
|
|
71
101
|
|
|
72
|
-
// Prefer re-rendering from the original source:
|
|
73
|
-
// per-role-colored, node-tinted diagram. Fall back to the plain result text.
|
|
102
|
+
// Prefer re-rendering from the original source: themed, per-node-tinted, colored.
|
|
74
103
|
const source = args?.mermaid?.trim();
|
|
75
|
-
const
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
// Keep the diagram's own colors — do NOT recolor each line a flat tool color.
|
|
79
|
-
// Show the FULL diagram: truncating a diagram with "… N more lines" defeats the purpose.
|
|
80
|
-
const diagramLines = diagramText.split("\n").map(line => replaceTabs(line));
|
|
81
|
-
addSection(sections, "Diagram", diagramLines, uiTheme);
|
|
82
|
-
|
|
83
|
-
if (result.details?.artifactId) {
|
|
84
|
-
meta.push(uiTheme.fg("dim", `artifact:${result.details.artifactId.slice(0, 8)}`));
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const header = renderStatusLine(
|
|
88
|
-
{
|
|
89
|
-
title: TOOL_TITLE,
|
|
90
|
-
titleColor: "dim",
|
|
91
|
-
description: uiTheme.fg("muted", caption),
|
|
92
|
-
meta: meta.length > 0 ? meta : undefined,
|
|
93
|
-
},
|
|
94
|
-
uiTheme,
|
|
95
|
-
);
|
|
104
|
+
const typeLabel = source ? diagramTypeLabel(detectDiagramType(source)) : "diagram";
|
|
105
|
+
const artifactId = result.details?.artifactId;
|
|
96
106
|
|
|
97
|
-
const
|
|
107
|
+
const block = new CachedOutputBlock();
|
|
98
108
|
return {
|
|
99
109
|
render(width: number): string[] {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
// Expand the diagram toward the available width (inside the frame), then
|
|
111
|
+
// size the frame snugly around the result.
|
|
112
|
+
const targetWidth = Math.max(20, width - 4);
|
|
113
|
+
const diagramText = (source ? renderMermaidThemed(source, uiTheme, { targetWidth }) : null) ?? plainText;
|
|
114
|
+
return block.render(
|
|
115
|
+
buildMermaidBlockOptions(diagramText, { width, theme: uiTheme, typeLabel, artifactId }),
|
|
105
116
|
uiTheme,
|
|
106
117
|
);
|
|
107
118
|
},
|
|
108
119
|
invalidate() {
|
|
109
|
-
|
|
120
|
+
block.invalidate();
|
|
110
121
|
},
|
|
111
122
|
};
|
|
112
123
|
},
|