@f5-sales-demo/xcsh 20.18.1 → 20.19.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/CHANGELOG.md CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## Unreleased
6
+
7
+ ### Added
8
+
9
+ - Added provenance-validated, deterministic `render_map` PNG generation with OpenStreetMap tile
10
+ policy compliance, schematic and text fallbacks, and optional atomic PNG/GeoJSON export
11
+ ([#3202](https://github.com/f5-sales-demo/xcsh/issues/3202)).
12
+
13
+ ### Changed
14
+
15
+ - Unified generated and existing media publication behind the versioned `xcsh.media/v1` result
16
+ contract so TUI, Browser, Office, RPC, and ACP transports no longer identify media by tool name
17
+ ([#3202](https://github.com/f5-sales-demo/xcsh/issues/3202)).
18
+
5
19
  ## [20.6.3] - 2026-08-07
6
20
 
7
21
  ### Improved
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.1",
4
+ "version": "20.19.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.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",
64
+ "@f5-sales-demo/pi-agent-core": "20.19.1",
65
+ "@f5-sales-demo/pi-ai": "20.19.1",
66
+ "@f5-sales-demo/pi-natives": "20.19.1",
67
+ "@f5-sales-demo/pi-resource-management": "20.19.1",
68
+ "@f5-sales-demo/pi-tui": "20.19.1",
69
+ "@f5-sales-demo/pi-utils": "20.19.1",
70
+ "@f5-sales-demo/xcsh-stats": "20.19.1",
71
71
  "@mozilla/readability": "^0.6",
72
72
  "@sinclair/typebox": "^0.34",
73
73
  "@xterm/headless": "^6.0",
@@ -891,7 +891,8 @@
891
891
  "const": "tool"
892
892
  },
893
893
  "source": {
894
- "const": "display_media"
894
+ "type": "string",
895
+ "pattern": "^[a-z][a-z0-9_]{0,63}$"
895
896
  }
896
897
  }
897
898
  },
@@ -942,6 +943,23 @@
942
943
  },
943
944
  "degradation": {
944
945
  "type": "string"
946
+ },
947
+ "filenameHint": {
948
+ "type": "string",
949
+ "minLength": 1,
950
+ "maxLength": 255,
951
+ "pattern": "^[^/\\\\]+$"
952
+ },
953
+ "metadata": {
954
+ "type": "object",
955
+ "maxProperties": 16,
956
+ "propertyNames": {
957
+ "pattern": "^[a-zA-Z0-9_.-]{1,64}$"
958
+ },
959
+ "additionalProperties": {
960
+ "type": "string",
961
+ "maxLength": 512
962
+ }
945
963
  }
946
964
  }
947
965
  }
@@ -334,15 +334,13 @@ 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") {
338
- const descriptor = extractMediaDescriptorFromToolResult(event.result);
339
- if (descriptor) {
340
- this.#server.send({
341
- type: "chat_media",
342
- id: chat.id,
343
- media: projectMediaDescriptorForTransport(descriptor),
344
- } satisfies ChatMedia);
345
- }
337
+ const descriptor = extractMediaDescriptorFromToolResult(event.result);
338
+ if (descriptor) {
339
+ this.#server.send({
340
+ type: "chat_media",
341
+ id: chat.id,
342
+ media: projectMediaDescriptorForTransport(descriptor),
343
+ } satisfies ChatMedia);
346
344
  }
347
345
  // ToolExecutionEndEvent carries `isError` (NOT `error`) — checking the wrong
348
346
  // field made this always ok:true, so errored tools rendered ✓ and "failed"
@@ -16,7 +16,6 @@ import {
16
16
  type ModelRefreshStrategy,
17
17
  type OAuthCredentials,
18
18
  type OAuthLoginCallbacks,
19
- openaiCodexModelManagerOptions,
20
19
  PROVIDER_DESCRIPTORS,
21
20
  readModelCache,
22
21
  registerCustomApi,
@@ -32,7 +31,7 @@ import { type ConfigError, ConfigFile } from "../config";
32
31
  import { hasLiteLLMEnv, probeAndUpgradeLiteLLMConfig, startupHealthCheck } from "../config/auto-config";
33
32
  import { parseModelString, resolveProviderModelReference } from "../config/model-resolver";
34
33
  import { isValidThemeColor, type ThemeColor } from "../modes/theme/theme";
35
- import type { AuthStorage, OAuthCredential } from "../session/auth-storage";
34
+ import type { AuthStorage } from "../session/auth-storage";
36
35
  import {
37
36
  buildCanonicalModelIndex,
38
37
  type CanonicalModelIndex,
@@ -553,31 +552,6 @@ function extractGoogleOAuthToken(value: string | undefined): string | undefined
553
552
  return value;
554
553
  }
555
554
 
556
- function getOAuthCredentialsForProvider(authStorage: AuthStorage, provider: string): OAuthCredential[] {
557
- const providerEntry = authStorage.getAll()[provider];
558
- if (!providerEntry) {
559
- return [];
560
- }
561
- const entries = Array.isArray(providerEntry) ? providerEntry : [providerEntry];
562
- return entries.filter((entry): entry is OAuthCredential => entry.type === "oauth");
563
- }
564
-
565
- function resolveOAuthAccountIdForAccessToken(
566
- authStorage: AuthStorage,
567
- provider: string,
568
- accessToken: string,
569
- ): string | undefined {
570
- const oauthCredentials = getOAuthCredentialsForProvider(authStorage, provider);
571
- const matchingCredential = oauthCredentials.find(credential => credential.access === accessToken);
572
- if (matchingCredential) {
573
- return matchingCredential.accountId;
574
- }
575
- if (oauthCredentials.length === 1) {
576
- return oauthCredentials[0].accountId;
577
- }
578
- return undefined;
579
- }
580
-
581
555
  function mergeCompat(
582
556
  baseCompat: Model<Api>["compat"],
583
557
  overrideCompat: ModelOverride["compat"],
@@ -1416,17 +1390,6 @@ export class ModelRegistry {
1416
1390
  endpoint: this.getProviderBaseUrl("google-gemini-cli"),
1417
1391
  }),
1418
1392
  },
