@f5-sales-demo/xcsh 21.31.0 → 21.32.4
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/office-pane-server.ts +1 -1
- package/src/cli/update-cli.ts +13 -5
- package/src/internal-urls/build-info.generated.ts +9 -9
- package/src/internal-urls/docs-index.generated.ts +1 -1
- package/src/internal-urls/sitecli-index.generated.ts +57 -3
- package/src/remote-control/lifecycle-state.ts +39 -3
- package/src/remote-control/startup-manager.ts +21 -5
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5-sales-demo/xcsh",
|
|
4
|
-
"version": "21.
|
|
4
|
+
"version": "21.32.4",
|
|
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",
|
|
@@ -63,13 +63,13 @@
|
|
|
63
63
|
},
|
|
64
64
|
"dependencies": {
|
|
65
65
|
"@agentclientprotocol/sdk": "1.4.0",
|
|
66
|
-
"@f5-sales-demo/pi-agent-core": "21.
|
|
67
|
-
"@f5-sales-demo/pi-ai": "21.
|
|
68
|
-
"@f5-sales-demo/pi-natives": "21.
|
|
69
|
-
"@f5-sales-demo/pi-resource-management": "21.
|
|
70
|
-
"@f5-sales-demo/pi-tui": "21.
|
|
71
|
-
"@f5-sales-demo/pi-utils": "21.
|
|
72
|
-
"@f5-sales-demo/xcsh-stats": "21.
|
|
66
|
+
"@f5-sales-demo/pi-agent-core": "21.32.4",
|
|
67
|
+
"@f5-sales-demo/pi-ai": "21.32.4",
|
|
68
|
+
"@f5-sales-demo/pi-natives": "21.32.4",
|
|
69
|
+
"@f5-sales-demo/pi-resource-management": "21.32.4",
|
|
70
|
+
"@f5-sales-demo/pi-tui": "21.32.4",
|
|
71
|
+
"@f5-sales-demo/pi-utils": "21.32.4",
|
|
72
|
+
"@f5-sales-demo/xcsh-stats": "21.32.4",
|
|
73
73
|
"@mozilla/readability": "^0.6",
|
|
74
74
|
"@sinclair/typebox": "0.34.52",
|
|
75
75
|
"@xterm/headless": "^6.0",
|
|
@@ -155,7 +155,7 @@ export function paneUnavailableMessage(distDir: string, source: PaneSource): str
|
|
|
155
155
|
return (
|
|
156
156
|
"The Office pane is not included in the npm package — it ships as a build-time asset of the " +
|
|
157
157
|
"compiled binary, which is also what provides the sideload and the trusted certificate. " +
|
|
158
|
-
"Install it with `brew install f5-sales-demo/tap/xcsh` and run `xcsh office` from there."
|
|
158
|
+
"Install it with `brew install --cask f5-sales-demo/tap/xcsh` and run `xcsh office` from there."
|
|
159
159
|
);
|
|
160
160
|
}
|
|
161
161
|
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -75,7 +75,7 @@ type UpdateTarget =
|
|
|
75
75
|
* Detection order:
|
|
76
76
|
* 1. bun — binary is inside bun's global bin directory
|
|
77
77
|
* 2. npm — binary is a symlink whose resolution chain contains "node_modules"
|
|
78
|
-
* 3. brew — binary path or realpath contains "Cellar" or "homebrew"
|
|
78
|
+
* 3. brew — binary path or realpath contains "Cellar", "Caskroom", or "homebrew"
|
|
79
79
|
* 4. binary — fallback for standalone installs
|
|
80
80
|
*/
|
|
81
81
|
function detectInstallMethod(binPath: string, bunBinDir: string | undefined): InstallMethod {
|
|
@@ -106,14 +106,18 @@ function detectInstallMethod(binPath: string, bunBinDir: string | undefined): In
|
|
|
106
106
|
// lstat/readlink may fail; fall through
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
// 3. brew: path or realpath contains Cellar or homebrew
|
|
109
|
+
// 3. brew: path or realpath contains Cellar, Caskroom, or homebrew
|
|
110
110
|
const lowerBinPath = binPath.toLowerCase();
|
|
111
|
-
if (
|
|
111
|
+
if (
|
|
112
|
+
lowerBinPath.includes("/cellar/") ||
|
|
113
|
+
lowerBinPath.includes("/caskroom/") ||
|
|
114
|
+
lowerBinPath.includes("/homebrew/")
|
|
115
|
+
) {
|
|
112
116
|
return "brew";
|
|
113
117
|
}
|
|
114
118
|
try {
|
|
115
119
|
const realPath = fs.realpathSync(binPath).toLowerCase();
|
|
116
|
-
if (realPath.includes("/cellar/") || realPath.includes("/homebrew/")) {
|
|
120
|
+
if (realPath.includes("/cellar/") || realPath.includes("/caskroom/") || realPath.includes("/homebrew/")) {
|
|
117
121
|
return "brew";
|
|
118
122
|
}
|
|
119
123
|
} catch {
|
|
@@ -322,7 +326,7 @@ async function updateViaNpm(expectedVersion: string): Promise<void> {
|
|
|
322
326
|
function updateViaBrew(targetPath: string, expectedVersion: string): void {
|
|
323
327
|
console.log(chalk.yellow(`\n${APP_NAME} at ${targetPath} was installed via Homebrew.`));
|
|
324
328
|
console.log(chalk.yellow(`To update to ${expectedVersion}, run:`));
|
|
325
|
-
console.log(chalk.cyan(`
|
|
329
|
+
console.log(chalk.cyan(` ${getBrewUpgradeCommand()}`));
|
|
326
330
|
console.log(chalk.dim("\nThis ensures the update goes through your organization's Homebrew tap."));
|
|
327
331
|
// #1874 Task 7: brew upgrade runs out-of-band, so we can't recycle automatically.
|
|
328
332
|
// Nudge the one command that applies it to the Chrome extension immediately.
|
|
@@ -330,6 +334,10 @@ function updateViaBrew(targetPath: string, expectedVersion: string): void {
|
|
|
330
334
|
console.log(chalk.dim("(otherwise it takes effect the next time you open Chrome)."));
|
|
331
335
|
}
|
|
332
336
|
|
|
337
|
+
export function getBrewUpgradeCommand(): string {
|
|
338
|
+
return `brew upgrade --cask ${APP_NAME}`;
|
|
339
|
+
}
|
|
340
|
+
|
|
333
341
|
/**
|
|
334
342
|
* Download a release binary to a target path, replacing an existing file.
|
|
335
343
|
*/
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "21.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
23
|
-
"branch": "
|
|
24
|
-
"tag": "v21.
|
|
25
|
-
"commitDate": "2026-09-
|
|
26
|
-
"buildDate": "2026-09-
|
|
20
|
+
"version": "21.32.4",
|
|
21
|
+
"commit": "a12d78ad6bb7f1d0aeeabb0f8656f579c8130ba8",
|
|
22
|
+
"shortCommit": "a12d78a",
|
|
23
|
+
"branch": "main",
|
|
24
|
+
"tag": "v21.32.4",
|
|
25
|
+
"commitDate": "2026-09-18T10:32:48+00:00",
|
|
26
|
+
"buildDate": "2026-09-18T11:33:24.618Z",
|
|
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/v21.
|
|
31
|
+
"commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/a12d78ad6bb7f1d0aeeabb0f8656f579c8130ba8",
|
|
32
|
+
"releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v21.32.4"
|
|
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 { 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\">\nChoose the Homebrew formula for the signed release archive, or the managed cask for the signed macOS package. Install one, not both:\n\n```bash\nbrew install f5-sales-demo/tap/xcsh\n# or\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 xcsh` or `brew upgrade --cask xcsh`. Remove the selected channel with `brew uninstall xcsh` or `brew uninstall --cask xcsh`.\n</details>\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\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 Herdr protocol 20 or 22 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 22 adds producer-native controls. 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\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 2 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-22 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-20 socket that acknowledges ordinary reporter traffic but\ndrops exactly one `agent.turn.report` reply. 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-22 producer integration is tracked by [issue #3791](https://github.com/f5-sales-demo/xcsh/issues/3791); its lifecycle foundation is tracked by [issue #3768](https://github.com/f5-sales-demo/xcsh/issues/3768). The active protocol and lifecycle behavior 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",
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Run `bun generate-sitecli-index` to regenerate.
|
|
2
2
|
//
|
|
3
|
-
// Source: f5-sales-demo/
|
|
3
|
+
// Source: f5-sales-demo/multi-cloud-networking sitecli/catalog.json, captured from a live Customer Edge.
|
|
4
4
|
// The command surface depends on the node software build, so SITECLI_BUILD records
|
|
5
5
|
// which build this describes.
|
|
6
6
|
|
|
7
|
-
export const SITECLI_BUILD = "crt-
|
|
7
|
+
export const SITECLI_BUILD = "crt-20260201-0179";
|
|
8
8
|
|
|
9
9
|
export const SITECLI_SOURCE = {
|
|
10
10
|
node: "f5-xc-ce-vm-01",
|
|
11
|
-
site: "
|
|
11
|
+
site: "mcn-ce-ha-eastus01",
|
|
12
12
|
} as const;
|
|
13
13
|
|
|
14
14
|
export const SITECLI_COMMANDS = {
|
|
@@ -18,6 +18,12 @@ export const SITECLI_COMMANDS = {
|
|
|
18
18
|
transport: "exec-user",
|
|
19
19
|
mutating: false,
|
|
20
20
|
},
|
|
21
|
+
"collect-database-stats": {
|
|
22
|
+
category: "System Troubleshooting",
|
|
23
|
+
tier: "ExecUser",
|
|
24
|
+
transport: "exec-user",
|
|
25
|
+
mutating: false,
|
|
26
|
+
},
|
|
21
27
|
"crictl-images": {
|
|
22
28
|
category: "System Troubleshooting",
|
|
23
29
|
tier: "ExecUser",
|
|
@@ -176,6 +182,12 @@ export const SITECLI_COMMANDS = {
|
|
|
176
182
|
transport: "exec-user",
|
|
177
183
|
mutating: false,
|
|
178
184
|
},
|
|
185
|
+
"iptables-lv": {
|
|
186
|
+
category: "Network Troubleshooting",
|
|
187
|
+
tier: "ExecUser",
|
|
188
|
+
transport: "exec-user",
|
|
189
|
+
mutating: false,
|
|
190
|
+
},
|
|
179
191
|
journalctl: {
|
|
180
192
|
category: "System Troubleshooting",
|
|
181
193
|
tier: "ExecUser",
|
|
@@ -183,6 +195,24 @@ export const SITECLI_COMMANDS = {
|
|
|
183
195
|
mutating: false,
|
|
184
196
|
example: "-u vpm -n 200",
|
|
185
197
|
},
|
|
198
|
+
"marker-exists-crio": {
|
|
199
|
+
category: "System Troubleshooting",
|
|
200
|
+
tier: "Exec",
|
|
201
|
+
transport: "exec",
|
|
202
|
+
mutating: true,
|
|
203
|
+
},
|
|
204
|
+
"marker-exists-kubelet": {
|
|
205
|
+
category: "System Troubleshooting",
|
|
206
|
+
tier: "Exec",
|
|
207
|
+
transport: "exec",
|
|
208
|
+
mutating: true,
|
|
209
|
+
},
|
|
210
|
+
"marker-exists-NetworkManager": {
|
|
211
|
+
category: "System Troubleshooting",
|
|
212
|
+
tier: "Exec",
|
|
213
|
+
transport: "exec",
|
|
214
|
+
mutating: true,
|
|
215
|
+
},
|
|
186
216
|
netstat: {
|
|
187
217
|
category: "Network Troubleshooting",
|
|
188
218
|
tier: "ExecUser",
|
|
@@ -227,6 +257,30 @@ export const SITECLI_COMMANDS = {
|
|
|
227
257
|
transport: "exec-user",
|
|
228
258
|
mutating: false,
|
|
229
259
|
},
|
|
260
|
+
"systemctl-restart-crio": {
|
|
261
|
+
category: "System Troubleshooting",
|
|
262
|
+
tier: "Exec",
|
|
263
|
+
transport: "exec",
|
|
264
|
+
mutating: true,
|
|
265
|
+
},
|
|
266
|
+
"systemctl-restart-kubelet": {
|
|
267
|
+
category: "System Troubleshooting",
|
|
268
|
+
tier: "Exec",
|
|
269
|
+
transport: "exec",
|
|
270
|
+
mutating: true,
|
|
271
|
+
},
|
|
272
|
+
"systemctl-restart-NetworkManager": {
|
|
273
|
+
category: "System Troubleshooting",
|
|
274
|
+
tier: "Exec",
|
|
275
|
+
transport: "exec",
|
|
276
|
+
mutating: true,
|
|
277
|
+
},
|
|
278
|
+
"systemctl-start-crio-prune": {
|
|
279
|
+
category: "System Troubleshooting",
|
|
280
|
+
tier: "Exec",
|
|
281
|
+
transport: "exec",
|
|
282
|
+
mutating: true,
|
|
283
|
+
},
|
|
230
284
|
vif: {
|
|
231
285
|
category: "Network Troubleshooting",
|
|
232
286
|
tier: "ExecUser",
|
|
@@ -6,6 +6,11 @@ import { promisify } from "node:util";
|
|
|
6
6
|
|
|
7
7
|
const execFileAsync = promisify(execFile);
|
|
8
8
|
const PROCESS_KINDS = ["supervisor", "host"] as const;
|
|
9
|
+
const executableDigestCache = new Map<
|
|
10
|
+
string,
|
|
11
|
+
{ dev: number; ino: number; size: number; mtimeMs: number; ctimeMs: number; digest: string }
|
|
12
|
+
>();
|
|
13
|
+
const executableDigestInFlight = new Map<string, Promise<string>>();
|
|
9
14
|
export type ProcessKind = (typeof PROCESS_KINDS)[number];
|
|
10
15
|
|
|
11
16
|
export interface ProcessIdentity {
|
|
@@ -186,9 +191,40 @@ async function processStartTime(pid: number): Promise<string> {
|
|
|
186
191
|
}
|
|
187
192
|
|
|
188
193
|
async function sha256File(path: string): Promise<string> {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
194
|
+
const metadata = await stat(path);
|
|
195
|
+
const cached = executableDigestCache.get(path);
|
|
196
|
+
if (
|
|
197
|
+
cached &&
|
|
198
|
+
cached.dev === metadata.dev &&
|
|
199
|
+
cached.ino === metadata.ino &&
|
|
200
|
+
cached.size === metadata.size &&
|
|
201
|
+
cached.mtimeMs === metadata.mtimeMs &&
|
|
202
|
+
cached.ctimeMs === metadata.ctimeMs
|
|
203
|
+
)
|
|
204
|
+
return cached.digest;
|
|
205
|
+
const key = `${path}:${metadata.dev}:${metadata.ino}:${metadata.size}:${metadata.mtimeMs}:${metadata.ctimeMs}`;
|
|
206
|
+
const pending = executableDigestInFlight.get(key);
|
|
207
|
+
if (pending) return pending;
|
|
208
|
+
const digest = (async () => {
|
|
209
|
+
const value = createHash("sha256")
|
|
210
|
+
.update(await readFile(path))
|
|
211
|
+
.digest("hex");
|
|
212
|
+
executableDigestCache.set(path, {
|
|
213
|
+
dev: metadata.dev,
|
|
214
|
+
ino: metadata.ino,
|
|
215
|
+
size: metadata.size,
|
|
216
|
+
mtimeMs: metadata.mtimeMs,
|
|
217
|
+
ctimeMs: metadata.ctimeMs,
|
|
218
|
+
digest: value,
|
|
219
|
+
});
|
|
220
|
+
return value;
|
|
221
|
+
})();
|
|
222
|
+
executableDigestInFlight.set(key, digest);
|
|
223
|
+
try {
|
|
224
|
+
return await digest;
|
|
225
|
+
} finally {
|
|
226
|
+
executableDigestInFlight.delete(key);
|
|
227
|
+
}
|
|
192
228
|
}
|
|
193
229
|
|
|
194
230
|
export async function inspectProcess(pid: number, generation: number): Promise<ProcessIdentity | undefined> {
|
|
@@ -29,13 +29,29 @@ async function atomicText(path: string, content: string): Promise<void> {
|
|
|
29
29
|
await chmod(path, 0o600);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
const SYSTEMCTL_TIMEOUT_MS = 1_000;
|
|
33
|
+
|
|
34
|
+
export async function runSystemctlUser(
|
|
35
|
+
args: string[],
|
|
36
|
+
command = "systemctl",
|
|
37
|
+
): Promise<{ code: number; stdout: string }> {
|
|
33
38
|
return new Promise(resolve => {
|
|
34
|
-
const child = spawn(
|
|
39
|
+
const child = spawn(command, ["--user", ...args], { stdio: ["ignore", "pipe", "ignore"] });
|
|
35
40
|
let stdout = "";
|
|
41
|
+
let settled = false;
|
|
42
|
+
const finish = (result: { code: number; stdout: string }) => {
|
|
43
|
+
if (settled) return;
|
|
44
|
+
settled = true;
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
resolve(result);
|
|
47
|
+
};
|
|
36
48
|
child.stdout.on("data", chunk => (stdout += String(chunk)));
|
|
37
|
-
child.once("error", () =>
|
|
38
|
-
child.once("close", code =>
|
|
49
|
+
child.once("error", () => finish({ code: 127, stdout: "" }));
|
|
50
|
+
child.once("close", code => finish({ code: code ?? 1, stdout: stdout.trim() }));
|
|
51
|
+
const timeout = setTimeout(() => {
|
|
52
|
+
child.kill("SIGTERM");
|
|
53
|
+
finish({ code: 124, stdout: stdout.trim() });
|
|
54
|
+
}, SYSTEMCTL_TIMEOUT_MS);
|
|
39
55
|
});
|
|
40
56
|
}
|
|
41
57
|
|
|
@@ -45,7 +61,7 @@ export class SystemdUserManager {
|
|
|
45
61
|
configHome: string,
|
|
46
62
|
private readonly executablePath: string,
|
|
47
63
|
private readonly sourceArguments: string[] = [],
|
|
48
|
-
private readonly run: (args: string[]) => Promise<{ code: number; stdout: string }> =
|
|
64
|
+
private readonly run: (args: string[]) => Promise<{ code: number; stdout: string }> = runSystemctlUser,
|
|
49
65
|
) {
|
|
50
66
|
this.unitPath = join(configHome, "systemd", "user", REMOTE_CONTROL_SERVICE);
|
|
51
67
|
}
|