@f5-sales-demo/xcsh 22.13.2 → 22.14.2

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.
Files changed (39) hide show
  1. package/package.json +8 -8
  2. package/src/cli/args.ts +4 -0
  3. package/src/cli/flag-spec.ts +1 -0
  4. package/src/cli.ts +13 -0
  5. package/src/commands/blindfold.ts +80 -0
  6. package/src/commands/context.ts +119 -0
  7. package/src/config/keybindings.ts +2 -0
  8. package/src/config/settings-schema.ts +1 -0
  9. package/src/config/settings.ts +5 -0
  10. package/src/documentation-measurement.ts +84 -0
  11. package/src/internal-urls/api-catalog-qmd-index.generated.ts +2 -2
  12. package/src/internal-urls/api-catalog-resolve.ts +4 -3
  13. package/src/internal-urls/build-info.generated.ts +8 -8
  14. package/src/internal-urls/docs-index.generated.ts +6 -3
  15. package/src/internal-urls/documentation-repository.ts +2 -2
  16. package/src/internal-urls/documentation-resolve.ts +1 -1
  17. package/src/internal-urls/public-citation-destinations.generated.ts +2 -2
  18. package/src/main.ts +1 -0
  19. package/src/modes/components/context-add-wizard.ts +131 -97
  20. package/src/modes/components/context-picker.ts +258 -0
  21. package/src/modes/controllers/context-command-controller.ts +498 -107
  22. package/src/npm-binary-bootstrap.ts +1 -0
  23. package/src/prompts/tools/xcsh-blindfold.md +1 -0
  24. package/src/qmd-smoke.ts +5 -0
  25. package/src/sandbox/enforce.ts +8 -0
  26. package/src/sdk.ts +75 -23
  27. package/src/services/blindfold.ts +312 -0
  28. package/src/services/context-env.ts +3 -2
  29. package/src/services/context-execution.ts +47 -0
  30. package/src/services/context-operations.ts +217 -0
  31. package/src/services/xcsh-context-command.ts +27 -8
  32. package/src/services/xcsh-context.ts +209 -10
  33. package/src/session/agent-session.ts +85 -43
  34. package/src/session/session-manager.ts +12 -1
  35. package/src/slash-commands/builtin-registry.ts +16 -3
  36. package/src/tools/catalog-workflow-runner.ts +13 -8
  37. package/src/tools/index.ts +2 -0
  38. package/src/tools/xcsh-api.ts +45 -7
  39. package/src/tools/xcsh-blindfold.ts +93 -0
@@ -1,5 +1,6 @@
1
1
  import os from "node:os";
2
2
  import path from "node:path";
