@f5xc-salesdemos/xcsh 18.79.0 → 18.81.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/xcsh",
4
- "version": "18.79.0",
4
+ "version": "18.81.0",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5xc-salesdemos/xcsh",
7
7
  "author": "Can Boluk",
@@ -48,12 +48,12 @@
48
48
  "dependencies": {
49
49
  "@agentclientprotocol/sdk": "0.16.1",
50
50
  "@mozilla/readability": "^0.6",
51
- "@f5xc-salesdemos/xcsh-stats": "18.79.0",
52
- "@f5xc-salesdemos/pi-agent-core": "18.79.0",
53
- "@f5xc-salesdemos/pi-ai": "18.79.0",
54
- "@f5xc-salesdemos/pi-natives": "18.79.0",
55
- "@f5xc-salesdemos/pi-tui": "18.79.0",
56
- "@f5xc-salesdemos/pi-utils": "18.79.0",
51
+ "@f5xc-salesdemos/xcsh-stats": "18.81.0",
52
+ "@f5xc-salesdemos/pi-agent-core": "18.81.0",
53
+ "@f5xc-salesdemos/pi-ai": "18.81.0",
54
+ "@f5xc-salesdemos/pi-natives": "18.81.0",
55
+ "@f5xc-salesdemos/pi-tui": "18.81.0",
56
+ "@f5xc-salesdemos/pi-utils": "18.81.0",
57
57
  "@sinclair/typebox": "^0.34",
58
58
  "@xterm/headless": "^6.0",
59
59
  "ajv": "^8.18",
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "18.79.0",
21
- "commit": "cc280f31122399fcfa7cde248777d0430b721bc7",
22
- "shortCommit": "cc280f3",
20
+ "version": "18.81.0",
21
+ "commit": "042ddfbad1fad8132b3dc9a1eb0190ac17b2d22d",
22
+ "shortCommit": "042ddfb",
23
23
  "branch": "main",
24
- "tag": "v18.79.0",
25
- "commitDate": "2026-05-24T21:32:29Z",
26
- "buildDate": "2026-05-24T21:50:49.956Z",
24
+ "tag": "v18.81.0",
25
+ "commitDate": "2026-05-25T15:40:42Z",
26
+ "buildDate": "2026-05-25T16:05:58.171Z",
27
27
  "dirty": true,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
30
30
  "repoSlug": "f5xc-salesdemos/xcsh",
31
- "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/cc280f31122399fcfa7cde248777d0430b721bc7",
32
- "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.79.0"
31
+ "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/042ddfbad1fad8132b3dc9a1eb0190ac17b2d22d",
32
+ "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.81.0"
33
33
  };
@@ -6,9 +6,7 @@ import xcshApiDescription from "../prompts/tools/xcsh-api.md" with { type: "text
6
6
  import { type ContextEnv, createContextEnv } from "../services/context-env";
7
7
  import type { ToolSession } from ".";
8
8
 
9
- // ── Spec-driven namespace filtering ────────────────────────────────
10
- // Replaces hardcoded startsWith("ves-io")/startsWith("system")/startsWith("shared")
11
- // with data-driven classification aligned to x-f5xc-namespace-profile extension.
9
+ // Namespace filtering driven by x-f5xc-namespace-profile from enriched API specs.
12
10
 
13
11
  type NamespaceType = "system" | "shared" | "default" | "custom";
14
12
 
@@ -133,6 +131,7 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
133
131
  #contextEnv: ContextEnv;
134
132
  #lastApiBase = "";
135
133
  #listablePathsCache: string[] | null = null;
134
+ #autoExpandPathsCache: string[] | null = null;
136
135
  #expandedNamespaces = new Set<string>();
137
136
 
138
137
  constructor(session: ToolSession) {
@@ -180,7 +179,11 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
180
179
  const CONFIG_PREFIX = "/api/config/namespaces/{namespace}/";
181
180
  // Only include app/security types (keyword filter). Reduces batch from ~136 to ~42 paths,
182
181
  // cutting expansion time by ~3× and eliminating infrastructure noise from the response.
182
+ // Healthcheck is included in batch content (for HC labels) but NOT in the auto-expand
183
+ // trigger list — direct GET to /healthchecks should not trigger a full namespace expansion.
183
184
  const APP_KW =
185
+ /loadbalancer|pool|firewall|healthcheck|_policys|setting|type|mitigation|identification|network|route|host|definition|rate_limiter|prefix_set|cdn|waf|api_/i;
186
+ const AUTO_EXPAND_KW =
184
187
  /loadbalancer|pool|firewall|_policys|setting|type|mitigation|identification|network|route|host|definition|rate_limiter|prefix_set|cdn|waf|api_/i;
185
188
  const META_EXCL = /policy_set|policy_rule|data_polic/i;
186
189
  for (const summary of summaries) {
@@ -200,6 +203,11 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
200
203
  }
201
204
  }
202
205
  }
