@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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/xcsh",
4
- "version": "20.18.0",
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.0",
65
- "@f5-sales-demo/pi-ai": "20.18.0",
66
- "@f5-sales-demo/pi-natives": "20.18.0",
67
- "@f5-sales-demo/pi-resource-management": "20.18.0",
68
- "@f5-sales-demo/pi-tui": "20.18.0",
69
- "@f5-sales-demo/pi-utils": "20.18.0",
70
- "@f5-sales-demo/xcsh-stats": "20.18.0",
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" || event.toolName === "display_image") {
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.0",
21
- "commit": "bb8af0601559effb96162735f79350a7d6beb9b0",
22
- "shortCommit": "bb8af06",
20
+ "version": "20.18.1",
21
+ "commit": "05ebcdc9d4b43f54c4e54ff44c52229b34e62a6b",
22
+ "shortCommit": "05ebcdc",
23
23
  "branch": "main",
24
- "tag": "v20.18.0",
25
- "commitDate": "2026-08-15T07:52:07Z",
26
- "buildDate": "2026-08-15T08:18:07.894Z",
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/bb8af0601559effb96162735f79350a7d6beb9b0",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.18.0"
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" || event.toolName === "display_image"
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) {
@@ -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" },
@@ -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),
@@ -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";