@f5-sales-demo/xcsh 20.18.0 → 20.18.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/package.json +8 -8
- package/src/browser/chat-handler.ts +1 -1
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/modes/acp/acp-event-mapper.ts +1 -3
- package/src/modes/rpc/rpc-mode.ts +1 -3
- package/src/sandbox/enforce.ts +0 -1
- package/src/tools/index.ts +0 -3
- package/src/tools/renderers.ts +0 -2
- package/src/prompts/tools/display-image.md +0 -23
- package/src/tools/display-image-renderer.ts +0 -96
- package/src/tools/display-image.ts +0 -69
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "20.18.
|
|
4
|
+
"version": "20.18.1",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5-sales-demo/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -61,13 +61,13 @@
|
|
|
61
61
|
},
|
|
62
62
|
"dependencies": {
|
|
63
63
|
"@agentclientprotocol/sdk": "1.3.0",
|
|
64
|
-
"@f5-sales-demo/pi-agent-core": "20.18.
|
|
65
|
-
"@f5-sales-demo/pi-ai": "20.18.
|
|
66
|
-
"@f5-sales-demo/pi-natives": "20.18.
|
|
67
|
-
"@f5-sales-demo/pi-resource-management": "20.18.
|
|
68
|
-
"@f5-sales-demo/pi-tui": "20.18.
|
|
69
|
-
"@f5-sales-demo/pi-utils": "20.18.
|
|
70
|
-
"@f5-sales-demo/xcsh-stats": "20.18.
|
|
64
|
+
"@f5-sales-demo/pi-agent-core": "20.18.1",
|
|
65
|
+
"@f5-sales-demo/pi-ai": "20.18.1",
|
|
66
|
+
"@f5-sales-demo/pi-natives": "20.18.1",
|
|
67
|
+
"@f5-sales-demo/pi-resource-management": "20.18.1",
|
|
68
|
+
"@f5-sales-demo/pi-tui": "20.18.1",
|
|
69
|
+
"@f5-sales-demo/pi-utils": "20.18.1",
|
|
70
|
+
"@f5-sales-demo/xcsh-stats": "20.18.1",
|
|
71
71
|
"@mozilla/readability": "^0.6",
|
|
72
72
|
"@sinclair/typebox": "^0.34",
|
|
73
73
|
"@xterm/headless": "^6.0",
|
|
@@ -334,7 +334,7 @@ export class ChatHandler {
|
|
|
334
334
|
return;
|
|
335
335
|
}
|
|
336
336
|
if (event.type === "tool_execution_end" && "toolName" in event) {
|
|
337
|
-
if (event.toolName === "display_media"
|
|
337
|
+
if (event.toolName === "display_media") {
|
|
338
338
|
const descriptor = extractMediaDescriptorFromToolResult(event.result);
|
|
339
339
|
if (descriptor) {
|
|
340
340
|
this.#server.send({
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "20.18.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "20.18.1",
|
|
21
|
+
"commit": "05ebcdc9d4b43f54c4e54ff44c52229b34e62a6b",
|
|
22
|
+
"shortCommit": "05ebcdc",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v20.18.
|
|
25
|
-
"commitDate": "2026-08-
|
|
26
|
-
"buildDate": "2026-08-
|
|
24
|
+
"tag": "v20.18.1",
|
|
25
|
+
"commitDate": "2026-08-15T13:25:53Z",
|
|
26
|
+
"buildDate": "2026-08-15T13:57:09.805Z",
|
|
27
27
|
"dirty": true,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5-sales-demo/xcsh",
|
|
30
30
|
"repoSlug": "f5-sales-demo/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.18.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/05ebcdc9d4b43f54c4e54ff44c52229b34e62a6b",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.18.1"
|
|
33
33
|
};
|
|
@@ -158,9 +158,7 @@ export function mapAgentSessionEventToAcpSessionUpdates(
|
|
|
158
158
|
}
|
|
159
159
|
case "tool_execution_end": {
|
|
160
160
|
const descriptor =
|
|
161
|
-
event.toolName === "display_media"
|
|
162
|
-
? extractMediaDescriptorFromToolResult(event.result)
|
|
163
|
-
: undefined;
|
|
161
|
+
event.toolName === "display_media" ? extractMediaDescriptorFromToolResult(event.result) : undefined;
|
|
164
162
|
const content = descriptor
|
|
165
163
|
? extractStructuredToolCallContent(event.result)
|
|
166
164
|
: extractToolCallContent(event.result);
|
|
@@ -504,9 +504,7 @@ export async function runRpcMode(session: AgentSession): Promise<never> {
|
|
|
504
504
|
|
|
505
505
|
// Output all agent events as JSON
|
|
506
506
|
session.subscribe(event => {
|
|
507
|
-
const isMediaTool =
|
|
508
|
-
event.type === "tool_execution_end" &&
|
|
509
|
-
(event.toolName === "display_media" || event.toolName === "display_image");
|
|
507
|
+
const isMediaTool = event.type === "tool_execution_end" && event.toolName === "display_media";
|
|
510
508
|
const descriptor = isMediaTool ? extractMediaDescriptorFromToolResult(event.result) : undefined;
|
|
511
509
|
const projected = descriptor ? projectMediaDescriptorForTransport(descriptor) : undefined;
|
|
512
510
|
if (event.type === "tool_execution_end" && projected) {
|
package/src/sandbox/enforce.ts
CHANGED
|
@@ -65,7 +65,6 @@ const TOOL_PATHS: Record<string, PathArgSpec[]> = {
|
|
|
65
65
|
write: [{ keys: ["file_path", "path"], access: "write" }],
|
|
66
66
|
notebook: [{ keys: ["notebook_path"], access: "write" }],
|
|
67
67
|
inspect_image: [{ keys: ["path"], access: "read" }],
|
|
68
|
-
display_image: [{ keys: ["path"], access: "read" }],
|
|
69
68
|
lsp: [{ keys: ["file"], access: "read" }], // read for most actions; rename-apply writes
|
|
70
69
|
catalog_workflow_runner: [
|
|
71
70
|
{ keys: ["catalog_path"], access: "read" },
|
package/src/tools/index.ts
CHANGED
|
@@ -28,7 +28,6 @@ import { CancelJobTool } from "./cancel-job";
|
|
|
28
28
|
import { CatalogWorkflowRunnerTool } from "./catalog-workflow-runner";
|
|
29
29
|
import { type CheckpointState, CheckpointTool, RewindTool } from "./checkpoint";
|
|
30
30
|
import { DebugTool } from "./debug";
|
|
31
|
-
import { DisplayImageTool } from "./display-image";
|
|
32
31
|
import { DisplayMediaTool } from "./display-media";
|
|
33
32
|
import { ExitPlanModeTool } from "./exit-plan-mode";
|
|
34
33
|
import { FindTool } from "./find";
|
|
@@ -71,7 +70,6 @@ export * from "./cancel-job";
|
|
|
71
70
|
export * from "./catalog-workflow-runner";
|
|
72
71
|
export * from "./checkpoint";
|
|
73
72
|
export * from "./debug";
|
|
74
|
-
export * from "./display-image";
|
|
75
73
|
export * from "./display-media";
|
|
76
74
|
export * from "./exit-plan-mode";
|
|
77
75
|
export * from "./find";
|
|
@@ -229,7 +227,6 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
|
|
|
229
227
|
notebook: s => new NotebookTool(s),
|
|
230
228
|
read: s => new ReadTool(s),
|
|
231
229
|
display_media: s => new DisplayMediaTool(s),
|
|
232
|
-
display_image: s => new DisplayImageTool(s),
|
|
233
230
|
inspect_image: s => new InspectImageTool(s),
|
|
234
231
|
browser: s => new BrowserTool(s),
|
|
235
232
|
catalog_workflow_runner: s => new CatalogWorkflowRunnerTool(s),
|
package/src/tools/renderers.ts
CHANGED
|
@@ -18,7 +18,6 @@ import { bashToolRenderer } from "./bash";
|
|
|
18
18
|
import { browserRenderer } from "./browser-renderer";
|
|
19
19
|
import { calculatorToolRenderer } from "./calculator";
|
|
20
20
|
import { debugToolRenderer } from "./debug";
|
|
21
|
-
import { displayImageToolRenderer } from "./display-image-renderer";
|
|
22
21
|
import { displayMediaToolRenderer } from "./display-media-renderer";
|
|
23
22
|
import { findToolRenderer } from "./find";
|
|
24
23
|
import { grepToolRenderer } from "./grep";
|
|
@@ -61,7 +60,6 @@ export const toolRenderers: Record<string, ToolRenderer> = {
|
|
|
61
60
|
lsp: lspToolRenderer as ToolRenderer,
|
|
62
61
|
notebook: notebookToolRenderer as ToolRenderer,
|
|
63
62
|
display_media: displayMediaToolRenderer as ToolRenderer,
|
|
64
|
-
display_image: displayImageToolRenderer as ToolRenderer,
|
|
65
63
|
inspect_image: inspectImageToolRenderer as ToolRenderer,
|
|
66
64
|
read: readToolRenderer as ToolRenderer,
|
|
67
65
|
resolve: resolveToolRenderer as ToolRenderer,
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
Displays an image inline in the terminal conversation. Shows the image visually if the terminal supports it, or opens it in the system image viewer as a fallback.
|
|
2
|
-
|
|
3
|
-
<instruction>
|
|
4
|
-
- Use this when you want to show an image to the user (screenshot, diagram, generated image, photo)
|
|
5
|
-
- Use `inspect_image` instead when you need to analyze or extract information from an image
|
|
6
|
-
- Provide `path` to the local image file (absolute or relative to working directory)
|
|
7
|
-
- Optional `caption` adds descriptive text below the image
|
|
8
|
-
</instruction>
|
|
9
|
-
|
|
10
|
-
<examples>
|
|
11
|
-
- Show a screenshot:
|
|
12
|
-
- `{"path":"screenshots/dashboard.png","caption":"Current dashboard layout"}`
|
|
13
|
-
- Display a generated diagram:
|
|
14
|
-
- `{"path":"output/architecture.png"}`
|
|
15
|
-
- Show a photo with context:
|
|
16
|
-
- `{"path":"assets/logo.png","caption":"Current brand logo"}`
|
|
17
|
-
</examples>
|
|
18
|
-
|
|
19
|
-
<output>
|
|
20
|
-
- Returns the image as an inline image block when the terminal supports image protocols
|
|
21
|
-
- Falls back to opening the image in the system image viewer (Preview.app, xdg-open)
|
|
22
|
-
- Supports PNG, JPEG, GIF, and WEBP formats
|
|
23
|
-
</output>
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import type { Component } from "@f5-sales-demo/pi-tui";
|
|
2
|
-
import { Text } from "@f5-sales-demo/pi-tui";
|
|
3
|
-
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
4
|
-
import type { Theme } from "../modes/theme/theme";
|
|
5
|
-
import { CachedOutputBlock, F5_TOOL_BORDER_COLOR, renderStatusLine } from "../tui";
|
|
6
|
-
import { addSection, formatErrorMessage, shortenPath } from "./render-utils";
|
|
7
|
-
|
|
8
|
-
const TOOL_TITLE = "Display Image";
|
|
9
|
-
|
|
10
|
-
interface DisplayImageRenderArgs {
|
|
11
|
-
path?: string;
|
|
12
|
-
caption?: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface DisplayImageRendererDetails {
|
|
16
|
-
imagePath: string;
|
|
17
|
-
mimeType: string;
|
|
18
|
-
displayMethod: "inline" | "external";
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
interface DisplayImageRendererResult {
|
|
22
|
-
content: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;
|
|
23
|
-
details?: DisplayImageRendererDetails;
|
|
24
|
-
isError?: boolean;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export const displayImageToolRenderer = {
|
|
28
|
-
renderCall(args: DisplayImageRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
29
|
-
const rawPath = args.path ?? "";
|
|
30
|
-
const pathDisplay = rawPath ? shortenPath(rawPath) : "...";
|
|
31
|
-
const description = uiTheme.fg("muted", pathDisplay);
|
|
32
|
-
const text = renderStatusLine({ icon: "pending", title: TOOL_TITLE, description }, uiTheme);
|
|
33
|
-
return new Text(text, 0, 0);
|
|
34
|
-
},
|
|
35
|
-
|
|
36
|
-
renderResult(
|
|
37
|
-
result: DisplayImageRendererResult,
|
|
38
|
-
options: RenderResultOptions,
|
|
39
|
-
uiTheme: Theme,
|
|
40
|
-
args?: DisplayImageRenderArgs,
|
|
41
|
-
): Component {
|
|
42
|
-
const details = result.details;
|
|
43
|
-
const isError = result.isError === true;
|
|
44
|
-
|
|
45
|
-
if (isError && !details) {
|
|
46
|
-
const errorText = result.content?.find(c => c.type === "text")?.text;
|
|
47
|
-
return new Text(formatErrorMessage(errorText, uiTheme), 0, 0);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const rawPath = details?.imagePath ?? args?.path ?? "";
|
|
51
|
-
const pathDisplay = rawPath ? shortenPath(rawPath) : "image";
|
|
52
|
-
const sections: Array<{ label?: string; lines: string[] }> = [];
|
|
53
|
-
const meta: string[] = [];
|
|
54
|
-
|
|
55
|
-
if (details?.mimeType) meta.push(uiTheme.fg("dim", details.mimeType));
|
|
56
|
-
if (details?.displayMethod === "external") meta.push(uiTheme.fg("dim", "external viewer"));
|
|
57
|
-
|
|
58
|
-
if (isError) {
|
|
59
|
-
const errorText = result.content?.find(c => c.type === "text")?.text ?? "Unknown error";
|
|
60
|
-
addSection(sections, "Error", [uiTheme.fg("error", errorText)], uiTheme);
|
|
61
|
-
} else {
|
|
62
|
-
const textContent = result.content?.filter(c => c.type === "text");
|
|
63
|
-
if (textContent?.length) {
|
|
64
|
-
for (const block of textContent) {
|
|
65
|
-
if (block.text) {
|
|
66
|
-
addSection(sections, "", [uiTheme.fg("toolOutput", ` ${block.text}`)], uiTheme);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const header = renderStatusLine(
|
|
73
|
-
{
|
|
74
|
-
title: TOOL_TITLE,
|
|
75
|
-
titleColor: "contentAccent",
|
|
76
|
-
description: pathDisplay,
|
|
77
|
-
meta: meta.length > 0 ? meta : undefined,
|
|
78
|
-
},
|
|
79
|
-
uiTheme,
|
|
80
|
-
);
|
|
81
|
-
|
|
82
|
-
const outputBlock = new CachedOutputBlock();
|
|
83
|
-
return {
|
|
84
|
-
render(width: number): string[] {
|
|
85
|
-
const state = options.isPartial ? "pending" : isError ? "error" : "success";
|
|
86
|
-
return outputBlock.render({ header, state, sections, width, borderColor: F5_TOOL_BORDER_COLOR }, uiTheme);
|
|
87
|
-
},
|
|
88
|
-
invalidate() {
|
|
89
|
-
outputBlock.invalidate();
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
},
|
|
93
|
-
|
|
94
|
-
mergeCallAndResult: true,
|
|
95
|
-
inline: true,
|
|
96
|
-
};
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import * as path from "node:path";
|
|
2
|
-
import type {
|
|
3
|
-
AgentTool,
|
|
4
|
-
AgentToolContext,
|
|
5
|
-
AgentToolResult,
|
|
6
|
-
AgentToolUpdateCallback,
|
|
7
|
-
} from "@f5-sales-demo/pi-agent-core";
|
|
8
|
-
import { prompt } from "@f5-sales-demo/pi-utils";
|
|
9
|
-
import { type Static, Type } from "@sinclair/typebox";
|
|
10
|
-
import displayImageDescription from "../prompts/tools/display-image.md" with { type: "text" };
|
|
11
|
-
import { DisplayMediaTool } from "./display-media";
|
|
12
|
-
import type { ToolSession } from "./index";
|
|
13
|
-
|
|
14
|
-
const displayImageSchema = Type.Object(
|
|
15
|
-
{
|
|
16
|
-
path: Type.String({ description: "Filesystem path to an image file" }),
|
|
17
|
-
caption: Type.Optional(Type.String({ description: "Caption text shown below the image" })),
|
|
18
|
-
},
|
|
19
|
-
{ additionalProperties: false },
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
export type DisplayImageParams = Static<typeof displayImageSchema>;
|
|
23
|
-
|
|
24
|
-
export interface DisplayImageToolDetails {
|
|
25
|
-
imagePath: string;
|
|
26
|
-
mimeType: string;
|
|
27
|
-
displayMethod: "inline" | "external";
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Compatibility wrapper for callers that still use the legacy display_image contract. */
|
|
31
|
-
export class DisplayImageTool implements AgentTool<typeof displayImageSchema, DisplayImageToolDetails> {
|
|
32
|
-
readonly name = "display_image";
|
|
33
|
-
readonly label = "DisplayImage";
|
|
34
|
-
readonly description = prompt.render(displayImageDescription);
|
|
35
|
-
readonly parameters = displayImageSchema;
|
|
36
|
-
readonly strict = true;
|
|
37
|
-
|
|
38
|
-
constructor(private readonly session: ToolSession) {}
|
|
39
|
-
|
|
40
|
-
async execute(
|
|
41
|
-
toolCallId: string,
|
|
42
|
-
params: DisplayImageParams,
|
|
43
|
-
signal?: AbortSignal,
|
|
44
|
-
_onUpdate?: AgentToolUpdateCallback<DisplayImageToolDetails>,
|
|
45
|
-
context?: AgentToolContext,
|
|
46
|
-
): Promise<AgentToolResult<DisplayImageToolDetails>> {
|
|
47
|
-
const result = await new DisplayMediaTool(this.session).execute(
|
|
48
|
-
toolCallId,
|
|
49
|
-
{ source: params.path, caption: params.caption },
|
|
50
|
-
signal,
|
|
51
|
-
undefined,
|
|
52
|
-
context,
|
|
53
|
-
);
|
|
54
|
-
const descriptor = result.details?.descriptor;
|
|
55
|
-
if (!descriptor?.original) throw new Error("display_media did not return an original image asset");
|
|
56
|
-
return {
|
|
57
|
-
content: result.content,
|
|
58
|
-
details: {
|
|
59
|
-
imagePath: path.isAbsolute(params.path)
|
|
60
|
-
? path.normalize(params.path)
|
|
61
|
-
: path.resolve(this.session.cwd, params.path),
|
|
62
|
-
mimeType: descriptor.original.mimeType,
|
|
63
|
-
displayMethod: "inline",
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export { displayImageToolRenderer } from "./display-image-renderer";
|