@f5-sales-demo/xcsh 21.42.0 → 21.43.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
@@ -6,6 +6,10 @@
6
6
 
7
7
  ### Added
8
8
 
9
+ - Added current ChatGPT subscription roles for GPT-6 Luna/Sol, Claude Opus 5.5 selection, and an
10
+ opt-in Providers setting for the GPT-6 1.05M-token context window. The default remains 272K to
11
+ make long-context pricing explicit; LiteLLM retains its existing catalog
12
+ ([#4240](https://github.com/f5-sales-demo/xcsh/issues/4240)).
9
13
  - Added owner-scoped, capability-filtered plugin advisories that render machine-readable provenance,
10
14
  fail open on matcher errors, and refresh with plugin lifecycle changes
11
15
  ([#4175](https://github.com/f5-sales-demo/xcsh/issues/4175)).
@@ -53,6 +57,10 @@
53
57
 
54
58
  ### Fixed
55
59
 
60
+ - Added the exact `/plugin setup <plugin>` next action after interactive installation of plugins
61
+ that require separately authorized setup ([#4253](https://github.com/f5-sales-demo/xcsh/issues/4253)).
62
+ - Made marketplace plugin uninstall dry-runs return a deterministic preview without changing the
63
+ installed registry or cache ([#4251](https://github.com/f5-sales-demo/xcsh/issues/4251)).
56
64
  - Routed Platform plugin setup through the native interactive context wizard, rejected empty or
57
65
  mixed setup plans, and made generated API catalogs enforce the `XCSH_*`-only environment contract
58
66
  ([#4234](https://github.com/f5-sales-demo/xcsh/issues/4234)).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/xcsh",
4
- "version": "21.42.0",
4
+ "version": "21.43.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",
@@ -64,13 +64,13 @@
64
64
  },
65
65
  "dependencies": {
66
66
  "@agentclientprotocol/sdk": "1.4.0",
67
- "@f5-sales-demo/pi-agent-core": "21.42.0",
68
- "@f5-sales-demo/pi-ai": "21.42.0",
69
- "@f5-sales-demo/pi-natives": "21.42.0",
70
- "@f5-sales-demo/pi-resource-management": "21.42.0",
71
- "@f5-sales-demo/pi-tui": "21.42.0",
72
- "@f5-sales-demo/pi-utils": "21.42.0",
73
- "@f5-sales-demo/xcsh-stats": "21.42.0",
67
+ "@f5-sales-demo/pi-agent-core": "21.43.1",
68
+ "@f5-sales-demo/pi-ai": "21.43.1",
69
+ "@f5-sales-demo/pi-natives": "21.43.1",
70
+ "@f5-sales-demo/pi-resource-management": "21.43.1",
71
+ "@f5-sales-demo/pi-tui": "21.43.1",
72
+ "@f5-sales-demo/pi-utils": "21.43.1",
73
+ "@f5-sales-demo/xcsh-stats": "21.43.1",
74
74
  "@mozilla/readability": "^0.6",
75
75
  "@sinclair/typebox": "0.34.52",
76
76
  "@tobilu/qmd": "2.8.3",
@@ -773,7 +773,7 @@ async function handleInstall(
773
773
  async function handleUninstall(
774
774
  manager: PluginManager,
775
775
  packages: string[],
776
- flags: { json?: boolean; scope?: "user" | "project" },
776
+ flags: { json?: boolean; dryRun?: boolean; scope?: "user" | "project" },
777
777
  ): Promise<void> {
778
778
  if (packages.length === 0) {
779
779
  console.error(chalk.red(`Usage: ${APP_NAME} plugin uninstall <package> ...`));
@@ -791,8 +791,30 @@ async function handleUninstall(
791
791
  if (installedPlugins.has(name) || target.type === "marketplace") {
792
792
  // Exact match against installed marketplace plugin IDs (name@marketplace)
793
793
  try {
794
+ if (flags.dryRun) {
795
+ const preview = await mktMgr.previewUninstallPlugin(name, flags.scope);
796
+ if (flags.json) {
797
+ console.log(
798
+ JSON.stringify(
799
+ {
800
+ action: "uninstall",
801
+ target: preview.pluginId,
802
+ scope: preview.scope,
803
+ dryRun: true,
804
+ installPaths: preview.installPaths,
805
+ },
806
+ null,
807
+ 2,
808
+ ),
809
+ );
810
+ } else {
811
+ console.log(chalk.dim(`[dry-run] Would uninstall ${preview.pluginId} (${preview.scope})`));
812
+ }
813
+ continue;
814
+ }
794
815
  await mktMgr.uninstallPlugin(name, flags.scope);
795
- console.log(chalk.green(`${theme.status.success} Uninstalled ${name}`));
816
+ if (flags.json) console.log(JSON.stringify({ uninstalled: name }));
817
+ else console.log(chalk.green(`${theme.status.success} Uninstalled ${name}`));
796
818
  } catch (err) {
797
819
  console.error(chalk.red(`${theme.status.error} Failed to uninstall ${name}: ${err}`));
798
820
  process.exit(1);
@@ -1306,8 +1328,8 @@ ${chalk.bold("Options:")}
1306
1328
  --json Output as JSON
1307
1329
  --fix Attempt automatic fixes (doctor)
1308
1330
  --force Overwrite without prompting (install)
1309
- --scope <scope> Install scope: user (default) or project (install name@marketplace)
1310
- --dry-run Preview changes without applying (install)
1331
+ --scope <scope> Marketplace install/uninstall scope: user (default) or project
1332
+ --dry-run Preview supported install, uninstall, or upgrade changes
1311
1333
  -l, --local Use project-local overrides
1312
1334
 
1313
1335
  ${chalk.bold("Examples:")}
@@ -11,7 +11,7 @@ function compareVersions(left: string, right: string): number {
11
11
  }
12
12
 
13
13
  /** Keep historical catalogs available while presenting only current user-facing families. */
14
- const DEFAULT_OPENAI_CODEX_MODEL_IDS = new Set(["gpt-5.6-luna", "gpt-5.6-terra", "gpt-5.6-sol", "gpt-6-astra"]);
14
+ const DEFAULT_OPENAI_CODEX_MODEL_IDS = new Set(["gpt-5.6-terra", "gpt-6-astra", "gpt-6-luna", "gpt-6-sol"]);
15
15
 
16
16
  /** Shared catalog boundary for the TUI and attached human interfaces. */
17
17
  export function filterCurrentBrowserModels(models: readonly Model[]): Model[] {
@@ -50,6 +50,10 @@ export type { CanonicalModelIndex, CanonicalModelRecord, CanonicalModelVariant,
50
50
 
51
51
  export const kNoAuth = NO_AUTH_API_KEY;
52
52
 
53
+ const OPENAI_CODEX_STANDARD_CONTEXT_WINDOW = 272_000;
54
+ const OPENAI_CODEX_MAX_CONTEXT_WINDOW = 1_050_000;
55
+ const OPENAI_CODEX_MAX_CONTEXT_MODEL_IDS = new Set(["gpt-6-luna", "gpt-6-sol"]);
56
+
53
57
  export function isAuthenticated(apiKey: string | undefined | null): apiKey is string {
54
58
  return Boolean(apiKey) && apiKey !== kNoAuth;
55
59
  }
@@ -871,6 +875,7 @@ export class ModelRegistry {
871
875
  #lastDiscoveryWarnings: Map<string, string> = new Map();
872
876
  #hasProbed = false;
873
877
  #refreshQueue: Promise<void> = Promise.resolve();
878
+ #openAICodexMaxContext = false;
874
879
 
875
880
  #enqueueRefresh(operation: () => Promise<void>): Promise<void> {
876
881
  const pending = this.#refreshQueue.then(operation);
@@ -890,7 +895,10 @@ export class ModelRegistry {
890
895
  constructor(
891
896
  readonly authStorage: AuthStorage,
892
897
  modelsPath?: string,
893
- private readonly options: { getProviderOrder?: () => readonly string[] } = {},
898
+ private readonly options: {
899
+ getProviderOrder?: () => readonly string[];
900
+ getOpenAICodexMaxContext?: () => boolean;
901
+ } = {},
894
902
  ) {
895
903
  this.#modelsConfigFile = ModelsConfigFile.relocate(modelsPath);
896
904
  this.#cacheDbPath = modelsPath ? path.join(path.dirname(modelsPath), "models.db") : undefined;
@@ -1042,6 +1050,7 @@ export class ModelRegistry {
1042
1050
  }
1043
1051
 
1044
1052
  #loadModels() {
1053
+ this.#openAICodexMaxContext = this.options.getOpenAICodexMaxContext?.() ?? this.#openAICodexMaxContext;
1045
1054
  // Load custom models from models.json first (to know which providers to override)
1046
1055
  const {
1047
1056
  models: customModels = [],
@@ -1075,6 +1084,25 @@ export class ModelRegistry {
1075
1084
  const combined = this.#mergeCustomModels(withConfigModels, this.#runtimeModelOverlays);
1076
1085
 
1077
1086
  this.#models = this.#applyProviderModelAllowlists(this.#applyModelOverrides(combined, this.#modelOverrides));
1087
+ this.#applyOpenAICodexContextWindow();
1088
+ this.#rebuildCanonicalIndex();
1089
+ }
1090
+
1091
+ #applyOpenAICodexContextWindow(): void {
1092
+ const contextWindow = this.#openAICodexMaxContext
1093
+ ? OPENAI_CODEX_MAX_CONTEXT_WINDOW
1094
+ : OPENAI_CODEX_STANDARD_CONTEXT_WINDOW;
1095
+ for (const model of this.#models) {
1096
+ if (model.provider === "openai-codex" && OPENAI_CODEX_MAX_CONTEXT_MODEL_IDS.has(model.id)) {
1097
+ model.contextWindow = contextWindow;
1098
+ }
1099
+ }
1100
+ }
1101
+
1102
+ /** Update GPT-6 subscription context limits without rebuilding the registry. */
1103
+ setOpenAICodexMaxContext(enabled: boolean): void {
1104
+ this.#openAICodexMaxContext = enabled;
1105
+ this.#applyOpenAICodexContextWindow();
1078
1106
  this.#rebuildCanonicalIndex();
1079
1107
  }
1080
1108
 
@@ -2102,6 +2102,17 @@ export const SETTINGS_SCHEMA = {
2102
2102
  },
2103
2103
  },
2104
2104
 
2105
+ "providers.openaiCodexMaxContext": {
2106
+ type: "boolean",
2107
+ default: false,
2108
+ ui: {
2109
+ tab: "providers",
2110
+ label: "OpenAI Codex Maximum Context",
2111
+ description:
2112
+ "Use the 1.05M-token context window for GPT-6 Luna and Sol (long-context pricing applies above 272K)",
2113
+ },
2114
+ },
2115
+
2105
2116
  "providers.parallelFetch": {
2106
2117
  type: "boolean",
2107
2118
  default: true,
@@ -88,6 +88,12 @@ export interface PluginDependencyPlanItem {
88
88
  dependency: boolean;
89
89
  }
90
90
 
91
+ export interface PluginUninstallPreview {
92
+ pluginId: string;
93
+ scope: "user" | "project";
94
+ installPaths: string[];
95
+ }
96
+
91
97
  function resolvePluginDependencyNames(catalog: MarketplaceCatalog, root: string): string[] {
92
98
  const plugins = new Map(catalog.plugins.map(plugin => [plugin.name, plugin]));
93
99
  const state = new Map<string, "visiting" | "visited">();
@@ -691,7 +697,7 @@ export class MarketplaceManager {
691
697
  return "0.0.0";
692
698
  }
693
699
 
694
- async uninstallPlugin(pluginId: string, scope?: "user" | "project"): Promise<void> {
700
+ async #resolvePluginUninstall(pluginId: string, scope?: "user" | "project") {
695
701
  const parsed = parsePluginId(pluginId);
696
702
  if (!parsed) {
697
703
  throw new Error(`Invalid plugin ID format: "${pluginId}". Expected "name@marketplace".`);
@@ -731,6 +737,23 @@ export class MarketplaceManager {
731
737
  const targetReg = targetScope === "project" ? projectReg : userReg;
732
738
  const registryPath = this.#registryPath(targetScope);
733
739
  await this.#assertNoInstalledDependents(pluginId, targetReg);
740
+ return { targetEntries, targetReg, targetScope, registryPath };
741
+ }
742
+
743
+ async previewUninstallPlugin(pluginId: string, scope?: "user" | "project"): Promise<PluginUninstallPreview> {
744
+ const { targetEntries, targetScope } = await this.#resolvePluginUninstall(pluginId, scope);
745
+ return {
746
+ pluginId,
747
+ scope: targetScope,
748
+ installPaths: targetEntries.map(entry => entry.installPath),
749
+ };
750
+ }
751
+
752
+ async uninstallPlugin(pluginId: string, scope?: "user" | "project"): Promise<void> {
753
+ const { targetEntries, targetReg, targetScope, registryPath } = await this.#resolvePluginUninstall(
754
+ pluginId,
755
+ scope,
756
+ );
734
757
 
735
758
  const updatedReg = removeInstalledPlugin(targetReg, pluginId);
736
759
  await writeInstalledPluginsRegistry(registryPath, updatedReg);
@@ -26,6 +26,14 @@ export function describeIntegrationSetupNextAction(
26
26
  : `xcsh plugin setup ${target}`;
27
27
  }
28
28
 
29
+ export function describeInteractiveInstallSetupNextAction(
30
+ plugin: string,
31
+ lifecycle: { readonly setupRequired: boolean; readonly setupAuthorization?: "separate" | "install" },
32
+ ): string | undefined {
33
+ if (!lifecycle.setupRequired || (lifecycle.setupAuthorization ?? "separate") === "install") return undefined;
34
+ return `/plugin setup ${plugin}`;
35
+ }
36
+
29
37
  export function describeInstallSetupOutcome(
30
38
  plugin: string,
31
39
  status: Pick<IntegrationSnapshot<unknown>, "state" | "reason">,
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "21.42.0",
21
- "commit": "3c71f7719e8cfdb4b16c058a5630bb9b90d3172b",
22
- "shortCommit": "3c71f77",
20
+ "version": "21.43.1",
21
+ "commit": "52977a8638fa3f0543c64d1ca887c7568e7846d4",
22
+ "shortCommit": "52977a8",
23
23
  "branch": "main",
24
- "tag": "v21.42.0",
25
- "commitDate": "2026-09-23T23:38:33+00:00",
26
- "buildDate": "2026-09-24T00:42:04.451Z",
24
+ "tag": "v21.43.1",
25
+ "commitDate": "2026-09-24T03:08:49+00:00",
26
+ "buildDate": "2026-09-24T04:17:08.314Z",
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/3c71f7719e8cfdb4b16c058a5630bb9b90d3172b",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v21.42.0"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/52977a8638fa3f0543c64d1ca887c7568e7846d4",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v21.43.1"
33
33
  };
@@ -42,7 +42,7 @@ export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
42
42
  "en/getting-started/first-manifest.mdx": "---\ntitle: \"Complete your first manifest lifecycle\"\ndescription: \"Validate, compare, apply, inspect, export, and delete one resource manifest.\"\nsidebar:\n order: 5\n label: \"First manifest\"\nhead:\n - tag: style\n content: |\n .sl-markdown-content .expressive-code { max-width: 100%; overflow-x: auto; }\n .sl-markdown-content table { display: block; max-width: 100%; overflow-x: auto; }\n---\n\nA manifest names one F5 Distributed Cloud resource with `kind`, `metadata`, and `spec`. Begin from an exported or catalog-backed example for the exact resource kind; do not invent schema fields. This page walks one resource from local validation to proven deletion, so run it against a lab namespace you are authorized to change.\n\n## How do I check a manifest without credentials?\n\n```bash\nxcsh validate -f manifest.yaml --result-file validation.json\n```\n\nValidation reads the file locally and returns a nonzero status for malformed or unsupported input. Review the aggregate JavaScript Object Notation (JSON) report before moving to a live context.\n\n## How do I preview the live change?\n\n```bash\nxcsh diff -f manifest.yaml --result-file diff.json\nxcsh apply -f manifest.yaml --dry-run client --result-file dry-run.json\n```\n\nA diff requires the intended context. A dry run calculates the mutation path without applying it. Read every create, update, and preserve entry before you continue.\n\n## How do I apply and verify the resource?\n\n```bash\nxcsh apply -f manifest.yaml --result-file apply.json\nxcsh get <KIND> <NAME> -n <NAMESPACE> --result-file get.json\n```\n\nCompare the identity and the fields you set in `get.json` against the manifest. A zero exit status records that the request was accepted; only the retrieved object records the resulting state.\n\n## How do I export and remove it?\n\n```bash\nxcsh export <KIND> <NAME> -n <NAMESPACE> -f exported.yaml\nxcsh delete <KIND> <NAME> -n <NAMESPACE> --result-file delete.json\nxcsh get <KIND> <NAME> -n <NAMESPACE>\n```\n\nSanitize server-managed metadata out of `exported.yaml` before you store it. The closing `get` must return the not-found response for that kind; a delete request without the absence check leaves the lifecycle unfinished.\n",
43
43
  "en/getting-started/index.mdx": "---\ntitle: \"Getting started\"\ndescription: \"Install xcsh, connect a model and an F5 Distributed Cloud tenant, and complete a safe first workflow.\"\nsidebar:\n order: 0\n label: \"Overview\"\n---\n\nUse this section to reach the first useful command without configuring every optional integration.\n\n## What do I need before I begin?\n\nYou need a supported xcsh build and one model provider. F5 Distributed Cloud credentials are needed only for live resource commands; local manifest validation works without them.\n\n## Which path matches my goal?\n\n1. [Install, update, or remove xcsh](/xcsh/en/#install-xcsh).\n2. [Authenticate a model](/xcsh/en/getting-started/model-authentication/), which the quickstart requires.\n3. Run the [general quickstart](/xcsh/en/#quickstart).\n4. Connect an [F5 Distributed Cloud context](/xcsh/en/f5-distributed-cloud/contexts-namespaces/) when you intend to reach a tenant.\n5. Complete [your first manifest lifecycle](/xcsh/en/getting-started/first-manifest/) against a lab namespace you are authorized to change.\n",
44
44
  "en/getting-started/model-authentication.mdx": "---\ntitle: \"Authenticate a model provider\"\ndescription: \"Configure an API key or supported subscription login without placing credentials in project files.\"\nsidebar:\n order: 2\n label: \"Model authentication\"\nhead:\n - tag: style\n content: |\n .sl-markdown-content .expressive-code { max-width: 100%; overflow-x: auto; }\n .sl-markdown-content table { display: block; max-width: 100%; overflow-x: auto; }\n---\n\nModel credentials belong in the provider-supported environment or subscription login, not in prompts, settings committed to a repository, or command arguments.\n\n## Which authentication method should I choose?\n\nUse a provider application programming interface (API) key for service-style automation. Use a supported subscription login for an interactive user session. Run `xcsh --list-models <PROVIDER>` after authentication to confirm the credential can enumerate models.\n\n## How do I select a model explicitly?\n\n```bash\nxcsh --model p-openai/gpt-5.2 --no-tools -p \"Summarize README.md\"\n```\n\nReplace the example with a model shown by your installed build. Provider-qualified names avoid an accidental fuzzy match when several providers expose similar model names.\n\nFor Anthropic, either complete `/login anthropic` with a Claude subscription or export\n`ANTHROPIC_API_KEY` for direct API billing. `--model fable` and `--model anthropic/fable` are exact\naliases for `anthropic/claude-fable-5-1`; use `anthropic/claude-fable-5` when you specifically need\nthe earlier Fable 5 model. Fable access depends on the selected account's entitlement.\n\nStart xcsh, enter `/login`, and choose only the provider you intend to use. Complete the\nprovider-owned sign-in flow, return to the model picker, and select an explicit model.\nAuthentication may store a refresh token or subscription session outside the repository; a prompt\nnever needs the credential value. Send a no-tool prompt, inspect the selected provider and model,\nthen use `/logout` when the account must not remain available on that workstation.\n",
45
- "en/index.mdx": "---\ntitle: xcsh\ndescription: Install xcsh, authenticate a model provider, and begin a reviewable terminal or F5 Distributed Cloud workflow.\ntemplate: splash\neditUrl: false\nsidebar:\n hidden: true\n order: 0\nhead:\n - tag: style\n content: |\n main:has(.landing-hero) > .content-panel:first-of-type { padding-block-end: .5rem; }\n main:has(.landing-hero) > .content-panel:first-of-type + .content-panel { border-top: 0; padding-block-start: 0; }\n .landing-hero { display: grid; gap: clamp(2rem, 4vw, 4rem); grid-template-columns: minmax(0, 1fr) minmax(18rem, 35rem); align-items: center; margin-block: .75rem 2rem; }\n .landing-hero__content, .landing-hero__image, .landing-installer, .landing-installer .expressive-code, .landing-command { min-width: 0; }\n h1#_top { max-width: 13ch; margin-block-end: 0; text-wrap: balance; }\n .landing-hero__lede { max-width: 42rem; color: var(--sl-color-gray-2); font-size: var(--sl-text-lg); }\n .landing-installer { margin-block: 0 4rem; padding: clamp(1rem, 2vw, 1.5rem); border: 1px solid var(--sl-color-gray-5); border-radius: .75rem; background: var(--sl-color-bg-nav); }\n .landing-installer h2 { margin: 0; font-size: var(--sl-text-lg); }\n .landing-installer p { margin-block: .5rem 0; }\n .landing-installer pre { max-width: 100%; overflow-x: auto; }\n .landing-installer .expressive-code .ec-line .code { padding-inline-end: 3.5rem; white-space: pre; overflow-wrap: normal; }\n .landing-installer .expressive-code .copy button { opacity: 1; }\n .landing-hero__image { margin: 0; }\n .landing-hero__image img { display: block; width: 100%; height: auto; aspect-ratio: 1442 / 1268; object-fit: contain; filter: drop-shadow(0 1rem 2.5rem color-mix(in srgb, var(--sl-color-accent) 28%, transparent)); }\n .landing-grid { display: grid; gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-block: 1.5rem; }\n .landing-explore { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n details.landing-disclosure { margin-block: 1rem 0; padding: .75rem 1rem; border: 1px solid var(--sl-color-gray-5); border-radius: .5rem; background: var(--sl-color-bg-nav); }\n details.landing-disclosure summary { cursor: pointer; font-weight: 600; }\n :is(.landing-hero, .landing-installer, .landing-grid, .landing-disclosure) :is(a, button, summary):focus-visible { outline: 2px solid var(--sl-color-accent-high); outline-offset: 3px; }\n @media (max-width: 50rem) { .landing-hero { grid-template-columns: minmax(0, 1fr); gap: 2rem; margin-block: .5rem 2rem; } .landing-installer { margin-block-end: 3rem; padding: 1rem; } .landing-grid { grid-template-columns: minmax(0, 1fr); } }\n---\n\nimport { Aside, Card, LinkCard, TabItem, Tabs } from '@astrojs/starlight/components';\n\n<section class=\"landing-hero\" aria-labelledby=\"_top\">\n <div class=\"landing-hero__content\">\n <p class=\"landing-hero__lede\">An AI-native terminal assistant for engineering, automation, and reviewable F5 Distributed Cloud workflows.</p>\n <p>xcsh is an independent open-source project derived from pi/pi-mono, specialized for F5 Distributed Cloud workflows; it is not an F5 product.</p>\n </div>\n\n <figure class=\"landing-hero__image\">\n <img src=\"/xcsh/images/xcsh-ghostty-terminal.png\" width=\"1442\" height=\"1268\" alt=\"xcsh running in a Ghostty terminal with the model selector, prompt, and session status visible.\" />\n </figure>\n</section>\n\n<section class=\"landing-installer\" aria-labelledby=\"install-xcsh\">\n\n## Install xcsh\n\n <p>Universal installer for macOS and Linux.</p>\n\n ```bash\n curl -fsSL https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/scripts/install.sh | sh\n ```\n\n <p>It installs the latest prebuilt release into <code>~/.local/bin</code>. Need a managed or platform-specific channel? Compare the <a href=\"#installation-options\">installation options</a>.</p>\n</section>\n\n## What xcsh helps you do\n\n<div class=\"landing-grid landing-capabilities\">\n <Card title=\"Agentic terminal work\" icon=\"terminal\">\n Run interactive or print-mode prompts, inspect files, use tools, and keep durable session history when the task needs it. [Learn the agent loop](/xcsh/en/use-xcsh/agent-loop/).\n </Card>\n <Card title=\"Reviewable F5 Distributed Cloud workflows\" icon=\"document\">\n Discover schemas, validate manifests, and inspect proposed differences before an authorized resource change. [Use resource workflows](/xcsh/en/f5-distributed-cloud/).\n </Card>\n <Card title=\"Extensible automation\" icon=\"puzzle\">\n Add headless workflows, custom tools, skills, plugins, or MCP servers when built-in commands are not enough. [Automate and extend](/xcsh/en/automate-extend/).\n </Card>\n</div>\nThese workflows start with a working executable; choose another channel only when the universal installer is not the right fit.\n\n## Installation options\n\nUse one channel for install and upgrades. Mixing package-manager and standalone installations can leave more than one `xcsh` on `PATH`; the universal installer above is not repeated here.\n\n<Tabs syncKey=\"install-platform\">\n<TabItem label=\"macOS\" icon=\"seti:apple\">\nInstall the signed and notarized macOS archive through the Homebrew cask. The cask preserves the released executable and native addon byte for byte and does not require `sudo`:\n\n```bash\nbrew install --cask f5-sales-demo/tap/xcsh\n```\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nUpgrade with `brew upgrade --cask xcsh`. Remove the cask with `brew uninstall --cask xcsh`. These commands preserve configuration, credentials, and sessions under `~/.xcsh`.\n</details>\n\n<Aside type=\"caution\" title=\"Clean break from the historical package cask\">\nBefore installing this cask on a Mac that received an earlier xcsh package,\nuninstall both old Homebrew entries (`brew uninstall --formula xcsh` and\n`brew uninstall --cask xcsh`). Then have MDM forget the `com.f5.xcsh` receipt\nand remove only the package-owned `/usr/local/bin/xcsh` and\n`/Library/Application Support/xcsh` payload. Do not remove `~/.xcsh`. The signed\nand stapled `.pkg` release assets remain available only for direct MDM\ndeployment.\n</Aside>\n</TabItem>\n\n<TabItem label=\"Ubuntu or Debian\" icon=\"seti:ubuntu\">\nThe signed apt repository supports amd64 and arm64 and follows normal system upgrades:\n\n```bash\nsudo install -d -m 0755 /etc/apt/keyrings\ncurl -fsSL https://f5-sales-demo.github.io/apt-repo/f5xc-archive-keyring.gpg \\\n | sudo tee /etc/apt/keyrings/f5xc-archive-keyring.gpg >/dev/null\necho \"deb [arch=amd64,arm64 signed-by=/etc/apt/keyrings/f5xc-archive-keyring.gpg] https://f5-sales-demo.github.io/apt-repo stable main\" \\\n | sudo tee /etc/apt/sources.list.d/f5xc.list\nsudo apt-get update && sudo apt-get install xcsh\n```\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nUpgrade with `sudo apt-get update && sudo apt-get install --only-upgrade xcsh`. Remove the package with `sudo apt-get remove xcsh`.\n</details>\n</TabItem>\n\n<TabItem label=\"Windows\" icon=\"seti:windows\">\nRun the PowerShell installer, then restart the terminal so its user `PATH` refreshes:\n\n```powershell\nirm https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/scripts/install.ps1 | iex\n```\n\nIt installs `xcsh.exe` and native add-ons to `%LOCALAPPDATA%\\\\xcsh`. **Bash is required for tool-backed sessions.** Install Git for Windows, WSL, Cygwin, or MSYS2; set `shellPath` in `%USERPROFILE%\\\\.xcsh\\\\agent\\\\settings.json` when Bash is elsewhere.\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nRe-run the installer to upgrade. To uninstall, remove `%LOCALAPPDATA%\\\\xcsh` and its entry from the user `PATH`.\n</details>\n</TabItem>\n\n<TabItem label=\"Container\" icon=\"seti:docker\">\nDocker and Podman use the same multi-architecture image. Pin a release tag, resolve its digest for deployment, and mount only the workspace and state required by the task:\n\n```bash\ndocker pull ghcr.io/f5-sales-demo/xcsh:vX.Y.Z\ndocker image inspect --format '{{index .RepoDigests 0}}' ghcr.io/f5-sales-demo/xcsh:vX.Y.Z\ndocker run --rm ghcr.io/f5-sales-demo/xcsh@sha256:<digest> --version\n```\n\nPodman accepts the same pull, inspect, and run arguments. Pass provider credentials at runtime through a secret manager or environment file; never bake them into an image layer.\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nPull a newer pinned tag to upgrade. Remove an unused image with `docker image rm IMAGE` or `podman image rm IMAGE`.\n</details>\n</TabItem>\n\n<TabItem label=\"Packages and source\" icon=\"seti:config\">\nUse a JavaScript package or a source/ref install when you need a toolchain or an unreleased ref. Source installs require Git and Bun 1.4.2 or newer:\n\n```bash\nbun install --global @f5-sales-demo/xcsh\nnpm install --global @f5-sales-demo/xcsh\ncurl -fsSL https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/scripts/install.sh \\\n | sh -s -- --source --ref vX.Y.Z\n```\n\nThe explicit `--source` and `--ref` arguments select a reproducible source install.\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nUpgrade with `bun update --global @f5-sales-demo/xcsh` or `npm update --global @f5-sales-demo/xcsh`. Remove the package with `bun remove --global @f5-sales-demo/xcsh` or `npm uninstall --global @f5-sales-demo/xcsh`; re-run the source command at a new ref to replace that channel.\n</details>\n</TabItem>\n</Tabs>\n\nWhichever installation channel you choose, open xcsh next.\n\n<span id=\"verification\" aria-hidden=\"true\"></span>\n\n## Verify installation\n\n<span id=\"verify-the-active-installation\" aria-hidden=\"true\"></span>\n\nStart the interactive terminal UI:\n\n<div class=\"landing-command\">\n\n```bash\nxcsh\n```\n\n</div>\n\nWhen the xcsh prompt appears, connect a model provider from inside the TUI.\n\n<span id=\"authentication\" aria-hidden=\"true\"></span>\n\n## Authenticate a provider\n\nAt the xcsh prompt, open the provider picker:\n\n<div class=\"landing-command\">\n\n```text\n/login\n```\n\n</div>\n\nChoose a provider and follow its sign-in flow. You can also enter `/login PROVIDER` to open a known provider directly. Keep credentials in the provider-supported environment or subscription login—never in a prompt or committed settings file. See [model authentication](/xcsh/en/getting-started/model-authentication/) for provider-specific options.\n\nAfter sign-in selects a model, stay in the TUI and send a small first prompt.\n\n## Quickstart\n\nAt the xcsh prompt, enter:\n\n<div class=\"landing-command\">\n\n```text\nReply with only: xcsh is ready\n```\n\n</div>\n\nA matching response confirms the installation, provider, and selected model are working together\nwithout granting a tool any file or network side effect. If it fails, verify the active executable\nwith `command -v xcsh`, reopen `/login`, and confirm the selected model is available to that\naccount. Next, learn the [interactive TUI](/xcsh/en/use-xcsh/interactive-tui/) or choose a [context and\nnamespace](/xcsh/en/f5-distributed-cloud/contexts-namespaces/) before an authorized F5 Distributed Cloud\nchange.\n\nFrom here, continue with the documentation path that matches your goal.\n\n<span id=\"exploration\" aria-hidden=\"true\"></span>\n\n## Explore by goal\n\nChoose the goal closest to your next task; each path starts from the verified installation above.\n\n<div class=\"landing-grid landing-explore\">\n <LinkCard title=\"Use xcsh\" icon=\"terminal\" href=\"./use-xcsh/\">Daily terminal use, tools, sessions, plans, and agents.</LinkCard>\n <LinkCard title=\"F5 Distributed Cloud\" icon=\"cloud\" href=\"./f5-distributed-cloud/\">Contexts, manifests, validation, and reviewable resource changes.</LinkCard>\n <LinkCard title=\"Configure and secure\" icon=\"setting\" href=\"./configure-secure/\">Providers, settings, secrets, and sandbox boundaries.</LinkCard>\n <LinkCard title=\"Automate and extend\" icon=\"puzzle\" href=\"./automate-extend/\">Headless modes, extensions, MCP, skills, plugins, and SDKs.</LinkCard>\n <LinkCard title=\"Integrations and deployment\" icon=\"rocket\" href=\"./integrations-deployment/\">Containers plus VS Code, Chrome, Office, and Herdr.</LinkCard>\n <LinkCard title=\"Reference and troubleshooting\" icon=\"information\" href=\"./reference-troubleshooting/\">Diagnostics, command reference, hotkeys, and configuration schema.</LinkCard>\n</div>\n",
45
+ "en/index.mdx": "---\ntitle: xcsh\ndescription: Install xcsh, authenticate a model provider, and begin a reviewable terminal or F5 Distributed Cloud workflow.\ntemplate: splash\neditUrl: false\nsidebar:\n hidden: true\n order: 0\nhead:\n - tag: style\n content: |\n main:has(.landing-hero) > .content-panel:first-of-type { padding-block-end: .5rem; }\n main:has(.landing-hero) > .content-panel:first-of-type + .content-panel { border-top: 0; padding-block-start: 0; }\n .landing-hero { display: grid; gap: clamp(2rem, 4vw, 4rem); grid-template-columns: minmax(0, 1fr) minmax(18rem, 35rem); align-items: center; margin-block: .75rem 2rem; }\n .landing-hero__content, .landing-hero__image, .landing-installer, .landing-installer .expressive-code, .landing-command { min-width: 0; }\n h1#_top { max-width: 13ch; margin-block-end: 0; text-wrap: balance; }\n .landing-hero__lede { max-width: 42rem; color: var(--sl-color-gray-2); font-size: var(--sl-text-lg); }\n .landing-installer { margin-block: 0 4rem; padding: clamp(1rem, 2vw, 1.5rem); border: 1px solid var(--sl-color-gray-5); border-radius: .75rem; background: var(--sl-color-bg-nav); }\n .landing-installer h2 { margin: 0; font-size: var(--sl-text-lg); }\n .landing-installer p { margin-block: .5rem 0; }\n .landing-installer pre { max-width: 100%; overflow-x: auto; }\n .landing-installer .expressive-code .ec-line .code { padding-inline-end: 3.5rem; white-space: pre; overflow-wrap: normal; }\n .landing-installer .expressive-code .copy button { opacity: 1; }\n .landing-hero__image { margin: 0; }\n .landing-hero__image img { display: block; width: 100%; height: auto; aspect-ratio: 1442 / 1268; object-fit: contain; filter: drop-shadow(0 1rem 2.5rem color-mix(in srgb, var(--sl-color-accent) 28%, transparent)); }\n .landing-grid { display: grid; gap: 1rem; grid-template-columns: repeat(3, minmax(0, 1fr)); margin-block: 1.5rem; }\n .landing-explore { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n details.landing-disclosure { margin-block: 1rem 0; padding: .75rem 1rem; border: 1px solid var(--sl-color-gray-5); border-radius: .5rem; background: var(--sl-color-bg-nav); }\n details.landing-disclosure summary { cursor: pointer; font-weight: 600; }\n :is(.landing-hero, .landing-installer, .landing-grid, .landing-disclosure) :is(a, button, summary):focus-visible { outline: 2px solid var(--sl-color-accent-high); outline-offset: 3px; }\n @media (max-width: 50rem) { .landing-hero { grid-template-columns: minmax(0, 1fr); gap: 2rem; margin-block: .5rem 2rem; } .landing-installer { margin-block-end: 3rem; padding: 1rem; } .landing-grid { grid-template-columns: minmax(0, 1fr); } }\n---\n\nimport { Aside, Card, LinkCard, TabItem, Tabs } from '@astrojs/starlight/components';\n\n<section class=\"landing-hero\" aria-labelledby=\"_top\">\n <div class=\"landing-hero__content\">\n <p class=\"landing-hero__lede\">An AI-native terminal assistant for engineering, automation, and reviewable F5 Distributed Cloud workflows.</p>\n <p>xcsh is an independent open-source project derived from pi/pi-mono, specialized for F5 Distributed Cloud workflows; it is not an F5 product.</p>\n </div>\n\n <figure class=\"landing-hero__image\">\n <img src=\"/xcsh/images/xcsh-ghostty-terminal.png\" width=\"1442\" height=\"1268\" alt=\"xcsh running in a Ghostty terminal with the model selector, prompt, and session status visible.\" />\n </figure>\n</section>\n\n<section class=\"landing-installer\" aria-labelledby=\"install-xcsh\">\n\n## Install xcsh\n\n <p>Universal installer for macOS and Linux.</p>\n\n ```bash\n curl -fsSL https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/scripts/install.sh | sh\n ```\n\n <p>It installs the latest prebuilt release into <code>~/.local/bin</code>. Need a managed or platform-specific channel? Compare the <a href=\"#installation-options\">installation options</a>.</p>\n</section>\n\n## What xcsh helps you do\n\n<div class=\"landing-grid landing-capabilities\">\n <Card title=\"Agentic terminal work\" icon=\"terminal\">\n Run interactive or print-mode prompts, inspect files, use tools, and keep durable session history when the task needs it. [Learn the agent loop](/xcsh/en/use-xcsh/agent-loop/).\n </Card>\n <Card title=\"Reviewable F5 Distributed Cloud workflows\" icon=\"document\">\n Discover schemas, validate manifests, and inspect proposed differences before an authorized resource change. [Use resource workflows](/xcsh/en/f5-distributed-cloud/).\n </Card>\n <Card title=\"Extensible automation\" icon=\"puzzle\">\n Add headless workflows, custom tools, skills, plugins, or MCP servers when built-in commands are not enough. [Automate and extend](/xcsh/en/automate-extend/).\n </Card>\n</div>\nThese workflows start with a working executable; choose another channel only when the universal installer is not the right fit.\n\n## Installation options\n\nUse one channel for install and upgrades. Mixing package-manager and standalone installations can leave more than one `xcsh` on `PATH`; the universal installer above is not repeated here.\n\n<Tabs syncKey=\"install-platform\">\n<TabItem label=\"macOS\" icon=\"seti:apple\">\nInstall the signed and notarized macOS archive through the Homebrew cask. The cask preserves the released executable and native addon byte for byte and does not require `sudo`:\n\n```bash\nbrew install --cask f5-sales-demo/tap/xcsh\n```\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nUpgrade with `brew upgrade --cask xcsh`. Remove the cask with `brew uninstall --cask xcsh`. These commands preserve configuration, credentials, and sessions under `~/.xcsh`.\n</details>\n\n<Aside type=\"caution\" title=\"Clean break from the historical package cask\">\nBefore installing this cask on a Mac that received an earlier xcsh package,\nuninstall both old Homebrew entries (`brew uninstall --formula xcsh` and\n`brew uninstall --cask xcsh`). Then have MDM forget the `com.f5.xcsh` receipt\nand remove only the package-owned `/usr/local/bin/xcsh` and\n`/Library/Application Support/xcsh` payload. Do not remove `~/.xcsh`. The signed\nand stapled `.pkg` release assets remain available only for direct MDM\ndeployment.\n</Aside>\n</TabItem>\n\n<TabItem label=\"Ubuntu or Debian\" icon=\"seti:ubuntu\">\nThe signed apt repository supports amd64 and arm64 and follows normal system upgrades:\n\n```bash\nsudo install -d -m 0755 /etc/apt/keyrings\ncurl -fsSL https://f5-sales-demo.github.io/apt-repo/f5xc-archive-keyring.gpg \\\n | sudo tee /etc/apt/keyrings/f5xc-archive-keyring.gpg >/dev/null\necho \"deb [arch=amd64,arm64 signed-by=/etc/apt/keyrings/f5xc-archive-keyring.gpg] https://f5-sales-demo.github.io/apt-repo stable main\" \\\n | sudo tee /etc/apt/sources.list.d/f5xc.list\nsudo apt-get update && sudo apt-get install xcsh\n```\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nUpgrade with `sudo apt-get update && sudo apt-get install --only-upgrade xcsh`. Remove the package with `sudo apt-get remove xcsh`.\n</details>\n</TabItem>\n\n<TabItem label=\"Windows\" icon=\"seti:windows\">\nRun the PowerShell installer, then restart the terminal so its user `PATH` refreshes:\n\n```powershell\nirm https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/scripts/install.ps1 | iex\n```\n\nIt installs `xcsh.exe` and native add-ons to `%LOCALAPPDATA%\\\\xcsh`. **Bash is required for tool-backed sessions.** Install Git for Windows, WSL, Cygwin, or MSYS2; set `shellPath` in `%USERPROFILE%\\\\.xcsh\\\\agent\\\\settings.json` when Bash is elsewhere.\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nRe-run the installer to upgrade. To uninstall, remove `%LOCALAPPDATA%\\\\xcsh` and its entry from the user `PATH`.\n</details>\n</TabItem>\n\n<TabItem label=\"Container\" icon=\"seti:docker\">\nDocker and Podman use the same multi-architecture image. Pin a release tag, resolve its digest for deployment, and mount only the workspace and state required by the task:\n\n```bash\ndocker pull ghcr.io/f5-sales-demo/xcsh:vX.Y.Z\ndocker image inspect --format '{{index .RepoDigests 0}}' ghcr.io/f5-sales-demo/xcsh:vX.Y.Z\ndocker run --rm ghcr.io/f5-sales-demo/xcsh@sha256:<digest> --version\n```\n\nPodman accepts the same pull, inspect, and run arguments. Pass provider credentials at runtime through a secret manager or environment file; never bake them into an image layer.\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nPull a newer pinned tag to upgrade. Remove an unused image with `docker image rm IMAGE` or `podman image rm IMAGE`.\n</details>\n</TabItem>\n\n<TabItem label=\"Packages and source\" icon=\"seti:config\">\nUse a JavaScript package or a source/ref install when you need a toolchain or an unreleased ref. Source installs require Git and Bun 1.4.2 or newer:\n\n```bash\nbun install --global @f5-sales-demo/xcsh\nnpm install --global @f5-sales-demo/xcsh\ncurl -fsSL https://raw.githubusercontent.com/f5-sales-demo/xcsh/main/scripts/install.sh \\\n | sh -s -- --source --ref vX.Y.Z\n```\n\nThe explicit `--source` and `--ref` arguments select a reproducible source install.\n\n<details class=\"landing-disclosure\">\n<summary>Upgrade or remove</summary>\n\nUpgrade with `bun update --global @f5-sales-demo/xcsh` or `npm update --global @f5-sales-demo/xcsh`. Remove the package with `bun remove --global @f5-sales-demo/xcsh` or `npm uninstall --global @f5-sales-demo/xcsh`; re-run the source command at a new ref to replace that channel.\n</details>\n</TabItem>\n</Tabs>\n\nWhichever installation channel you choose, open xcsh next.\n\n<span id=\"verification\" aria-hidden=\"true\"></span>\n\n## Verify installation\n\n<span id=\"verify-the-active-installation\" aria-hidden=\"true\"></span>\n\nStart the interactive terminal UI:\n\n<div class=\"landing-command\">\n\n```bash\nxcsh\n```\n\n</div>\n\nWhen the xcsh prompt appears, connect a model provider from inside the TUI.\n\n<span id=\"authentication\" aria-hidden=\"true\"></span>\n\n## Authenticate a provider\n\nAt the xcsh prompt, open the provider picker:\n\n<div class=\"landing-command\">\n\n```text\n/login\n```\n\n</div>\n\nChoose a provider and follow its sign-in flow. You can also enter `/login PROVIDER` to open a known provider directly. Keep credentials in the provider-supported environment or subscription login—never in a prompt or committed settings file. See [model authentication](/xcsh/en/getting-started/model-authentication/) for provider-specific options.\n\nGPT-6 Luna and Sol use a 272K-token context window by default for ChatGPT subscription sessions.\nTo opt in to their published 1.05M-token window, open `/settings`, select **Providers**, and enable\n**OpenAI Codex Maximum Context**. OpenAI applies higher token pricing to requests above 272K.\n\nAfter sign-in selects a model, stay in the TUI and send a small first prompt.\n\n## Quickstart\n\nAt the xcsh prompt, enter:\n\n<div class=\"landing-command\">\n\n```text\nReply with only: xcsh is ready\n```\n\n</div>\n\nA matching response confirms the installation, provider, and selected model are working together\nwithout granting a tool any file or network side effect. If it fails, verify the active executable\nwith `command -v xcsh`, reopen `/login`, and confirm the selected model is available to that\naccount. Next, learn the [interactive TUI](/xcsh/en/use-xcsh/interactive-tui/) or choose a [context and\nnamespace](/xcsh/en/f5-distributed-cloud/contexts-namespaces/) before an authorized F5 Distributed Cloud\nchange.\n\nFrom here, continue with the documentation path that matches your goal.\n\n<span id=\"exploration\" aria-hidden=\"true\"></span>\n\n## Explore by goal\n\nChoose the goal closest to your next task; each path starts from the verified installation above.\n\n<div class=\"landing-grid landing-explore\">\n <LinkCard title=\"Use xcsh\" icon=\"terminal\" href=\"./use-xcsh/\">Daily terminal use, tools, sessions, plans, and agents.</LinkCard>\n <LinkCard title=\"F5 Distributed Cloud\" icon=\"cloud\" href=\"./f5-distributed-cloud/\">Contexts, manifests, validation, and reviewable resource changes.</LinkCard>\n <LinkCard title=\"Configure and secure\" icon=\"setting\" href=\"./configure-secure/\">Providers, settings, secrets, and sandbox boundaries.</LinkCard>\n <LinkCard title=\"Automate and extend\" icon=\"puzzle\" href=\"./automate-extend/\">Headless modes, extensions, MCP, skills, plugins, and SDKs.</LinkCard>\n <LinkCard title=\"Integrations and deployment\" icon=\"rocket\" href=\"./integrations-deployment/\">Containers plus VS Code, Chrome, Office, and Herdr.</LinkCard>\n <LinkCard title=\"Reference and troubleshooting\" icon=\"information\" href=\"./reference-troubleshooting/\">Diagnostics, command reference, hotkeys, and configuration schema.</LinkCard>\n</div>\n",
46
46
  "en/integrations-deployment/chrome.mdx": "---\ntitle: \"Chrome\"\ndescription: \"Use the xcsh Chrome extension and native host with an isolated automation profile.\"\nsidebar:\n order: 3\n label: \"Chrome\"\n---\n\nThe Chrome integration connects xcsh to a browser session for supported console automation. The installed `xcsh chrome --help` output is the command authority.\n\n## What is the safe operating boundary?\n\nUse a dedicated profile and an authorized target. Confirm the visible account, uniform resource locator (URL), and object before an action that changes state. Prefer deterministic F5 Distributed Cloud resource commands whenever they cover the same operation.\n\n## Which Chrome capabilities does xcsh expose?\n\nThe `chrome` command inspects and arranges browser sessions, and `chrome-host` runs the native messaging host that connects the extension to the executable. Page-level interaction is driven by the browser tool inside a session rather than by a subcommand, so scope it with `--tools` in the same way as any other tool.\n\n| Need | Use Chrome integration? | Boundary |\n| --- | --- | --- |\n| Inspect a visible page or perform a supported console-only task | Yes | The browser profile and signed-in session define authority. |\n| Manage a resource with an xcsh catalog command | No | Prefer the typed resource workflow and its diff. |\n| Automate an unsupported site or a third-party account | No | The integration does not expand authorization. |\n\nStart with a read-only inspection and confirm the selected tab, URL, tenant, and browser profile. A click or submitted form can create an external side effect; the transcript must identify that boundary. Close temporary tabs and verify the intended page state after the task.\n",
47
47
  "en/integrations-deployment/containers.mdx": "---\ntitle: \"Containers\"\ndescription: \"Run the published multi-architecture Alpine image with explicit mounts and credentials.\"\nsidebar:\n order: 4\n label: \"Containers\"\nhead:\n - tag: style\n content: |\n .sl-markdown-content .expressive-code { max-width: 100%; overflow-x: auto; }\n .sl-markdown-content table { display: block; max-width: 100%; overflow-x: auto; }\n---\n\nThe published container packages xcsh for process isolation and repeatable deployment. It does not grant cloud credentials or filesystem access by itself.\n\n## How do I verify an image?\n\n```bash\ndocker pull ghcr.io/f5-sales-demo/xcsh:latest\ndocker run --rm ghcr.io/f5-sales-demo/xcsh:latest --version\n```\n\nPin a version tag or digest for automation. Mount only the task directory and inject credentials through the runtime's secret mechanism.\n\n## What must remain outside the image?\n\nKeep user contexts, provider tokens, and writable session data in explicit mounts or secret stores. Do not bake them into a derived layer.\n\nPull a versioned image, resolve its immutable digest, and run `xcsh --version` from that digest\nbefore mounting a workspace. The container image supplies the executable, not model or tenant\nauthority. Mount only required paths read-only where possible and inject credentials at runtime\nthrough the platform's secret mechanism. Remove the test container after exit; delete the pinned\nimage only when no deployment still references its digest.\n",
48
48
  "en/integrations-deployment/herdr.mdx": "---\ntitle: \"Integrate with Herdr\"\ndescription: \"Understand Herdr workspace launch, terminal actions, protocol negotiation, and isolation.\"\nsidebar:\n order: 5\n label: \"Herdr\"\nhead:\n - tag: style\n content: |\n .sl-markdown-content .expressive-code { max-width: 100%; overflow-x: auto; }\n .sl-markdown-content table { display: block; max-width: 100%; overflow-x: auto; }\n---\n\nHerdr support is optional and host-dependent. When the host does not provide it, xcsh terminal operation is unaffected.\n\n## How is the host protocol negotiated?\n\nThe integration checks the available socket protocol and media or graphics capabilities before it requests a workspace. Missing negotiation support leaves ordinary xcsh terminal operation intact.\n\n## How is a conversation-owned workspace launched?\n\nA workspace is tied to the conversation identity supplied at startup. Terminal-management actions create or address panes within that workspace, and lifecycle reporting stays anchored to the same startup context. Do not reuse an unrelated workspace merely because its socket is reachable.\n\n## How do I recover from socket failure?\n\nConnection and framing failures surface as integration diagnostics. The client must not open an inbound listener as a fallback. Close conversation-owned resources through the supported lifecycle and preserve unrelated Herdr workspaces.\n\n## What lifecycle state does xcsh publish?\n\nxcsh publishes native turn phases rather than inferring completion from terminal idleness or process\nexit. With a supported Herdr protocol through 26 and the advertised `agent_turn_journal` capability, a tracked\nexecution publishes a persisted session/turn identity and a bounded semantic result to Herdr's\ndurable journal. The existing 80-character metadata preview remains display-only and is never\ncompletion evidence.\nCommentary, prompt content, tool data, and failed or cancelled partial output are excluded.\n\n### External execution driver contract\n\nThe supported producer is the normal `xcsh` executable launched by Herdr's execution backend; it is not a mock or a no-provider/offline actor. For a journal-tracked invocation, that backend must inject the exact allocated `HERDR_EXECUTION_ID` and decimal safe-integer `HERDR_EXECUTION_GENERATION` into the child environment before it starts `xcsh`.\n\nxcsh never guesses a generation: without both values it retains ordinary pane lifecycle reporting but emits no semantic journal event. A continuation must be launched with its newly allocated generation.\n\nProtocol 26 is the current producer-native contract. Herdr injects a one-time `HERDR_NATIVE_CAPABILITY` into the child. xcsh includes it only in authenticated turn-report and action requests; it is never written to the session journal, logs, diagnostics, or receipts.\nHerdr does not authorize actions until the first `starting` report has been durably journaled and bound to the owned PTY, pane, session, generation, and turn.\n\nEach semantic report has a five-second deadline. xcsh retries exactly once only when timeout,\nEOF, or a transport error leaves admission ambiguous. The retry preserves the method and complete\nsemantic payload and changes only the transport request ID. Either correlated receipt marks the\nevent delivered; protocol, validation, malformed-response, and explicit remote errors are definitive\nand are not retried. Degraded tracking is shown only after both ambiguous attempts fail.\n\nThe producer wire shapes align with [Herdr PR #49](https://github.com/f5-sales-demo/herdr/pull/49) at cancellation-settlement commit `2c838cf545ed06439b4988cedb3e044f1d436264`, starting-replay recovery commit `edd5611cfd7685c0f069f244ceee0ac6c0a0678e`, and native-argv alignment commit `3397302960593a552fb37ceb71053cf99f2619a3`.\nThose commits are an integration contract under independent review, not released-backend evidence.\n\nAfter that registration, xcsh polls `agent.turn.action.get` with the same immutable provenance. A `cancel` action dismisses an active managed UI prompt and calls the real `AgentSession` abort path. xcsh persists the requested action and local safe point before sending the exact `agent.turn.action.ack`; it emits `cancelled` only after Herdr confirms that safe point.\nA lost ACK response is retried with the same action ID and revision, including after reporter restart. A backend `timed_out` action never triggers a late abort. PTY exit alone is not semantic cancellation.\n\nSession shutdown releases pane authority. It does not convert an unfinished turn into a successful completion.\n\n### Producer-native acceptance driver\n\n`xcsh lifecycle --json` prints the version 3 machine-readable producer contract. To execute a source or installed\nproducer check, supply a fresh absolute session directory, a normally configured model, and one scenario:\n\n```bash\nxcsh lifecycle --json \\\n --scenario await-continue \\\n --model openai-codex/gpt-5.6-luna \\\n --session-dir /absolute/fresh/xcsh-lifecycle-session\n```\n\nSupported scenarios are `success`, `failure`, `await-continue`, `cancel`, `managed-cancel`, `managed-working-cancel`, and `reply-loss-replay`. The driver first\nuses the prompt-free JSON session contract to persist one canonical 16-character lowercase hexadecimal session\nheader, then reopens that exact path in an ordinary interactive xcsh child. It generates a random mode-0600 fixture\nfor successful reads. `await-continue` pauses in the real `ExtensionUiController` input surface before the configured\nmodel runs; `cancel` sends SIGINT through `PtySession.interrupt()` and requires xcsh's native `cancelled` transition.\n`managed-cancel` uses a local protocol-26 control fixture to request the action and requires the executable child to\nacknowledge its safe point before its native `cancelled` report. That fixture validates the producer adapter only; it\nis not evidence for Herdr's durable action journal, manager generation replacement, or consumer deduplication.\n`managed-working-cancel` requests the same cooperative action after the real child reports `working`, without opening\nthe acceptance prompt, and verifies cancellation through the active `AgentSession` path.\n\nThe reply-loss scenario owns a temporary local protocol-26 socket that acknowledges ordinary reporter traffic but\ndrops both bounded `agent.turn.report` attempts. xcsh creates and persists the semantic event before transport, runs the\nconfigured provider and `read` tool, then a second xcsh process resumes the exact session path. The scenario passes\nonly when the reporter redelivers the byte-equivalent execution, pane, session, turn, generation, event revision, and\nstate fields. The socket never authors a lifecycle frame or substitutes an offline model.\n\nThe receipt's `evidenceClass` is `source_native_child`. This proves the measured source or executable behavior only;\nthe Control Manager remains responsible for its own admission, authenticated execution binding, generation changes,\nconsumer receipts, and installed-artifact acceptance. The command does not install or release xcsh or Herdr and does\nnot change normal launch defaults.\n\nThe verified contract is:\n\n| Concern | xcsh signal | Herdr disposition |\n| --- | --- | --- |\n| Session start and identity | Persisted native session ID/path | Herdr resume reference plus stable semantic session identity. |\n| Turn start/progress | Persisted UUID and normalized `turn_phase` | `starting`/`working` journal events with producer revision and server revision. |\n| Waiting for input/approval | `awaiting_user` and closed prompt kind | `waiting_input` with fixed safe reason; private prompt content is excluded. |\n| Successful completion | Settlement-aware `idle` after `agent_end` | `completed` with at most 8,000 UTF-8 bytes and a matching SHA-256 digest. |\n| Failure/cancellation | `error` or `cancelled` | Distinct terminal state and bounded safe reason; no partial result. |\n| Managed cancellation | Persisted action receipt, Extension UI signal, and `AgentSession.abort()` | Authenticated `safe_point` precedes and is linked to the native `cancelled` report. |\n| Resume/fork | Session events and persisted custom turn entries | Resume preserves identity; unfinished recovered work becomes `interrupted`; fork has separate session lineage. |\n| Reconnect/order | Serialized queue and persisted event revision | Exact duplicates are idempotent; stale/conflicting revisions fail; terminal state is immutable. |\n| Application exit | `session_shutdown` | Active turn becomes `interrupted`, then pane authority is released; never success. |\n\nThe protocol-26 native-interaction update is tracked by\n[issue #4161](https://github.com/f5-sales-demo/xcsh/issues/4161); its producer lifecycle foundation is\ntracked by [issue #3791](https://github.com/f5-sales-demo/xcsh/issues/3791) and\n[issue #3768](https://github.com/f5-sales-demo/xcsh/issues/3768). The active protocol and lifecycle\nbehavior is described on this page; obsolete delivery checklists are not part of the runtime contract.\n\nHerdr lifecycle reconciliation is tracked by issue #5 in the F5 Herdr fork. Current source already recognizes the exact `(\"herdr:xcsh\", \"xcsh\")` resume pair; deployed build provenance and live resume/fork acceptance remain required before feature acceptance.\n\nTreat the negotiated protocol and the pane lifecycle as separate checks. First confirm that the\nHerdr socket and protocol version are compatible, then launch one conversation-owned workspace and\nobserve its published state through exit. xcsh owns only workspaces it created for that\nconversation; it must not close unrelated panes. After a forced socket failure, reconnect and verify\nthat stale workspace state is reconciled before another launch.\n",
package/src/main.ts CHANGED
@@ -691,6 +691,7 @@ export async function runRootCommand(rawArgs: string[]): Promise<void> {
691
691
  const registrySettings = await Settings.init({ cwd: getProjectDir() });
692
692
  const modelRegistry = new ModelRegistry(authStorage, undefined, {
693
693
  getProviderOrder: () => registrySettings.get("modelProviderOrder"),
694
+ getOpenAICodexMaxContext: () => registrySettings.get("providers.openaiCodexMaxContext"),
694
695
  });
695
696
  // Explicit CLI selectors and scopes must see providers loaded during bootstrap.
696
697
  // Keep their declarations queued for the SDK's source reconciliation and reload.
@@ -1023,8 +1024,6 @@ export async function runRootCommand(rawArgs: string[]): Promise<void> {
1023
1024
  ];
1024
1025
  }
1025
1026
 
1026
- // YAGNI: skip MCP server discovery (500-3000ms) — not used in our workflow.
1027
- sessionOptions.enableMCP = false;
1028
1027
  // Trusted process configuration can disable automatic discovery (for isolated CLI tests or embedding).
1029
1028
  sessionOptions.profileDiscovery = process.env.XCSH_PROFILE_DISCOVERY !== "0";
1030
1029
 
@@ -2,11 +2,7 @@ import { ThinkingLevel } from "@f5-sales-demo/pi-agent-core";
2
2
  import { canonicalizeOAuthProviderId, type Model, ReasoningEffort } from "@f5-sales-demo/pi-ai";
3
3
  import type { Settings } from "../../config/settings";
4
4
  import type { VllmDiscoveredModel } from "../../config/vllm-config";
5
- import {
6
- applySubscriptionProfileRoles,
7
- SUBSCRIPTION_ROUTING_PROFILES,
8
- type SubscriptionProfileId,
9
- } from "../../routing/subscription-profiles";
5
+ import { applySubscriptionProfileRoles, type SubscriptionProfileId } from "../../routing/subscription-profiles";
10
6
 
11
7
  export interface LoginModelChoice {
12
8
  label: string;
@@ -83,14 +79,20 @@ export function getAvailableLiteLLMLoginModelChoices(availableModelIds: readonly
83
79
  * that policy onto the provider namespace used by the LiteLLM configuration.
84
80
  */
85
81
  export function getLiteLLMLoginModelRoles(choice: LiteLLMLoginModelChoice): Record<string, string> {
86
- const profileId: SubscriptionProfileId = choice.modelId === "claude-opus-5" ? "anthropic" : "openai-codex";
87
- const profile = SUBSCRIPTION_ROUTING_PROFILES[profileId];
88
- return Object.fromEntries(
89
- Object.entries(profile.roles).map(([role, selector]) => {
90
- const slash = selector.indexOf("/");
91
- return [role, `${choice.provider}/${selector.slice(slash + 1)}`];
92
- }),
93
- );
82
+ if (choice.modelId === "claude-opus-5") {
83
+ return {
84
+ smol: `${choice.provider}/claude-haiku-4-5:low`,
85
+ default: `${choice.provider}/claude-sonnet-5:medium`,
86
+ slow: `${choice.provider}/claude-opus-5:high`,
87
+ plan: `${choice.provider}/claude-opus-5:high`,
88
+ };
89
+ }
90
+ return {
91
+ smol: `${choice.provider}/gpt-5.6-luna:low`,
92
+ default: `${choice.provider}/gpt-5.6-terra:medium`,
93
+ slow: `${choice.provider}/gpt-5.6-sol:high`,
94
+ plan: `${choice.provider}/gpt-5.6-sol:high`,
95
+ };
94
96
  }
95
97
 
96
98
  export function getVllmLoginModelChoices(models: readonly VllmDiscoveredModel[]): LoginModelChoice[] {
@@ -874,6 +874,11 @@ export class SelectorController {
874
874
  setPreferredImageProvider(value);
875
875
  }
876
876
  break;
877
+ case "providers.openaiCodexMaxContext":
878
+ this.ctx.session.modelRegistry.setOpenAICodexMaxContext(value === true);
879
+ this.ctx.statusLine.invalidate();
880
+ this.ctx.ui.requestRender();
881
+ break;
877
882
 
878
883
  // MCP update injection - live subscribe/unsubscribe
879
884
  case "mcp.notifications":
@@ -6,20 +6,20 @@ export const BUILTIN_ROUTING_PRESETS: Record<string, RoutingPoolConfig> = {
6
6
  "openai/gpt-5.6": {
7
7
  id: "openai/gpt-5.6",
8
8
  provider: "openai",
9
- tiers: { ...OPENAI_CODEX_ROUTING_POOL.tiers },
9
+ tiers: { utility: "gpt-5.6-luna", balanced: "gpt-5.6-terra", frontier: "gpt-5.6-sol" },
10
10
  effortPolicy: OPENAI_CODEX_ROUTING_POOL.effortPolicy,
11
11
  },
12
12
  [ANTHROPIC_ROUTING_POOL.id]: ANTHROPIC_ROUTING_POOL,
13
13
  "litellm/openai": {
14
14
  id: "litellm/openai",
15
15
  provider: "litellm",
16
- tiers: { ...OPENAI_CODEX_ROUTING_POOL.tiers },
16
+ tiers: { utility: "gpt-5.6-luna", balanced: "gpt-5.6-terra", frontier: "gpt-5.6-sol" },
17
17
  effortPolicy: OPENAI_CODEX_ROUTING_POOL.effortPolicy,
18
18
  },
19
19
  "litellm/anthropic": {
20
20
  id: "litellm/anthropic",
21
21
  provider: "litellm",
22
- tiers: { ...ANTHROPIC_ROUTING_POOL.tiers },
22
+ tiers: { utility: "claude-haiku-4-5", balanced: "claude-sonnet-5", frontier: "claude-opus-5" },
23
23
  effortPolicy: ANTHROPIC_ROUTING_POOL.effortPolicy,
24
24
  },
25
25
  };
@@ -10,12 +10,12 @@ export interface SubscriptionRoutingProfile {
10
10
  }
11
11
 
12
12
  const OPENAI_CODEX_POOL: RoutingPoolConfig = {
13
- id: "openai-codex/gpt-5.6",
13
+ id: "openai-codex/gpt-6",
14
14
  provider: "openai-codex",
15
15
  tiers: {
16
- utility: "gpt-5.6-luna",
16
+ utility: "gpt-6-luna",
17
17
  balanced: "gpt-5.6-terra",
18
- frontier: "gpt-5.6-sol",
18
+ frontier: "gpt-6-sol",
19
19
  },
20
20
  effortPolicy: {
21
21
  byTier: { utility: "low", balanced: "medium", frontier: "high" },
@@ -29,7 +29,7 @@ const ANTHROPIC_POOL: RoutingPoolConfig = {
29
29
  tiers: {
30
30
  utility: "claude-haiku-4-5",
31
31
  balanced: "claude-sonnet-5",
32
- frontier: "claude-opus-5",
32
+ frontier: "claude-opus-5-5",
33
33
  },
34
34
  effortPolicy: {
35
35
  byTier: { utility: "low", balanced: "medium", frontier: "high" },
@@ -44,8 +44,8 @@ export const SUBSCRIPTION_ROUTING_PROFILES: Readonly<Record<SubscriptionProfileI
44
44
  roles: {
45
45
  smol: "anthropic/claude-haiku-4-5:low",
46
46
  default: "anthropic/claude-sonnet-5:medium",
47
- slow: "anthropic/claude-opus-5:high",
48
- plan: "anthropic/claude-opus-5:high",
47
+ slow: "anthropic/claude-opus-5-5:high",
48
+ plan: "anthropic/claude-opus-5-5:high",
49
49
  },
50
50
  pool: ANTHROPIC_POOL,
51
51
  },
@@ -63,10 +63,10 @@ export const SUBSCRIPTION_ROUTING_PROFILES: Readonly<Record<SubscriptionProfileI
63
63
  id: "openai-codex",
64
64
  provider: "openai-codex",
65
65
  roles: {
66
- smol: "openai-codex/gpt-5.6-luna:low",
66
+ smol: "openai-codex/gpt-6-luna:low",
67
67
  default: "openai-codex/gpt-5.6-terra:medium",
68
- slow: "openai-codex/gpt-5.6-sol:high",
69
- plan: "openai-codex/gpt-5.6-sol:high",
68
+ slow: "openai-codex/gpt-6-sol:high",
69
+ plan: "openai-codex/gpt-6-sol:high",
70
70
  },
71
71
  pool: OPENAI_CODEX_POOL,
72
72
  },
package/src/sdk.ts CHANGED
@@ -712,7 +712,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
712
712
  const authStorage = options.authStorage ?? (await logger.time("discoverModels", discoverAuthStorage, agentDir));
713
713
  const modelRegistry =
714
714
  options.modelRegistry ??
715
- new ModelRegistry(authStorage, undefined, { getProviderOrder: () => settings.get("modelProviderOrder") });
715
+ new ModelRegistry(authStorage, undefined, {
716
+ getProviderOrder: () => settings.get("modelProviderOrder"),
717
+ getOpenAICodexMaxContext: () => settings.get("providers.openaiCodexMaxContext"),
718
+ });
716
719
 
717
720
  const configuredContextLoadingMode = settings.get("context.loadingMode");
718
721
  const resolveContextLoadingMode = (candidate: Model | undefined): "eager" | "progressive" =>
@@ -23,6 +23,7 @@ import { parseMarketplaceCatalog } from "../extensibility/plugins/marketplace/fe
23
23
  import {
24
24
  createSetupStepRunner,
25
25
  describeInstallSetupOutcome,
26
+ describeInteractiveInstallSetupNextAction,
26
27
  describeSetupPlan,
27
28
  executeInstallAuthorizedSetup,
28
29
  executeReviewedSetup,
@@ -1531,7 +1532,10 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<BuiltinSlashCommandSpec> = [
1531
1532
  showPluginStatus(
1532
1533
  `${installed}\n${describeInstallSetupOutcome(name, setupResult, dependencyPlan, handles)}`,
1533
1534
  );
1534
- } else showPluginStatus(installed);
1535
+ } else {
1536
+ const nextAction = describeInteractiveInstallSetupNextAction(name, prepared.target);
1537
+ showPluginStatus(nextAction ? `${installed}\nnext: ${nextAction}` : installed);
1538
+ }
1535
1539
  } else if (outcome === "unresolved")
1536
1540
  runtime.ctx.showError("Plugin installation remains unresolved; retry from a fresh review.");
1537
1541
  break;
@@ -980,7 +980,10 @@ export async function runSubprocess(options: ExecutorOptions): Promise<SingleRes
980
980
  checkAbort();
981
981
  const modelRegistry =
982
982
  options.modelRegistry ??
983
- new ModelRegistry(authStorage, undefined, { getProviderOrder: () => settings.get("modelProviderOrder") });
983
+ new ModelRegistry(authStorage, undefined, {
984
+ getProviderOrder: () => settings.get("modelProviderOrder"),
985
+ getOpenAICodexMaxContext: () => settings.get("providers.openaiCodexMaxContext"),
986
+ });
984
987
  await modelRegistry.refresh();
985
988
  checkAbort();
986
989