@f5xc-salesdemos/xcsh 19.43.1 → 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
|
@@ -2513,7 +2513,7 @@ export function getMarkdownTheme(): MarkdownTheme {
|
|
|
2513
2513
|
symbols: getSymbolTheme(),
|
|
2514
2514
|
getMermaidAscii: (hash: bigint | number) => getMermaidAscii(hash, mermaidThemeSignature(theme)),
|
|
2515
2515
|
renderMermaidBlock: (source: string, width: number): string[] | null => {
|
|
2516
|
-
const diagram = renderMermaidThemed(source, theme);
|
|
2516
|
+
const diagram = renderMermaidThemed(source, theme, { targetWidth: Math.max(20, width - 4) });
|
|
2517
2517
|
if (!diagram) return null;
|
|
2518
2518
|
return renderOutputBlock(
|
|
2519
2519
|
buildMermaidBlockOptions(diagram, { width, theme, typeLabel: diagramTypeLabel(detectDiagramType(source)) }),
|
|
@@ -101,13 +101,16 @@ export const mermaidRenderer = {
|
|
|
101
101
|
|
|
102
102
|
// Prefer re-rendering from the original source: themed, per-node-tinted, colored.
|
|
103
103
|
const source = args?.mermaid?.trim();
|
|
104
|
-
const diagramText = (source ? renderMermaidThemed(source, uiTheme) : null) ?? plainText;
|
|
105
104
|
const typeLabel = source ? diagramTypeLabel(detectDiagramType(source)) : "diagram";
|
|
106
105
|
const artifactId = result.details?.artifactId;
|
|
107
106
|
|
|
108
107
|
const block = new CachedOutputBlock();
|
|
109
108
|
return {
|
|
110
109
|
render(width: number): string[] {
|
|
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;
|
|
111
114
|
return block.render(
|
|
112
115
|
buildMermaidBlockOptions(diagramText, { width, theme: uiTheme, typeLabel, artifactId }),
|
|
113
116
|
uiTheme,
|