206
+ // Build separate auto-expand trigger list (excludes healthcheck)
207
+ this.#autoExpandPathsCache = paths.filter(p => {
208
+ const last = p.split("/").filter(Boolean).at(-1) ?? "";
209
+ return AUTO_EXPAND_KW.test(last);
210
+ });
203
211
  this.#listablePathsCache = paths;
204
212
  return paths;
205
213
  } catch {
@@ -419,7 +427,7 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
419
427
  // Only fetch specs for types that carry relationship data (LBs, pools, firewalls,
420
428
  // healthchecks). Excludes system-generated objects (routes, virtual_hosts, etc.)
421
429
  // that inflate the item count and don't add relationship info.
422
- const SPEC_TYPES = /loadbalancer|origin_pool|app_firewall|healthcheck/i;
430
+ const SPEC_TYPES = /loadbalancer|origin_pool|app_firewall|healthcheck|rate_limiter/i;
423
431
  for (const r of relevantData) {
424
432
  const typeName = r.path.split("/").pop() ?? "";
425
433
  if (!SPEC_TYPES.test(typeName)) continue;
@@ -459,15 +467,23 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
459
467
  // Core types get detailed per-resource output with spec summaries.
460
468
  // Secondary types get a compact count to reduce batch response noise.
461
469
  // Shorter, focused output helps the model find relationship data directly.
462
- const getTypeName = (r: BatchEntry) => r.path.split("/").pop() ?? r.path;
463
- const coreTypes = relevantData.filter(r => SPEC_TYPES.test(getTypeName(r)));
464
- const secondaryTypes = relevantData.filter(r => !SPEC_TYPES.test(getTypeName(r)));
470
+ const getRawTypeName = (r: BatchEntry) => r.path.split("/").pop() ?? r.path;
471
+ // Human-readable type name for display: http_loadbalancers → load balancers, origin_pools → origin pools
472
+ const humanizeType = (raw: string): string =>
473
+ raw
474
+ .replace(/^http_/, "")
475
+ .replace(/^tcp_/, "TCP ")
476
+ .replace(/_/g, " ")
477
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
478
+ .replace(/([a-z])(balancer|checker)/gi, "$1 $2");
479
+ const coreTypes = relevantData.filter(r => SPEC_TYPES.test(getRawTypeName(r)));
480
+ const secondaryTypes = relevantData.filter(r => !SPEC_TYPES.test(getRawTypeName(r)));
465
481
 
466
482
  if (coreTypes.length > 0) {
467
483
  sections.push(`Namespace resource inventory (${coreTypes.length} core types):\n`);
468
484
  let idx = 1;
469
485
  for (const r of coreTypes) {
470
- const typeName = getTypeName(r);
486
+ const typeName = humanizeType(getRawTypeName(r));
471
487
  const items = (r.parsed?.items as Array<Record<string, unknown>> | undefined) ?? [];
472
488
  if (items.length === 0) {
473
489
  sections.push(`${idx}. ${typeName}: ${r.itemCount} item(s)`);
@@ -486,7 +502,7 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
486
502
  if (secondaryTypes.length > 0) {
487
503
  const secondaryCount = secondaryTypes.reduce((sum, r) => sum + (r.itemCount ?? 0), 0);
488
504
  sections.push(
489
- `\n(+${secondaryTypes.length} other types with ${secondaryCount} items: ${secondaryTypes.map(r => getTypeName(r)).join(", ")})`,
505
+ `\n(+${secondaryTypes.length} other types with ${secondaryCount} items: ${secondaryTypes.map(r => humanizeType(getRawTypeName(r))).join(", ")})`,
490
506
  );
491
507
  }
492
508
 
@@ -516,7 +532,13 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
516
532
  const rName = parts.at(-1) ?? "";
517
533
  const rType = parts.at(-2) ?? "";
518
534
  const labels: string[] = [];
519
- if (/loadbalancer/i.test(rType)) {
535
+ if (/tcp_loadbalancer/i.test(rType)) {
536
+ const pools = extractPoolRefs(spec.origin_pools_weights);
537
+ if (pools.length > 0) labels.push(`pools=[${pools.join(",")}]`);
538
+ if (typeof spec.listen_port === "number") labels.push(`port=${spec.listen_port}`);
539
+ const domains = Array.isArray(spec.domains) ? (spec.domains as string[]) : [];
540
+ if (domains.length > 0) labels.push(`domains=[${domains.join(",")}]`);
541
+ } else if (/loadbalancer/i.test(rType)) {
520
542
  const waf = extractRef(spec.app_firewall);
521
543
  labels.push(waf ? `WAF=${waf}` : "no-WAF");
522
544
  const pools = extractPoolRefs(spec.default_route_pools);
@@ -540,6 +562,22 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
540
562
  if (spec.monitoring != null) labels.push("monitoring-mode");
541
563
  else if (spec.blocking != null) labels.push("blocking-mode");
542
564
  }
565
+ if (/healthcheck/i.test(rType)) {
566
+ if (spec.http_health_check != null) {
567
+ labels.push("http");
568
+ const httpHC = spec.http_health_check as Record<string, unknown>;
569
+ if (typeof httpHC.path === "string") labels.push(`path=${httpHC.path}`);
570
+ } else if (spec.tcp_health_check != null) {
571
+ labels.push("tcp");
572
+ }
573
+ }
574
+ if (/rate_limiter/i.test(rType)) {
575
+ if (typeof spec.total_number === "number") labels.push(`threshold=${spec.total_number}`);
576
+ if (typeof spec.burst_size === "number") labels.push(`burst=${spec.burst_size}`);
577
+ if (typeof spec.committed_information_rate === "number")
578
+ labels.push(`rate=${spec.committed_information_rate}`);
579
+ if (typeof spec.unit === "string") labels.push(`unit=${spec.unit}`);
580
+ }
543
581
  if (labels.length > 0) {
544
582
  summaryLines.push(`${rName}: ${labels.join(", ")}`);
545
583
  }
@@ -642,12 +680,15 @@ export class XcshApiTool implements AgentTool<typeof xcshApiSchema, XcshApiToolD
642
680
  // File-based cache in #executeBatch prevents redundant API calls across sessions.
643
681
  if (params.method === "GET" && !params.payload) {
644
682
  const listablePaths = this.#loadListablePaths();
645
- if (listablePaths.length > 0) {
683
+ // Use the auto-expand trigger list (excludes healthcheck) to decide WHETHER to expand.
684
+ // The batch itself uses the full listablePaths (includes healthcheck) for content.
685
+ const triggerPaths = this.#autoExpandPathsCache ?? listablePaths;
686
+ if (triggerPaths.length > 0) {
646
687
  const normalized = params.path.replace(
647
688
  /\/api\/config\/namespaces\/[^/]+\//,
648
689
  "/api/config/namespaces/{namespace}/",
649
690
  );
650
- if (listablePaths.includes(params.path) || listablePaths.includes(normalized)) {
691
+ if (triggerPaths.includes(params.path) || triggerPaths.includes(normalized)) {
651
692
  const nsMatch = params.path.match(/\/api\/config\/namespaces\/([^/]+)\//);
652
693
  const ns = params.params?.namespace ?? (nsMatch?.[1] && nsMatch[1] !== "{namespace}" ? nsMatch[1] : "");
653
694
  if (ns && !this.#expandedNamespaces.has(ns)) {