1419
- {
1420
- providerId: "openai-codex",
1421
- resolveKey: value => value,
1422
- createOptions: accessToken => {
1423
- const accountId = resolveOAuthAccountIdForAccessToken(this.authStorage, "openai-codex", accessToken);
1424
- return openaiCodexModelManagerOptions({
1425
- accessToken,
1426
- accountId,
1427
- });
1428
- },
1429
- },
1430
1393
  ];
1431
1394
  const peekKey = (descriptor: { providerId: string }) => this.#peekApiKeyForProvider(descriptor.providerId);
1432
1395
  // Special providers discover entitlement-scoped models through OAuth. Refresh their
@@ -1049,6 +1049,9 @@ export interface InitialModelResult {
1049
1049
  fallbackMessage: string | undefined;
1050
1050
  }
1051
1051
 
1052
+ export const UNSUPPORTED_OPENAI_CODEX_RECOVERY =
1053
+ "Saved OpenAI Codex subscription configuration is unsupported in xcsh. Use the official codex CLI for ChatGPT subscription access, set OPENAI_API_KEY for usage-based OpenAI API access in xcsh, select another provider, or remove the disabled legacy credential with /logout openai-codex.";
1054
+
1052
1055
  /**
1053
1056
  * Find the initial model to use based on priority:
1054
1057
  * 1. CLI args (provider + model)
@@ -1109,7 +1112,8 @@ export async function findInitialModel(options: {
1109
1112
  }
1110
1113
 
1111
1114
  // 3. Try saved default from settings
1112
- if (defaultProvider && defaultModelId) {
1115
+ const hasUnsupportedOpenAICodexDefault = defaultProvider === "openai-codex";
1116
+ if (defaultProvider && defaultModelId && !hasUnsupportedOpenAICodexDefault) {
1113
1117
  const found = modelRegistry.find(defaultProvider, defaultModelId);
1114
1118
  if (found) {
1115
1119
  model = found;
@@ -1127,16 +1131,28 @@ export async function findInitialModel(options: {
1127
1131
  const defaultId = defaultModelPerProvider[provider];
1128
1132
  const match = availableModels.find(m => m.provider === provider && m.id === defaultId);
1129
1133
  if (match) {
1130
- return { model: match, thinkingLevel: undefined, fallbackMessage: undefined };
1134
+ return {
1135
+ model: match,
1136
+ thinkingLevel: undefined,
1137
+ fallbackMessage: hasUnsupportedOpenAICodexDefault ? UNSUPPORTED_OPENAI_CODEX_RECOVERY : undefined,
1138
+ };
1131
1139
  }
1132
1140
  }
1133
1141
 
1134
1142
  // If no default found, use first available
1135
- return { model: availableModels[0], thinkingLevel: undefined, fallbackMessage: undefined };
1143
+ return {
1144
+ model: availableModels[0],
1145
+ thinkingLevel: undefined,
1146
+ fallbackMessage: hasUnsupportedOpenAICodexDefault ? UNSUPPORTED_OPENAI_CODEX_RECOVERY : undefined,
1147
+ };
1136
1148
  }
1137
1149
 
1138
1150
  // 5. No model found
1139
- return { model: undefined, thinkingLevel: undefined, fallbackMessage: undefined };
1151
+ return {
1152
+ model: undefined,
1153
+ thinkingLevel: undefined,
1154
+ fallbackMessage: hasUnsupportedOpenAICodexDefault ? UNSUPPORTED_OPENAI_CODEX_RECOVERY : undefined,
1155
+ };
1140
1156
  }
1141
1157
 
1142
1158
  /**
@@ -564,7 +564,7 @@ export const SETTINGS_SCHEMA = {
564
564
 
565
565
  "routing.profile": {
566
566
  type: "enum",
567
- values: ["none", "google-antigravity", "openai-codex"] as const,
567
+ values: ["none", "google-antigravity"] as const,
568
568
  default: "none",
569
569
  ui: {
570
570
  tab: "model",
@@ -1988,7 +1988,6 @@ export const SETTINGS_SCHEMA = {
1988
1988
  "perplexity",
1989
1989
  "anthropic",
1990
1990
  "gemini",
1991
- "codex",
1992
1991
  "tavily",
1993
1992
  "kagi",
1994
1993
  "synthetic",
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "20.18.1",
21
- "commit": "05ebcdc9d4b43f54c4e54ff44c52229b34e62a6b",
22
- "shortCommit": "05ebcdc",
20
+ "version": "20.19.1",
21
+ "commit": "85fec653171dd194403a9444e937285f47f5227b",
22
+ "shortCommit": "85fec65",
23
23
  "branch": "main",
24
- "tag": "v20.18.1",
25
- "commitDate": "2026-08-15T13:25:53Z",
26
- "buildDate": "2026-08-15T13:57:09.805Z",
24
+ "tag": "v20.19.1",
25
+ "commitDate": "2026-08-15T22:14:41Z",
26
+ "buildDate": "2026-08-15T22:42:30.318Z",
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/05ebcdc9d4b43f54c4e54ff44c52229b34e62a6b",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.18.1"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/85fec653171dd194403a9444e937285f47f5227b",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v20.19.1"
33
33
  };