3
+ import { executionEnvironmentValue } from "../services/context-execution";
3
4
  import {
4
5
  matchesBaselineCatalogDiscoveryTerm,
5
6
  normalizeApiCatalogDiscoveryTerm,
@@ -480,13 +481,13 @@ async function fetchNamespaceInventory(
480
481
  data: Readonly<Record<string, ApiCatalogCategory>>,
481
482
  url: InternalUrl,
482
483
  ): Promise<string> {
483
- const apiBase = (process.env.XCSH_API_URL ?? "").replace(/\/+$/, "");
484
- const apiToken = process.env.XCSH_API_TOKEN ?? "";
484
+ const apiBase = (executionEnvironmentValue("XCSH_API_URL") ?? "").replace(/\/+$/, "");
485
+ const apiToken = executionEnvironmentValue("XCSH_API_TOKEN") ?? "";
485
486
  if (!apiBase || !apiToken) {
486
487
  return "# Namespace Inventory\n\nError: No API credentials configured. Set XCSH_API_URL and XCSH_API_TOKEN, or activate a context.\n";
487
488
  }
488
489
 
489
- const ns = url.searchParams.get("ns") ?? process.env.XCSH_NAMESPACE ?? "default";
490
+ const ns = url.searchParams.get("ns") ?? executionEnvironmentValue("XCSH_NAMESPACE") ?? "default";
490
491
  const CONFIG_PREFIX = "/api/config/namespaces/{namespace}/";
491
492
  const APP_KW =
492
493
  /loadbalancer|pool|firewall|_policys|setting|type|mitigation|identification|network|route|host|definition|rate_limiter|prefix_set|cdn|waf|api_/i;
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "22.13.2",
21
- "commit": "173f41895374c7bc7726f9469b9d1b248dc8cd33",
22
- "shortCommit": "173f418",
20
+ "version": "22.14.2",
21
+ "commit": "b6faf7fc5db0490fbc8206d9401a2fc320401f6e",
22
+ "shortCommit": "b6faf7f",
23
23
  "branch": "main",
24
- "tag": "v22.13.2",
25
- "commitDate": "2026-10-07T03:58:32Z",
26
- "buildDate": "2026-10-07T05:14:01.272Z",
24
+ "tag": "v22.14.2",
25
+ "commitDate": "2026-10-07T06:17:09Z",
26
+ "buildDate": "2026-10-07T07:14:49.586Z",
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/173f41895374c7bc7726f9469b9d1b248dc8cd33",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v22.13.2"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/b6faf7fc5db0490fbc8206d9401a2fc320401f6e",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v22.14.2"
33
33
  };
@@ -1,8 +1,10 @@
1
1
  // Auto-generated by scripts/generate-docs-index.ts - DO NOT EDIT
2
2
 
3
- export const EMBEDDED_DOC_FILENAMES: readonly string[] = ["en/architecture-contribution/agent-session-runtime.mdx","en/architecture-contribution/build-release.mdx","en/architecture-contribution/extension-discovery.mdx","en/architecture-contribution/index.mdx","en/architecture-contribution/native-development.mdx","en/architecture-contribution/native-runtime.mdx","en/architecture-contribution/parallelism-qualification.mdx","en/architecture-contribution/prompt-authoring.mdx","en/architecture-contribution/provider-streaming.mdx","en/architecture-contribution/storage-artifacts.mdx","en/architecture-contribution/tool-runtime.mdx","en/architecture-contribution/tui-runtime.mdx","en/architecture-contribution/tui-style-guide.mdx","en/architecture-contribution/upstream-pi.mdx","en/automate-extend/extensions-custom-tools.mdx","en/automate-extend/headless-protocols.mdx","en/automate-extend/hooks-rules.mdx","en/automate-extend/index.mdx","en/automate-extend/plugins-marketplaces.mdx","en/automate-extend/sdk.mdx","en/automate-extend/skills.mdx","en/configure-secure/environment-reference.mdx","en/configure-secure/index.mdx","en/configure-secure/providers-routing.mdx","en/configure-secure/sandbox-boundaries.mdx","en/configure-secure/secrets-obfuscation.mdx","en/configure-secure/settings-files.mdx","en/f5-distributed-cloud/api-catalog.mdx","en/f5-distributed-cloud/contexts-namespaces.mdx","en/f5-distributed-cloud/create-apply-update.mdx","en/f5-distributed-cloud/get-export-delete.mdx","en/f5-distributed-cloud/index.mdx","en/f5-distributed-cloud/manifest-fundamentals.mdx","en/f5-distributed-cloud/validate-diff.mdx","en/getting-started/first-manifest.mdx","en/getting-started/index.mdx","en/getting-started/model-authentication.mdx","en/index.mdx","en/integrations-deployment/chrome.mdx","en/integrations-deployment/containers.mdx","en/integrations-deployment/herdr.mdx","en/integrations-deployment/index.mdx","en/integrations-deployment/office.mdx","en/integrations-deployment/vscode.mdx","en/reference-troubleshooting/cli-reference.mdx","en/reference-troubleshooting/configuration-schema.mdx","en/reference-troubleshooting/diagnostics.mdx","en/reference-troubleshooting/index.mdx","en/reference-troubleshooting/slash-keybindings.mdx","en/use-xcsh/agent-loop.mdx","en/use-xcsh/built-in-tools.mdx","en/use-xcsh/execution-modes.mdx","en/use-xcsh/index.mdx","en/use-xcsh/interactive-tui.mdx","en/use-xcsh/planning-agents.mdx","en/use-xcsh/sessions-memory.mdx","en/use-xcsh/tui-navigation.mdx","issue-intake.md"];
3
+ export const EMBEDDED_DOC_FILENAMES: readonly string[] = ["development/blindfold-delivery-ledger.md","development/blindfold-protocol.md","en/architecture-contribution/agent-session-runtime.mdx","en/architecture-contribution/build-release.mdx","en/architecture-contribution/extension-discovery.mdx","en/architecture-contribution/index.mdx","en/architecture-contribution/native-development.mdx","en/architecture-contribution/native-runtime.mdx","en/architecture-contribution/parallelism-qualification.mdx","en/architecture-contribution/prompt-authoring.mdx","en/architecture-contribution/provider-streaming.mdx","en/architecture-contribution/storage-artifacts.mdx","en/architecture-contribution/tool-runtime.mdx","en/architecture-contribution/tui-runtime.mdx","en/architecture-contribution/tui-style-guide.mdx","en/architecture-contribution/upstream-pi.mdx","en/automate-extend/extensions-custom-tools.mdx","en/automate-extend/headless-protocols.mdx","en/automate-extend/hooks-rules.mdx","en/automate-extend/index.mdx","en/automate-extend/plugins-marketplaces.mdx","en/automate-extend/sdk.mdx","en/automate-extend/skills.mdx","en/configure-secure/environment-reference.mdx","en/configure-secure/index.mdx","en/configure-secure/providers-routing.mdx","en/configure-secure/sandbox-boundaries.mdx","en/configure-secure/secrets-obfuscation.mdx","en/configure-secure/settings-files.mdx","en/f5-distributed-cloud/api-catalog.mdx","en/f5-distributed-cloud/blindfold-certificates.mdx","en/f5-distributed-cloud/contexts-namespaces.mdx","en/f5-distributed-cloud/create-apply-update.mdx","en/f5-distributed-cloud/get-export-delete.mdx","en/f5-distributed-cloud/index.mdx","en/f5-distributed-cloud/manifest-fundamentals.mdx","en/f5-distributed-cloud/validate-diff.mdx","en/getting-started/first-manifest.mdx","en/getting-started/index.mdx","en/getting-started/model-authentication.mdx","en/index.mdx","en/integrations-deployment/chrome.mdx","en/integrations-deployment/containers.mdx","en/integrations-deployment/herdr.mdx","en/integrations-deployment/index.mdx","en/integrations-deployment/office.mdx","en/integrations-deployment/vscode.mdx","en/reference-troubleshooting/cli-reference.mdx","en/reference-troubleshooting/configuration-schema.mdx","en/reference-troubleshooting/diagnostics.mdx","en/reference-troubleshooting/index.mdx","en/reference-troubleshooting/slash-keybindings.mdx","en/use-xcsh/agent-loop.mdx","en/use-xcsh/built-in-tools.mdx","en/use-xcsh/execution-modes.mdx","en/use-xcsh/index.mdx","en/use-xcsh/interactive-tui.mdx","en/use-xcsh/planning-agents.mdx","en/use-xcsh/sessions-memory.mdx","en/use-xcsh/tui-navigation.mdx","issue-intake.md"];
4
4
 
5
5
  export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
6
+ "development/blindfold-delivery-ledger.md": "# Issue 4750 delivery ledger\n\nCandidate base: `9bebb2ecc9763c343cf21162b5f1198ade67d003` (`origin/main`, v22.13.0).\nBranch: `feature/issue-4750-native-blindfold`; fresh Ubuntu worktree under `.worktrees/feature/issue-4750-native-blindfold`.\n\n## Planning and audit\n\nImplement one Rust native input/encryption boundary, shared TypeScript service, CLI and assistant adapters. Follow the binary contract in `blindfold-protocol.md`; preserve complete\npublic exponent and avoid the retired provider's OAEP format. Deploy only owned lab resources. Credentials and test CA/key/runtime evidence stay outside the checkout. Repository\nnamed rigor skills were unavailable; planning, TDD evidence and this completion ledger record the required process directly.\n\n## Acceptance ledger\n\n| Check | Command or operation | Expected | Actual | Evidence |\n| --- | --- | --- | --- | --- |\n| Bootstrap | `bash scripts/ci-bun-install.sh`; `bun scripts/ensure-dev-native.ts` | Source-matched addon | Passed | Private bootstrap logs; native receipts |\n| TDD red | `bun test packages/natives/test/blindfold.test.ts` | Missing new native export | Failed on missing blindfoldPrepare | Session test transcript |\n| Service TDD red | `bun test packages/coding-agent/test/blindfold-service.test.ts` | Missing shared service | Failed on absent module | Session test transcript |\n| Native inputs/protocol | Focused three-file tests | Independent secret recovery; supported formats; failure boundaries | 27 passed, 118 assertions | Public native-live receipt |\n| TypeScript | `bun run check:ts` | All checks pass | Passed before temporary packaging loader reset | Private check logs |\n| Rust | all-target Clippy, `bun run test:rs` | Pass | Passed | Private Rust logs |\n| Package | `bun --cwd=packages/coding-agent run build` | Standalone CLI | Passed | Private build log |\n| Package runtime | Compiled CLI help, dry-run, explicit replace | Native runtime and tenant readback | Passed | Public native-live receipt |\n| Containment | Scan 29 captured requests/results/logs/reports | No plaintext keys/tokens | Zero leaks | Public native-live receipt |\n| Live RSA | `bun run dev blindfold create`; fixed-response LB create; TLS | Trusted SNI/VIP TLS, matching fingerprint, HTTP 200 | TLS 1.3, matching RSA fingerprint, HTTP 200 | Public sanitized receipt; private runtime |\n| Rotation | `bun run dev blindfold replace` second RSA pair; TLS | New fingerprint and HTTP 200 | Passed | Public sanitized receipt |\n| Rejected rotation | RSA to EC on referenced resource | Existing certificate remains working | F5 HTTP 400; original RSA TLS intact | Public sanitized receipt |\n| Live EC | Separate EC certificate, LB reference update; TLS | EC fingerprint and HTTPS | Passed | Public sanitized receipt |\n| Retained demo | Restore rotated RSA LB reference; remove auxiliary EC | Final working demo; auxiliary absent | RSA TLS verified; EC GET 404 | Private ownership/expiry/teardown record |\n| Docs | docs-quality, unittest, PII enforcement | Source-backed guide and safe evidence | Passed; 28 checker tests | docs/en guide and evidence manifest |\n| Full TS suite | `bun run test:ts` after prescribed optional-loader reset | Full pass | Unqualified: unrelated five-second test timeouts; isolated plugin/Office checks passed; hosted CI required | Private stable-suite log |\n| Hosted native matrix | Existing CI full_native_matrix | All supported platforms | Pending | Future workflow receipts |\n| Delivery | Commit/push/linked PR/CI/merge/release | Released installation and public docs | Commit d48ba1b2b, PR #4752; CI/release pending | Issue #4750 |\n\nCompletion requires the final delivery rows. Local packaging acceptance is distinct from released-installation acceptance. The retained demo expires 30 days after its private creation timestamp; ownership, CA and teardown commands are recorded privately. No provider function integration is included.\n",
7
+ "development/blindfold-protocol.md": "# Blindfold protocol contract\n\nThis contract was recovered from vesctl 0.2.47 offline synthetic encryption and independently decrypted before implementation. The runtime uses bundled OpenSSL and native code;\nvesctl is not a dependency. Synthetic tests exercise recovery independently with Node crypto and big integers. Live certificate TLS acceptance verifies F5 decryption for RSA and EC\ninputs.\n\nAll envelope lengths are unsigned 32-bit big-endian. All integers use big-endian encoding. RSA exponent and modulus are unsigned, minimally encoded, length-prefixed byte strings. The complete public exponent is preserved.\n\n| Field | Encoding |\n| --- | --- |\n| Tenant | Length-prefixed UTF-8 canonical tenant ID |\n| Key version | Unsigned 32-bit big-endian |\n| Policy ID | Unsigned 64-bit big-endian |\n| Algorithm | One byte, value 2 |\n| Public exponent | Length-prefixed unsigned big-endian bytes |\n| Public modulus | Length-prefixed unsigned big-endian bytes |\n| Wrapped key block | Length-prefixed RSA modulus-width bytes |\n| Encrypted secret | AES-256-GCM ciphertext followed by 16-byte tag; no length prefix |\n\nFor policy ID `p` and original exponent `e`, the effective RSA exponent is `e * (2*p + 2^31 + 1)`. Arithmetic must not truncate the policy or exponent.\n\nConstruct a random block of modulus byte width minus two. Set bytes 0–3 to `de ad be ef`. Bytes 4–15 are the 12-byte GCM nonce; bytes 16–47 are the 32-byte AES key. The remaining\nbytes remain random. Interpret the block as an unsigned integer and compute its modular exponentiation with the effective exponent and modulus. Serialize the wrapped result at the\nfull modulus byte width. GCM uses empty additional authenticated data. Base64-encode the entire envelope and prefix `string:///`.\n\nThe synthetic reference used a generated 2048-bit RSA key, policy 101, and a 2048-byte secret. Independently deriving the private exponent modulo the RSA group order recovered\n`deadbeef`, the nonce, AES key and the entire plaintext. Wrong-policy recovery and altered GCM ciphertext must fail. Production code contains no decryption endpoint.\n\nPrivate input buffers, normalized key PEM and AES key block use zeroizing native allocations. OpenSSL owns parsed private-key allocations; the intermediate RSA plaintext big\ninteger is cleared after use. The native API returns only encrypted material and public certificate metadata. Service/tool results exclude encrypted payloads; requested artifacts\nstay on disk.\n",
6
8
  "en/architecture-contribution/agent-session-runtime.mdx": "---\ntitle: \"Agent loop and sessions\"\ndescription: \"Trace a user message through model selection, tool calls, append-only session state, compaction, and rendering.\"\nsidebar:\n order: 1\n label: \"Agent loop and sessions\"\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 command-line interface (CLI) parses arguments, resolves configuration and providers, creates a session, streams model events, dispatches tools, and renders the resulting entries.\n\n```text\nuser message\n -> cli.ts parse argv, resolve config and providers\n -> session factory create or resume the session\n -> provider stream AssistantMessageEvent deltas\n -> tool dispatch execute, append result, loop\n -> session JSONL append-only record\n -> renderer view of the appended state\n```\n\n## How do I trace a behavior?\n\nStart at `packages/coding-agent/src/cli.ts`, follow the session factory and event handlers, then inspect the persisted JSON Lines (JSONL) rather than relying only on terminal rendering. Provider and tool tests should assert the event sequence that caused the visible result.\n\n## Where does compaction act?\n\nCompaction transforms older conversation context before the next model turn; it does not rewrite the original session evidence. Test both the summary and subsequent message construction.\n\nTrace a normal response, a tool-producing response, and an aborted response separately. Each path\nmust append events in causal order, settle an active provider or tool only once, and leave a\nresumable leaf. To test compaction, force the configured threshold, capture the summary entry,\nresume from that leaf, and verify that the next model input includes the summary while the original\nJSONL entries remain readable. Rendering assertions belong after these state assertions because the\nTUI can repaint without changing the durable graph.\n",
7
9
  "en/architecture-contribution/build-release.mdx": "---\ntitle: \"Build and release xcsh\"\ndescription: \"Set up the monorepo, run TypeScript and Rust checks, and understand signed multi-channel releases.\"\nsidebar:\n order: 11\n label: \"Build and release xcsh\"\n---\n\nThe repository is a Bun workspace with a Rust native layer. Follow `AGENTS.md`, `CONTRIBUTING.md`, and `DEVELOPING.md` before editing.\n\n## How do I prepare a contribution?\n\nCreate a detailed issue, branch from current `origin/main` in an isolated worktree, and run `bun install --frozen-lockfile`. Write a failing focused test for code behavior, implement the smallest fix, then run the package and repository checks.\n\n## Which checks matter before a pull request?\n\nRun each gate before you open the pull request:\n\n1. `bun run check` for formatting, linting, and types.\n2. `bun run test` for the package suites.\n3. `python3 scripts/check_docs_quality.py` when an English MDX file changed.\n4. The secret and personally identifiable information (PII) scans.\n5. The repository review gate.\n\nInspect the complete diff, then deliver only through a linked pull request.\n\n## How are releases produced?\n\nProtected workflows build and verify binaries, npm packages, Homebrew artifacts, containers, and downstream apt packaging. Contributors do not publish those channels manually.\n\nBefore pushing, confirm `git diff --check`, inspect every staged path, and run the narrowest package\ntest that exercises the change. A documentation-only change does not authorize a release. A release\nworkflow owns versioning, signing, publication, and provenance checks; a contributor-owned command\nstops at the pull request boundary. If a gate fails, reproduce it from the same commit instead of\nbypassing the gate or substituting an older artifact.\n",
8
10
  "en/architecture-contribution/extension-discovery.mdx": "---\ntitle: \"Extension discovery architecture\"\ndescription: \"Choose between skills, commands, tools, hooks, extensions, plugins, and SDK embedding.\"\nsidebar:\n order: 5\n label: \"Extension discovery\"\n---\n\nThe TypeScript runtime owns the agent loop, configuration, discovery, protocols, and most tools. The native Rust addon supplies performance-sensitive terminal, filesystem, and platform operations behind typed bindings.\n\n## How are capabilities discovered?\n\nDiscovery providers scan bundled, user, project, plugin, and compatible manifest roots, normalize candidates into capability items, and deduplicate stable identifiers by precedence. Extension entry resolution and dynamic module loading happen only after metadata discovery.\n\nInvalid frontmatter, manifests, or module factories produce diagnostics at their own layer so one bad optional capability does not masquerade as an empty catalog.\n\n## Where should a change go?\n\nPrefer a public extension, skill, plugin, or software development kit (SDK) application programming interface (API) for optional behavior. Change the native layer only when a measured platform or performance requirement cannot be met in TypeScript.\n\n## How do I validate a boundary change?\n\nRun focused TypeScript tests for the caller and Rust tests for the native implementation, then build the addon and exercise the public command. Do not expose a native detail as a public contract accidentally.\n\nRead `packages/coding-agent/src/discovery` for the provider scan and deduplication, and `packages/coding-agent/src/capability` for the normalized capability items.\n\nWhen two providers expose the same identifier, the higher-precedence normalized item wins; discovery\ndoes not merge two implementations. Test both the winning provider and the diagnostic for the\nshadowed or invalid candidate. After changing discovery, start with all optional sources disabled,\nenable one source at a time, and confirm that removal or reload clears its capabilities instead of\nleaving a stale registration.\n",
@@ -31,10 +33,11 @@ export const EMBEDDED_DOCS: Readonly<Record<string, string>> = {
31
33
  "en/configure-secure/secrets-obfuscation.mdx": "---\ntitle: \"Resolve secrets safely\"\ndescription: \"Reference sensitive values without placing plaintext credentials in prompts, manifests, logs, or commits.\"\nsidebar:\n order: 4\n label: \"Resolve secrets safely\"\n---\n\nKeep provider keys and F5 Distributed Cloud contexts outside prompts, session exports, logs, and committed files. Pass secrets through supported environment or protected runtime files.\n\n## How does obfuscation work?\n\nWhen secret obfuscation is enabled, values declared in the protected `secrets.yml` source are resolved at runtime and replaced in observable text before it is retained or rendered. Environment values take their documented precedence over file-backed values.\n\nObfuscation reduces accidental disclosure in supported paths; it is not encryption for a compromised process or an excuse to place secrets in prompts.\n\n## How does the filesystem boundary work?\n\nxcsh discovers a task root and guards access outside it. Add an explicit path with `--allow-path`; use `--allow-home` only when the home directory is intentionally the task root. `--no-sandbox` removes that guard and should be reserved for a controlled diagnostic.\n\n## How do I inspect the boundary?\n\nRun `xcsh sandbox check`, then start a read-only session with the smallest required `--allow-path` set. A sandbox boundary limits file discovery; it does not replace operating-system permissions or tool review.\n\nRedaction reduces accidental disclosure in model and display paths; it is not encryption and does\nnot make a committed secret safe. Test with a synthetic value in an isolated process, inspect the\nprompt, tool result, logs, and exported session, then unset the value and remove the temporary rule.\nIf any surface retains the literal, stop before using a real credential and correct the boundary\nthat emitted it.\n",
32
34
  "en/configure-secure/settings-files.mdx": "---\ntitle: \"Understand settings precedence\"\ndescription: \"Predict which user, project, environment, and command-line value xcsh resolves.\"\nsidebar:\n order: 1\n label: \"Settings precedence\"\n---\n\nProject settings apply to one repository; user settings apply across projects; command flags override both for one invocation. Use `xcsh config list --json` to inspect effective values.\n\n## How is configuration resolved?\n\nDiscovery collects fixed user, project, environment, and command-line sources, normalizes each through the schema-backed configuration wrapper, then resolves values by explicit priority. Capability-specific discovery uses the same roots but owns its own merge and deduplication rules. Native `.xcsh` providers participate through the documented provider interface, not an implicit recursive scan.\n\n## Where are settings stored?\n\nRun `xcsh config path` instead of assuming a platform path. Project data uses `.xcsh/`, including `settings.json`, contexts, skills, agents, extensions, tools, hooks, commands, and `XCSH.md`. Primary user data lives under the xcsh agent directory; `PI_CODING_AGENT_DIR` can override that location.\n\n## How do I change one value?\n\n```bash\nxcsh config get <KEY>\nxcsh config set <KEY> <VALUE>\nxcsh config reset <KEY>\n```\n\nUse environment variables for credentials and ephemeral process configuration. Do not copy an entire old settings file when only one key is needed.\n\nChange one key in the narrowest applicable scope and restart xcsh before judging precedence. Use `/settings` or a schema-backed read path to inspect the effective value; do not infer it from the file you edited. Project settings can affect collaborators, while user settings affect other worktrees on the same account. Revert the test key and confirm a new process resolves the prior value.\n",
33
35
  "en/f5-distributed-cloud/api-catalog.mdx": "---\ntitle: \"Understand the API catalog\"\ndescription: \"See how xcsh resolves resource kinds and validation metadata from its packaged F5 Distributed Cloud catalog.\"\nsidebar:\n order: 6\n label: \"API catalog\"\n---\n\nThe catalog maps a supported `kind` to its application programming interface (API) path and schema handling. It is the authority for whether a resource can use deterministic commands.\n\n## How do I choose a supported kind?\n\nUse catalog discovery in the interactive shell, or inspect the generated resource catalog in the matching xcsh source release. Copy the exact `kind` spelling into the manifest.\n\n## What if a kind is absent?\n\nDo not substitute a similar name. Use console automation only when that interface is explicitly supported, or wait for catalog support. An absent kind cannot be made safe by adding arbitrary fields to a manifest.\n\nThe catalog is a normalized view of resource metadata used by resource commands; it is not evidence\nthat the active credential may mutate every listed kind. Resolve a kind, inspect its schema and\nscope, and distinguish namespace-scoped from system-scoped resources before building a manifest. An\nabsent kind blocks the workflow: verify the installed xcsh version and catalog source instead of\nguessing an endpoint or plural name.\n",
34
- "en/f5-distributed-cloud/contexts-namespaces.mdx": "---\ntitle: \"Manage contexts and namespaces\"\ndescription: \"Store named tenant connections, activate the intended context, and scope operations to a namespace.\"\nsidebar:\n order: 1\n label: \"Contexts and namespaces\"\n---\n\nA context chooses the tenant endpoint and credential. A namespace chooses the resource scope inside that tenant. They are separate decisions.\n\n## How do I prevent a scope mistake?\n\nLaunch with `xcsh --context <NAME>` and inspect `/context status`. For automation, pass `-n <NAMESPACE>` to the resource command instead of relying on ambient state. Stop if either value is unexpected.\n\n## Where is context data stored?\n\nContext files live under `.xcsh/contexts/` at project scope or the xcsh user data directory. Never commit them: they can contain credentials and tenant identifiers.\n\nSelect context and namespace before any live read or write, then issue a read-only command for an\nexpected resource and inspect the returned tenant scope. Context files contain connection metadata\nand may reference credentials; keep them out of repositories and transcripts. Changing the active\nscope affects later commands only. After a temporary test, restore the prior context and namespace\nand repeat the read-only check.\n",
36
+ "en/f5-distributed-cloud/blindfold-certificates.mdx": "---\ntitle: \"Encrypt and deploy TLS certificates\"\ndescription: \"Blindfold private keys locally, create certificate resources, and verify certificate rotation over HTTPS.\"\nsidebar:\n order: 7\n label: \"Blindfold certificates\"\n---\n\nUse `xcsh blindfold` to encrypt private keys with your tenant's public key before creating a certificate resource. RSA and EC keys, encrypted PEM, and single-key PKCS#12 bundles are parsed inside the native module. The installed command requires neither vesctl nor an OpenSSL executable.\n\n[Choose the context and namespace](/xcsh/en/f5-distributed-cloud/contexts-namespaces/) first. Commands use the existing xcsh context and environment rules; certificate namespace\ndefaults to `XCSH_NAMESPACE`, and secret policy defaults to `shared/ves-io-allow-volterra`. The policy and public key must identify the same canonical tenant.\n\n## Retrieve public encryption material\n\n```bash\nxcsh blindfold public-key --output-file tenant-public-key.json\nxcsh blindfold policy --policy shared/ves-io-allow-volterra --output-file policy.json\n```\n\nThese operations authenticate to the selected tenant. Output files must be new; the command publishes them atomically with owner-only permissions. Tenant public material can contain tenant identity, so keep it in your runtime directory.\n\n## Encrypt a secret or prepare a certificate manifest\n\n```bash\nxcsh blindfold encrypt --input secret.txt --output-file secret.blindfold\nxcsh blindfold certificate --cert chain.pem --key server-key.pem \\\n --name example-tls --output-file certificate.json --result-file prepared.json\n```\n\n`chain.pem` must list the leaf certificate first, then its issuers. The native parser verifies key correspondence, chain signatures and order, validity dates, supported algorithms,\nand encoded size. Supported keys are RSA 2048–8192 bits and EC P-256/P-384. Encoded secret locations and certificate chains are limited to 131072 bytes each.\n\nThe manifest encodes the public chain in `spec.certificate_url` and places the encrypted key in `spec.private_key.blindfold_secret_info.location`. It never emits a clear-key\nalternative. Raw encryption and manifest preparation print their artifact when no output file or `--json` is selected; use an output file to keep encrypted payloads out of\ntranscripts.\n\n## Use protected PEM and PKCS#12 inputs\n\nSet a passphrase variable through your shell's protected input or secret manager. Supply only its name:\n\n```bash\nxcsh blindfold certificate --cert chain.pem --key protected-key.pem \\\n --passphrase-env TLS_INPUT_PASSWORD --name example-tls --output-file protected.json\nxcsh blindfold certificate --bundle server.p12 --passphrase-env TLS_INPUT_PASSWORD \\\n --name example-tls --output-file bundle.json\n```\n\nDo not put literal passwords on the command line. Choose either a bundle or separate certificate/key files. Bundles containing more than one private key fail before deployment, even when aliases collide.\n\n## Create and rotate a certificate\n\n```bash\nxcsh blindfold create --cert chain.pem --key server-key.pem --name example-tls \\\n --dry-run=client --json --result-file preview.json\nxcsh blindfold create --cert chain.pem --key server-key.pem --name example-tls \\\n --json --result-file created.json\nxcsh blindfold replace --cert rotated-chain.pem --key rotated-key.pem --name example-tls \\\n --json --result-file rotated.json\n```\n\nUse different report paths for each run. Client dry runs retrieve public material and inspect the target but perform no tenant writes. Creation fails on an existing name; replacement fails when absent. Replacement preserves the writable metadata and certificate options returned by F5's replace form.\n\nF5 rejects a public-key algorithm change while another object uses the certificate. Rotate RSA to RSA or EC to EC. To change algorithms, create another certificate and change the\nload balancer's certificate reference. A rejected algorithm change left the previously served RSA certificate working during live acceptance.\n\n## Verify HTTPS after API acceptance\n\nAn `accepted` report means named readback matched the submitted certificate and encrypted key. Its readiness is `unverified`: load-balancer propagation and TLS must be checked separately.\n\nFor a load balancer referencing the certificate, connect to its allocated VIP with the certificate's intended SNI. Trust your issuing CA and compare the served fingerprint with the public report:\n\n```bash\ncurl --cacert ca.pem --resolve example.test:443:192.0.2.10 https://example.test/\n```\n\nReplace the example hostname and address with your owned load balancer's values. Live source acceptance used a private test CA and a fixed-response route: RSA creation, rotation to\na second RSA pair, and a separate EC certificate each returned HTTP 200 over TLS 1.3 with the expected served SHA-256 fingerprint. The final RSA demo was restored and verified\nafter EC acceptance.\n\n## Resolve failures and uncertain writes\n\nA wrong password, mismatched key, malformed certificate, expired chain, denied policy, or oversized payload fails before deployment. If a request outcome is uncertain, the service\nreads the named resource once before reporting success or an unresolved outcome; it does not automatically retry a mutation. Inspect the named resource and its current fingerprint\nbefore retrying.\n\nArtifacts require a new destination in an existing writable directory. A cancelled operation stops subsequent work; cancellation after a write can require a named read to determine\nits outcome. The `xcsh_blindfold` assistant tool accepts file paths and a passphrase environment-variable name, and returns public status, target, fingerprint, and artifact paths.\nIt keeps private keys, passwords, tokens, and encrypted payloads out of tool results. Session file-access controls apply to each input and output. Plan Mode blocks deployments and\nartifact writing.\n\n## Tear down an owned demo\n\nRemove the load balancer first, then the certificate it references:\n\n```bash\nxcsh delete http_loadbalancer example-tls-demo -n example-ns\nxcsh delete certificate example-tls -n example-ns\n```\n\nVerify both named resources are absent. Remove your local private keys, bundles, passphrase variables, and runtime artifacts according to your team's retention policy. Keep ownership and expiry records private for any demo you intentionally retain.\n",
37
+ "en/f5-distributed-cloud/contexts-namespaces.mdx": "---\ntitle: \"Manage contexts and namespaces\"\ndescription: \"Select a tenant, check its connection, and manage saved context configuration.\"\nsidebar:\n order: 1\n label: \"Contexts and namespaces\"\n---\n\nA context chooses the tenant endpoint and API credential. A namespace chooses the resource scope inside that tenant.\n\n## How do I prevent a scope mistake?\n\nRun `/context` to open the picker. Type to search names, endpoints, namespaces or storage sources. Use Up/Down and Page Up/Page Down to move, then Enter to select. The active context receives initial focus. Local and global contexts with the same name remain separate choices.\n\nSelection applies immediately to future turns.\n`Checking` means authentication is still running; `Connected` confirms it succeeded. A failed check retains the selection and offers recovery through context actions. Running work, retries and descendant jobs retain the context captured when their turn began. When a selection differs from running work, xcsh displays `Current work: A · Next turn: B`.\n\nUse Ctrl+O for details, validation, editing, namespace, rename, deletion, environment and project-link actions.\nCustomize this binding as `app.context.actions` in keybindings. Escape returns one level; at the root it closes the picker.\n`/context list` is an explicit read-only report. `/context show NAME` displays saved details without contacting the tenant; `/context validate NAME` checks credentials separately.\n\nAn explicit `/context activate NAME`, `/context NAME` or `/context -` switches immediately. Unqualified names select global contexts. To select a local inline context or project pointer, use its local picker row.\n\n## Create or edit a context\n\nRun `/context create` or choose Create context. Enter the HTTPS tenant URL, masked API token and context name. Validation happens before the default namespace and review. Failed validation offers retry or correction while retaining other draft values. Console credentials are optional and available from the review.\n\nThe review starts on Cancel and offers Save and activate or Save only. No file is written when a draft or review is cancelled. Save only leaves the context inactive. If saving succeeds but activation fails, retry completes activation without rewriting the saved file.\n\nRun `/context edit NAME` or select Edit in context actions. Saved values are prefilled. Leave token input empty to keep the saved token; enter a replacement explicitly. Changed credentials validate before saving. Editing preserves metadata, environment, knowledge sources and skill configuration. Renaming has a separate action.\n\n## Where is context data stored?\n\nGlobal files live under `~/.config/xcsh/contexts/`, or `$XDG_CONFIG_HOME/xcsh/contexts/`. Project files live under `.xcsh/contexts/`. Keep credential-bearing files out of Git and shared transcripts.\n\nA project pointer links a local name to a global context. Its namespace and environment overrides remain in the project. URL or token editing opens the linked global context and identifies that scope. Inline local contexts remain local.\n\n`/context namespace` opens the session namespace selector with manual entry. `/context namespace NAME` applies a runtime override. It does not change the saved default. Validate the tenant and namespace with a read-only resource request before performing live work.\n\nIf `XCSH_API_URL` is set in the process environment, it overrides saved selection. Unset it and restart before choosing a saved context. Token and namespace environment overrides retain their existing precedence.\n\n## Automate management\n\n`xcsh context` runs without menus or model inference. Bare invocation lists saved contexts. Use `--json` for structured output. Management commands require explicit names; `--source global` is the default, and `--source local` selects project storage.\n\n```sh\nxcsh context list --json\nxcsh context show demo --source global --json\nxcsh context validate demo --json\nxcsh context create demo https://tenant.example.test --token-stdin < token.txt\nxcsh context edit demo --namespace app\nxcsh context edit demo --token-stdin < replacement-token.txt\nxcsh context rename demo demonstration\nxcsh context delete demonstration --confirm\nxcsh context link project-demo demo --source local\nxcsh context unlink project-demo --source local\nxcsh context env demo set XCSH_REGION=example\nxcsh context env demo unset XCSH_REGION\nxcsh context import bundle.json --overwrite --json\nxcsh context import - --json < bundle.json\nxcsh context export demo > masked-bundle.json\n```\n\nOrdinary output masks credentials and sensitive environment values. Export emits the global bundle directly and masks tokens by default. An importable secret-bearing export requires explicit `--include-token`; protect that file privately. Imports preserve the existing bundle version, overwrite and masking rules.\n\nUsage errors exit 2, execution or authentication failures exit 1, and success exits 0. CLI commands never prompt for confirmation. Deletion requires `--confirm`.\n\nSession selection is explicit at launch:\n\n```sh\nxcsh --context demo\nxcsh --context project-demo --context-source local\n```\n\nThere is no persistent global switch command. For scripted resource operations, pass an explicit namespace rather than relying on ambient session state.\n",
35
38
  "en/f5-distributed-cloud/create-apply-update.mdx": "---\ntitle: \"Create, apply, and update resources\"\ndescription: \"Choose strict creation, convergent apply, or explicit update for a reviewed manifest.\"\nsidebar:\n order: 4\n label: \"Create and update\"\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\n`create` requires absence, `update` requires an existing resource, and `apply` chooses create or update while preserving already-matching resources.\n\n## Which mutation command fits?\n\n```bash\nxcsh create -f manifest.yaml --dry-run client --result-file create-preview.json\nxcsh update -f manifest.yaml --dry-run client --result-file update-preview.json\nxcsh apply -f manifest.yaml --dry-run client --result-file apply-preview.json\n```\n\nReview the preview, then repeat the same command without `--dry-run client`. Keep `--result-file` so automation can inspect the aggregate operation record.\n\n## How do I verify the mutation?\n\nRun `xcsh get <KIND> <NAME> -n <NAMESPACE>` and compare the returned identity and relevant fields with the manifest. Do not treat process exit alone as state verification.\n",
36
39
  "en/f5-distributed-cloud/get-export-delete.mdx": "---\ntitle: \"Get, export, and delete resources\"\ndescription: \"Inspect live resources, produce portable manifests, and perform deliberate deletion.\"\nsidebar:\n order: 5\n label: \"Get, export, delete\"\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\nUse `get` to inspect live state, `export` to create a reusable manifest, and `delete` only after verifying the exact identity and namespace.\n\n## How do I retrieve or export one resource?\n\n```bash\nxcsh get <KIND> <NAME> -n <NAMESPACE> --result-file get.json\nxcsh export <KIND> <NAME> -n <NAMESPACE> -f exported.yaml\n```\n\nSanitize exported server metadata and secrets before storing the file.\n\n## How do I delete and prove absence?\n\n```bash\nxcsh delete <KIND> <NAME> -n <NAMESPACE> --dry-run client\nxcsh delete <KIND> <NAME> -n <NAMESPACE> --result-file delete.json\nxcsh get <KIND> <NAME> -n <NAMESPACE>\n```\n\nThe final `get` must return the documented not-found response for the resource kind. A successful delete request without the absence check is incomplete.\n",
37
- "en/f5-distributed-cloud/index.mdx": "---\ntitle: \"F5 Distributed Cloud\"\ndescription: \"Manage F5 Distributed Cloud contexts and resources through explicit, reviewable manifest operations.\"\nsidebar:\n order: 0\n label: \"Overview\"\n---\n\nThe resource commands separate local validation, live comparison, mutation, retrieval, and cleanup. Keep those stages separate so a credentialed command is deliberate.\n\n## Which resource task do I need?\n\n- [Choose context and namespace](/xcsh/en/f5-distributed-cloud/contexts-namespaces/) before a live request.\n- [Find a kind in the catalog](/xcsh/en/f5-distributed-cloud/api-catalog/) and build a [manifest](/xcsh/en/f5-distributed-cloud/manifest-fundamentals/).\n- [Validate and diff](/xcsh/en/f5-distributed-cloud/validate-diff/) before [create, apply, or update](/xcsh/en/f5-distributed-cloud/create-apply-update/).\n- [Get, export, or delete](/xcsh/en/f5-distributed-cloud/get-export-delete/) existing resources.\n- Use [console automation](/xcsh/en/integrations-deployment/chrome/) only for a supported interface task that has no resource-command equivalent.\n",
40
+ "en/f5-distributed-cloud/index.mdx": "---\ntitle: \"F5 Distributed Cloud\"\ndescription: \"Manage F5 Distributed Cloud contexts and resources through explicit, reviewable manifest operations.\"\nsidebar:\n order: 0\n label: \"Overview\"\n---\n\nThe resource commands separate local validation, live comparison, mutation, retrieval, and cleanup. Keep those stages separate so a credentialed command is deliberate.\n\n## Which resource task do I need?\n\n- [Choose context and namespace](/xcsh/en/f5-distributed-cloud/contexts-namespaces/) before a live request.\n- [Find a kind in the catalog](/xcsh/en/f5-distributed-cloud/api-catalog/) and build a [manifest](/xcsh/en/f5-distributed-cloud/manifest-fundamentals/).\n- [Validate and diff](/xcsh/en/f5-distributed-cloud/validate-diff/) before [create, apply, or update](/xcsh/en/f5-distributed-cloud/create-apply-update/).\n- [Get, export, or delete](/xcsh/en/f5-distributed-cloud/get-export-delete/) existing resources.\n- [Encrypt and deploy TLS certificates](/xcsh/en/f5-distributed-cloud/blindfold-certificates/) with native Blindfold.\n- Use [console automation](/xcsh/en/integrations-deployment/chrome/) only for a supported interface task that has no resource-command equivalent.\n",
38
41
  "en/f5-distributed-cloud/manifest-fundamentals.mdx": "---\ntitle: \"Write resource manifests\"\ndescription: \"Represent an F5 Distributed Cloud resource with a stable kind, metadata, and specification.\"\nsidebar:\n order: 2\n label: \"Write resource manifests\"\n---\n\nEach manifest describes desired state for one resource. `metadata.name` identifies it, `metadata.namespace` selects its scope when supported, and `spec` contains kind-specific data.\n\n## How should I create a starting manifest?\n\nPrefer `xcsh export <KIND> <NAME> -f exported.yaml` for an existing resource. For a new resource, start from a repository example tied to the current catalog. Remove server-managed fields before reuse.\n\n## How do I keep a directory deterministic?\n\nUse one resource per YAML document, stable names, and explicit namespaces. Run `xcsh validate -f manifests/ -R` so nested files are included intentionally.\n\nStart from the catalog schema for the exact kind and keep one resource per manifest while learning.\nSet metadata, namespace, and required specification fields explicitly; omit server-owned status and\nidentifiers. Run local validation before any command that contacts the tenant, then run a live diff\nin the selected context. A clean local parse does not prove authorization, existence, or a safe\nremote change.\n",
39
42
  "en/f5-distributed-cloud/validate-diff.mdx": "---\ntitle: \"Validate and diff manifests\"\ndescription: \"Catch local schema errors first, then compare desired state with live state.\"\nsidebar:\n order: 3\n label: \"Validate and diff\"\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\nValidation checks local structure; diff compares that desired state with the live resource. A passing validation does not authorize or predict a live mutation.\n\n## How do I separate local and live checks?\n\n```bash\nxcsh validate -f manifests/ -R --result-file validation.json\nxcsh diff -f manifests/ -R --result-file diff.json\n```\n\nThe first command needs no application programming interface (API) credential. Run the second only after confirming the context and namespace. Read every create, update, preserve, and error entry in `diff.json`.\n\n## What blocks the next step?\n\nStop on an unknown kind, duplicate identity, unexpected namespace, destructive difference, or request against the wrong context. Correct the source manifest and rerun both commands.\n",
40
43
  "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",
@@ -351,9 +351,9 @@ function searchRows(
351
351
  return database
352
352
  .query(`WITH scored AS (
353
353
  SELECT dd.*, p.anchor, p.heading, p.markdown AS passage_markdown, p.ordinal,
354
- ABS(bm25(documents_fts, 1.5, 4.0, 1.0)) /
354
+ ROUND(ABS(bm25(documents_fts, 1.5, 4.0, 1.0)) /
355
355
  (1.0 + ABS(bm25(documents_fts, 1.5, 4.0, 1.0))) *
356
- CASE dd.lifecycle WHEN 'deprecated' THEN 0.85 WHEN 'superseded' THEN 0.65 ELSE 1.0 END AS score
356
+ CASE dd.lifecycle WHEN 'deprecated' THEN 0.85 WHEN 'superseded' THEN 0.65 ELSE 1.0 END, 12) AS score
357
357
  FROM documents_fts
358
358
  JOIN documents d ON d.id = documents_fts.rowid
359
359
  JOIN documentation_passages p ON p.source = d.collection AND p.qmd_path = d.path
@@ -284,7 +284,7 @@ export function createDocumentationResolver(repository: DocumentationRepository)
284
284
  const rawAnchor = url.hash.startsWith("#") ? url.hash.slice(1) : url.hash;
285
285
  if (/%(?:2f|5c|2e)/i.test(rawAnchor)) throw new Error("Invalid documentation anchor");
286
286
  const anchor = rawAnchor ? decodeURIComponent(rawAnchor) : undefined;
287
- if (anchor && (anchor.length > 256 || !/^[\p{L}\p{N}\p{M}_-]+$/u.test(anchor)))
287
+ if (anchor && (anchor.length > 1024 || !/^[\p{L}\p{N}\p{M}_-]+$/u.test(anchor)))
288
288
  throw new Error("Invalid documentation anchor");
289
289
  const document = await repository.readDocument(source, stablePath, anchor);
290
290
  if (!document) throw new Error(`Documentation file not found: ${source}/${stablePath}/index.md`);