@f5xc-salesdemos/xcsh 18.5.0 → 18.5.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": "18.5.
|
|
4
|
+
"version": "18.5.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",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
49
49
|
"@mozilla/readability": "^0.6",
|
|
50
|
-
"@f5xc-salesdemos/xcsh-stats": "18.5.
|
|
51
|
-
"@f5xc-salesdemos/pi-agent-core": "18.5.
|
|
52
|
-
"@f5xc-salesdemos/pi-ai": "18.5.
|
|
53
|
-
"@f5xc-salesdemos/pi-natives": "18.5.
|
|
54
|
-
"@f5xc-salesdemos/pi-tui": "18.5.
|
|
55
|
-
"@f5xc-salesdemos/pi-utils": "18.5.
|
|
50
|
+
"@f5xc-salesdemos/xcsh-stats": "18.5.2",
|
|
51
|
+
"@f5xc-salesdemos/pi-agent-core": "18.5.2",
|
|
52
|
+
"@f5xc-salesdemos/pi-ai": "18.5.2",
|
|
53
|
+
"@f5xc-salesdemos/pi-natives": "18.5.2",
|
|
54
|
+
"@f5xc-salesdemos/pi-tui": "18.5.2",
|
|
55
|
+
"@f5xc-salesdemos/pi-utils": "18.5.2",
|
|
56
56
|
"@sinclair/typebox": "^0.34",
|
|
57
57
|
"@xterm/headless": "^6.0",
|
|
58
58
|
"ajv": "^8.18",
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.5.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.5.2",
|
|
21
|
+
"commit": "241bff6e524c48aacf4e14b31b8fc5b39d7f9047",
|
|
22
|
+
"shortCommit": "241bff6",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.5.
|
|
25
|
-
"commitDate": "2026-04-
|
|
26
|
-
"buildDate": "2026-04-
|
|
24
|
+
"tag": "v18.5.2",
|
|
25
|
+
"commitDate": "2026-04-21T20:23:54Z",
|
|
26
|
+
"buildDate": "2026-04-21T20:47:19.277Z",
|
|
27
27
|
"dirty": false,
|
|
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/v18.5.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/241bff6e524c48aacf4e14b31b8fc5b39d7f9047",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.5.2"
|
|
33
33
|
};
|
|
@@ -82,7 +82,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
82
82
|
);
|
|
83
83
|
continue;
|
|
84
84
|
}
|
|
85
|
-
this.#contentContainer.addChild(new Text(theme.fg("toolOutput", `[Image: ${image.mimeType}]`),
|
|
85
|
+
this.#contentContainer.addChild(new Text(theme.fg("toolOutput", `[Image: ${image.mimeType}]`), 0, 0));
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
#triggerMermaidPrerender(message: AssistantMessage): void {
|
|
@@ -137,7 +137,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
137
137
|
if (content.type === "text" && content.text.trim()) {
|
|
138
138
|
// Assistant text messages with no background - trim the text
|
|
139
139
|
// Set paddingY=0 to avoid extra spacing before tool executions
|
|
140
|
-
this.#contentContainer.addChild(new Markdown(content.text.trim(),
|
|
140
|
+
this.#contentContainer.addChild(new Markdown(content.text.trim(), 0, 0, getMarkdownTheme()));
|
|
141
141
|
} else if (content.type === "thinking" && content.thinking.trim()) {
|
|
142
142
|
// Add spacing only when another visible assistant content block follows.
|
|
143
143
|
// This avoids a superfluous blank line before separately-rendered tool execution blocks.
|
|
@@ -147,14 +147,14 @@ export class AssistantMessageComponent extends Container {
|
|
|
147
147
|
|
|
148
148
|
if (this.hideThinkingBlock) {
|
|
149
149
|
// Show static "Thinking..." label when hidden
|
|
150
|
-
this.#contentContainer.addChild(new Text(theme.italic(theme.fg("thinkingText", "Thinking...")),
|
|
150
|
+
this.#contentContainer.addChild(new Text(theme.italic(theme.fg("thinkingText", "Thinking...")), 0, 0));
|
|
151
151
|
if (hasVisibleContentAfter) {
|
|
152
152
|
this.#contentContainer.addChild(new Spacer(1));
|
|
153
153
|
}
|
|
154
154
|
} else {
|
|
155
155
|
// Thinking traces in thinkingText color, italic
|
|
156
156
|
this.#contentContainer.addChild(
|
|
157
|
-
new Markdown(content.thinking.trim(),
|
|
157
|
+
new Markdown(content.thinking.trim(), 0, 0, getMarkdownTheme(), {
|
|
158
158
|
color: (text: string) => theme.fg("thinkingText", text),
|
|
159
159
|
italic: true,
|
|
160
160
|
}),
|
|
@@ -181,11 +181,11 @@ export class AssistantMessageComponent extends Container {
|
|
|
181
181
|
} else {
|
|
182
182
|
this.#contentContainer.addChild(new Spacer(1));
|
|
183
183
|
}
|
|
184
|
-
this.#contentContainer.addChild(new Text(theme.fg("error", abortMessage),
|
|
184
|
+
this.#contentContainer.addChild(new Text(theme.fg("error", abortMessage), 0, 0));
|
|
185
185
|
} else if (message.stopReason === "error") {
|
|
186
186
|
const errorMsg = message.errorMessage || "Unknown error";
|
|
187
187
|
this.#contentContainer.addChild(new Spacer(1));
|
|
188
|
-
this.#contentContainer.addChild(new Text(theme.fg("error", `Error: ${errorMsg}`),
|
|
188
|
+
this.#contentContainer.addChild(new Text(theme.fg("error", `Error: ${errorMsg}`), 0, 0));
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
|
|
@@ -200,7 +200,7 @@ export class AssistantMessageComponent extends Container {
|
|
|
200
200
|
parts.push(`cache: ${formatNumber(usage.cacheRead)}`);
|
|
201
201
|
}
|
|
202
202
|
this.#contentContainer.addChild(new Spacer(1));
|
|
203
|
-
this.#contentContainer.addChild(new Text(theme.fg("dim", parts.join(" ")),
|
|
203
|
+
this.#contentContainer.addChild(new Text(theme.fg("dim", parts.join(" ")), 0, 0));
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
}
|
|
@@ -7,16 +7,22 @@ const CONTINUATION_BAR = "┃";
|
|
|
7
7
|
// render output is 3 terminal cells. Anything narrower than prefix+3 would
|
|
8
8
|
// overflow the requested width — bail out instead.
|
|
9
9
|
const MIN_MARKDOWN_WIDTH = 3;
|
|
10
|
-
//
|
|
11
|
-
//
|
|
10
|
+
// Two-column layout: the gutter (col 0..GUTTER_WIDTH-1) stays outside the
|
|
11
|
+
// userMessageBg painted region and holds the π icon on the first content
|
|
12
|
+
// line / two spaces on continuations — mirroring how GutterBlock renders
|
|
13
|
+
// its ● indicator at col 0. The painted region starts at col GUTTER_WIDTH
|
|
14
|
+
// and hosts the ┃ accent bar on every content line (including the first).
|
|
12
15
|
const GUTTER_WIDTH = 2;
|
|
13
16
|
const GUTTER_PAD = " ";
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
|
-
* Renders a user message as an F5-branded admonition block
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
19
|
+
* Renders a user message as an F5-branded admonition block with a two-column
|
|
20
|
+
* layout: the π icon sits in the gutter at col 0 on the first content line
|
|
21
|
+
* (outside the painted region, matching the `●` indicator pattern used by
|
|
22
|
+
* `GutterBlock`); the ┃ heavy vertical bar renders at col GUTTER_WIDTH inside
|
|
23
|
+
* `userMessageBg` on every content line including the first. Both glyphs use
|
|
24
|
+
* the `border` fg. The bg is painted across the full requested width, and a
|
|
25
|
+
* leading blank spacer separates the prompt from the preceding block.
|
|
20
26
|
*/
|
|
21
27
|
export class UserMessageComponent extends Container {
|
|
22
28
|
constructor(text: string, synthetic = false) {
|
|
@@ -25,17 +31,14 @@ export class UserMessageComponent extends Container {
|
|
|
25
31
|
? (value: string) => theme.fg("dim", value)
|
|
26
32
|
: (value: string) => `\x1b[3m${theme.fg("userMessageText", value)}\x1b[23m`;
|
|
27
33
|
this.addChild(new Spacer(1));
|
|
28
|
-
this.addChild(new Markdown(text,
|
|
34
|
+
this.addChild(new Markdown(text, 0, 0, getMarkdownTheme(), { color }));
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
override render(width: number): string[] {
|
|
32
|
-
const piPrefix = `${theme.icon.pi} `;
|
|
33
38
|
const contPrefix = `${CONTINUATION_BAR} `;
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
37
|
-
const prefixWidth = Math.max(visibleWidth(piPrefix), visibleWidth(contPrefix));
|
|
38
|
-
const innerWidth = width - GUTTER_WIDTH - prefixWidth;
|
|
39
|
+
// π lives in the fixed-width gutter (see the content map below), so it
|
|
40
|
+
// does not factor into innerWidth. Only contPrefix eats content budget.
|
|
41
|
+
const innerWidth = width - GUTTER_WIDTH - visibleWidth(contPrefix);
|
|
39
42
|
if (innerWidth < MIN_MARKDOWN_WIDTH) {
|
|
40
43
|
return [];
|
|
41
44
|
}
|
|
@@ -52,12 +55,25 @@ export class UserMessageComponent extends Container {
|
|
|
52
55
|
return raw;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
// First-line gutter: π icon padded to exactly GUTTER_WIDTH cells. The
|
|
59
|
+
// glyph width is theme-dependent (Unicode π = 1 col, Nerd Font PUA = 2
|
|
60
|
+
// cols, ASCII "pi" = 2 cols); right-pad with spaces so the gutter
|
|
61
|
+
// occupies a fixed slot and the ┃ bar at col GUTTER_WIDTH aligns across
|
|
62
|
+
// every content line.
|
|
63
|
+
const piIcon = theme.icon.pi;
|
|
64
|
+
const piPadSize = Math.max(0, GUTTER_WIDTH - visibleWidth(piIcon));
|
|
65
|
+
// Pad inside the theme.fg wrap so the border-fg escape, glyph, and
|
|
66
|
+
// pad space form one contiguous span (no intervening fg reset). This
|
|
67
|
+
// matches the shape the raw-escape assertion in test 6 looks for.
|
|
68
|
+
const piGutter = theme.fg("border", piIcon + " ".repeat(piPadSize));
|
|
69
|
+
|
|
55
70
|
const leading = raw.slice(0, firstContent);
|
|
56
71
|
const content = raw.slice(firstContent).map((line, i) => {
|
|
57
|
-
const prefix = theme.fg("border",
|
|
72
|
+
const prefix = theme.fg("border", contPrefix);
|
|
58
73
|
const combined = prefix + line;
|
|
59
74
|
const pad = Math.max(0, width - GUTTER_WIDTH - visibleWidth(combined));
|
|
60
|
-
|
|
75
|
+
const gutter = i === 0 ? piGutter : GUTTER_PAD;
|
|
76
|
+
return gutter + theme.bg("userMessageBg", combined + padding(pad));
|
|
61
77
|
});
|
|
62
78
|
|
|
63
79
|
return [...leading, ...content];
|