@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.
|
|
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.
|
|
52
|
-
"@f5xc-salesdemos/pi-agent-core": "18.
|
|
53
|
-
"@f5xc-salesdemos/pi-ai": "18.
|
|
54
|
-
"@f5xc-salesdemos/pi-natives": "18.
|
|
55
|
-
"@f5xc-salesdemos/pi-tui": "18.
|
|
56
|
-
"@f5xc-salesdemos/pi-utils": "18.
|
|
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.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.81.0",
|
|
21
|
+
"commit": "042ddfbad1fad8132b3dc9a1eb0190ac17b2d22d",
|
|
22
|
+
"shortCommit": "042ddfb",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.
|
|
25
|
-
"commitDate": "2026-05-
|
|
26
|
-
"buildDate": "2026-05-
|
|
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/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.
|
|
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
|
};
|
package/src/tools/xcsh-api.ts
CHANGED
|
@@ -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
|
-
//
|
|
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
|
|
463
|
-
|
|
464
|
-
const
|
|
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 =
|
|
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 =>
|
|
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 (/
|
|
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
|
-
|
|
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 (
|
|
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)) {
|