@f5-sales-demo/xcsh 22.3.1 → 22.3.3

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.
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "22.3.1",
21
- "commit": "978281d4e8d54aa7f114e6925cdcdae2837504ce",
22
- "shortCommit": "978281d",
20
+ "version": "22.3.3",
21
+ "commit": "82917afa08ee15956c363dacfb1c0f4511c74d3e",
22
+ "shortCommit": "82917af",
23
23
  "branch": "main",
24
- "tag": "v22.3.1",
25
- "commitDate": "2026-09-28T05:26:47Z",
26
- "buildDate": "2026-09-28T06:09:14.324Z",
24
+ "tag": "v22.3.3",
25
+ "commitDate": "2026-09-28T13:54:02Z",
26
+ "buildDate": "2026-09-28T14:30:23.798Z",
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/978281d4e8d54aa7f114e6925cdcdae2837504ce",
32
- "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v22.3.1"
31
+ "commitUrl": "https://github.com/f5-sales-demo/xcsh/commit/82917afa08ee15956c363dacfb1c0f4511c74d3e",
32
+ "releaseUrl": "https://github.com/f5-sales-demo/xcsh/releases/tag/v22.3.3"
33
33
  };
@@ -6,12 +6,13 @@ import os from "node:os";
6
6
  import path from "node:path";
7
7
  import { gunzipSync } from "node:zlib";
8
8
  import { createStore } from "@tobilu/qmd";
9
- import type {
10
- DocumentationAsset,
11
- DocumentationDocument,
12
- DocumentationRepository,
13
- DocumentationSearchResult,
14
- DocumentationSource,
9
+ import {
10
+ DOCUMENTATION_SOURCES,
11
+ type DocumentationAsset,
12
+ type DocumentationDocument,
13
+ type DocumentationRepository,
14
+ type DocumentationSearchResult,
15
+ type DocumentationSource,
15
16
  } from "./documentation-resolve";
16
17
  import { extractVerifiedDocumentationAsset, type VerifiedDocumentationAsset } from "./documentation-snapshot";
17
18
 
@@ -263,6 +264,19 @@ function lexicalDocumentationQuery(query: string): string {
263
264
  return query.replace(/^\s*(?:what|who)\s+(?:is|are)\s+/i, "").trim() || query;
264
265
  }
265
266
 
267
+ const SUPPORT_QUERY = /\b(?:troubleshoot|support|knowledge[- ]base|error|failure|issue|K[0-9]{6,})\b/i;
268
+ const CONFIGURATION_QUERY = /\b(?:configure|configuration|set\s*up|procedure|instructions?|how\s+(?:do|can|to))\b/i;
269
+ const CONCEPTUAL_QUERY = /\b(?:what\s+(?:is|are)|overview|product|solution|capabilities|benefits)\b/i;
270
+ const MARKETING_TOPIC =
271
+ /\b(?:client[- ]side defense|distributed cloud|web (?:app|application) and api protection|multi[- ]cloud networking|dns load balancer|bot defense|api security|app connect|appstack|content delivery network|cdn|mobile app shield|synthetic monitoring|web app scanning)\b/i;
272
+
273
+ function preferredDocumentationSource(query: string): DocumentationSource | undefined {
274
+ if (SUPPORT_QUERY.test(query)) return "my-f5-com";
275
+ if (CONFIGURATION_QUERY.test(query)) return "docs-cloud-f5-com";
276
+ if (CONCEPTUAL_QUERY.test(query) || MARKETING_TOPIC.test(query)) return "www-f5-com";
277
+ return undefined;
278
+ }
279
+
266
280
  export function createEmbeddedDocumentationRepository(
267
281
  assets: EmbeddedDocumentationAssets,
268
282
  options: EmbeddedDocumentationRepositoryOptions = {},
@@ -301,7 +315,27 @@ export function createEmbeddedDocumentationRepository(
301
315
  },
302
316
  search: async (query, source, limit): Promise<readonly DocumentationSearchResult[]> => {
303
317
  const current = await state();
304
- const results = await current.store.searchLex(lexicalDocumentationQuery(query), { limit, collection: source });
318
+ const lexicalQuery = lexicalDocumentationQuery(query);
319
+ const preferredSource = source ? undefined : preferredDocumentationSource(query);
320
+ const results = source
321
+ ? await current.store.searchLex(lexicalQuery, { limit, collection: source })
322
+ : (
323
+ await Promise.all(
324
+ DOCUMENTATION_SOURCES.map(collection =>
325
+ current.store.searchLex(lexicalQuery, { limit, collection }),
326
+ ),
327
+ )
328
+ ).flat();
329
+ results.sort((left, right) => {
330
+ const sourceOrder =
331
+ Number(right.collectionName === preferredSource) - Number(left.collectionName === preferredSource);
332
+ return (
333
+ sourceOrder ||
334
+ right.score - left.score ||
335
+ left.collectionName.localeCompare(right.collectionName) ||
336
+ left.displayPath.localeCompare(right.displayPath)
337
+ );
338
+ });
305
339
  const rows: DocumentationSearchResult[] = [];
306
340
  const lookup = current.database.query(
307
341
  "SELECT source, stable_path, title, original_url, markdown FROM documentation_documents WHERE source = ? AND stable_path = ?",
@@ -281,6 +281,19 @@ export class InputController {
281
281
  return;
282
282
  }
283
283
 
284
+ // Handle built-in slash commands
285
+ const slashResult = await executeBuiltinSlashCommand(text, {
286
+ ctx: this.ctx,
287
+ handleBackgroundCommand: () => this.handleBackgroundCommand(),
288
+ });
289
+ if (slashResult === true) {
290
+ return;
291
+ }
292
+ if (typeof slashResult === "string") {
293
+ // Command handled but returned remaining text to use as prompt
294
+ text = slashResult;
295
+ }
296
+
284
297
  const runner = this.ctx.session.extensionRunner;
285
298
  let inputImages = this.ctx.pendingImages.length > 0 ? [...this.ctx.pendingImages] : undefined;
286
299
 
@@ -301,19 +314,6 @@ export class InputController {
301
314
 
302
315
  if (!text) return;
303
316
 
304
- // Handle built-in slash commands
305
- const slashResult = await executeBuiltinSlashCommand(text, {
306
- ctx: this.ctx,
307
- handleBackgroundCommand: () => this.handleBackgroundCommand(),
308
- });
309
- if (slashResult === true) {
310
- return;
311
- }
312
- if (typeof slashResult === "string") {
313
- // Command handled but returned remaining text to use as prompt
314
- text = slashResult;
315
- }
316
-
317
317
  // Handle skill commands (/skill:name [args])
318
318
  if (text.startsWith("/skill:")) {
319
319
  const spaceIndex = text.indexOf(" ");