@robinmordasiewicz/f5xc-xcsh 1.0.90-2601021717 → 1.0.90-2601022220

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/completions/_xcsh CHANGED
@@ -44,7 +44,7 @@ _xcsh() {
44
44
  'data_intelligence:Data Intelligence API'
45
45
  'ddos:Volumetric attack mitigation and traffic scrubbing.'
46
46
  'dns:Zones, record types, and load balancing.'
47
- 'generative_ai:AI assistant queries and feedback collection.'
47
+ 'generative_ai:AI assistant queries and feedback'
48
48
  'login:Authentication and session management'
49
49
  'managed_kubernetes:Cluster RBAC, pod security, and container registries.'
50
50
  'marketplace:Add-on services, connectors, and TPM policies.'
@@ -113,9 +113,6 @@ _xcsh() {
113
113
  'ddos-protect:Alias for ddos'
114
114
  'dns-zone:Alias for dns'
115
115
  'zones:Alias for dns'
116
- 'ai:Alias for generative_ai'
117
- 'genai:Alias for generative_ai'
118
- 'assistant:Alias for generative_ai'
119
116
  'mk8s:Alias for managed_kubernetes'
120
117
  'appstack:Alias for managed_kubernetes'
121
118
  'k8s-mgmt:Alias for managed_kubernetes'
@@ -193,6 +190,9 @@ _xcsh() {
193
190
  (completion)
194
191
  _values 'command' 'bash:Generate bash completion script' 'zsh:Generate zsh completion script' 'fish:Generate fish completion script'
195
192
  ;;
193
+ (generative_ai)
194
+ _values 'command' 'query:Query the AI assistant' 'chat:Interactive AI chat mode' 'feedback:Submit feedback for AI responses' 'eval:RBAC testing mode commands'
195
+ ;;
196
196
  (login)
197
197
  _values 'command' 'banner:Display xcsh banner with logo' 'profile:Manage saved connection profiles' 'context:Manage default namespace context'
198
198
  ;;
@@ -6,7 +6,7 @@ _xcsh_completions() {
6
6
  local cur prev words cword
7
7
  _init_completion || return
8
8
 
9
- local commands="admin_console_and_ui api authentication bigip billing_and_usage blindfold bot_and_threat_defense cdn ce_management certificates cloud_infrastructure cloudstatus completion container_services data_and_privacy_security data_intelligence ddos dns generative_ai login managed_kubernetes marketplace network network_security nginx_one object_storage observability rate_limiting secops_and_incident_response service_mesh shape sites statistics support telemetry_and_insights tenant_and_identity threat_campaign users virtual vpm_and_node_management waf console-ui ui-assets static-components apisec api-discovery authn oidc sso f5-bigip irule ltm billing-usage quotas usage-tracking bf encrypt secrets threat-defense tpm shape-bot cache content ce-mgmt edge-management ce-lifecycle cert certs ssl tls cloud infra provider vk8s containers workloads data-privacy pii sensitive-data lma di intelligence insights dos ddos-protect dns-zone zones ai genai assistant mk8s appstack k8s-mgmt market addons extensions net routing bgp netsec nfw nginx nms nginx-plus storage s3 buckets obs monitoring synth ratelimit throttle policer secops incident-response mitigation mesh svc-mesh shape-sec safeap site deployment stats metrics logs tickets help-desk telemetry ti tenant-identity idm user-settings threats campaigns threat-intel user accounts iam lb loadbalancer vhost vpm nodes node-mgmt firewall appfw help quit exit clear history"
9
+ local commands="admin_console_and_ui api authentication bigip billing_and_usage blindfold bot_and_threat_defense cdn ce_management certificates cloud_infrastructure cloudstatus completion container_services data_and_privacy_security data_intelligence ddos dns generative_ai login managed_kubernetes marketplace network network_security nginx_one object_storage observability rate_limiting secops_and_incident_response service_mesh shape sites statistics support telemetry_and_insights tenant_and_identity threat_campaign users virtual vpm_and_node_management waf console-ui ui-assets static-components apisec api-discovery authn oidc sso f5-bigip irule ltm billing-usage quotas usage-tracking bf encrypt secrets threat-defense tpm shape-bot cache content ce-mgmt edge-management ce-lifecycle cert certs ssl tls cloud infra provider vk8s containers workloads data-privacy pii sensitive-data lma di intelligence insights dos ddos-protect dns-zone zones mk8s appstack k8s-mgmt market addons extensions net routing bgp netsec nfw nginx nms nginx-plus storage s3 buckets obs monitoring synth ratelimit throttle policer secops incident-response mitigation mesh svc-mesh shape-sec safeap site deployment stats metrics logs tickets help-desk telemetry ti tenant-identity idm user-settings threats campaigns threat-intel user accounts iam lb loadbalancer vhost vpm nodes node-mgmt firewall appfw help quit exit clear history"
10
10
  local actions="list get create delete replace apply status patch add-labels remove-labels"
11
11
  local builtins="help quit exit clear history context ctx"
12
12
  local global_flags="--help -h --version -v --no-color --output -o --namespace -ns --spec"
@@ -34,6 +34,14 @@ _xcsh_completions() {
34
34
  COMPREPLY=($(compgen -W "bash zsh fish" -- "${cur}"))
35
35
  return 0
36
36
  ;;
37
+ generative_ai)
38
+ COMPREPLY=($(compgen -W "query chat feedback eval" -- "${cur}"))
39
+ return 0
40
+ ;;
41
+ generative_ai/eval)
42
+ COMPREPLY=($(compgen -W "query feedback" -- "${cur}"))
43
+ return 0
44
+ ;;
37
45
  login)
38
46
  COMPREPLY=($(compgen -W "banner profile context" -- "${cur}"))
39
47
  return 0
@@ -40,7 +40,7 @@ complete -c xcsh -n "__fish_use_subcommand" -a "data_and_privacy_security" -d 'P
40
40
  complete -c xcsh -n "__fish_use_subcommand" -a "data_intelligence" -d 'Data Intelligence API'
41
41
  complete -c xcsh -n "__fish_use_subcommand" -a "ddos" -d 'Volumetric attack mitigation and traffic scrubbing.'
42
42
  complete -c xcsh -n "__fish_use_subcommand" -a "dns" -d 'Zones, record types, and load balancing.'
43
- complete -c xcsh -n "__fish_use_subcommand" -a "generative_ai" -d 'AI assistant queries and feedback collection.'
43
+ complete -c xcsh -n "__fish_use_subcommand" -a "generative_ai" -d 'AI assistant queries and feedback'
44
44
  complete -c xcsh -n "__fish_use_subcommand" -a "login" -d 'Authentication and session management'
45
45
  complete -c xcsh -n "__fish_use_subcommand" -a "managed_kubernetes" -d 'Cluster RBAC, pod security, and container registries.'
46
46
  complete -c xcsh -n "__fish_use_subcommand" -a "marketplace" -d 'Add-on services, connectors, and TPM policies.'
@@ -111,9 +111,6 @@ complete -c xcsh -n "__fish_use_subcommand" -a "dos" -d 'Alias for ddos'
111
111
  complete -c xcsh -n "__fish_use_subcommand" -a "ddos-protect" -d 'Alias for ddos'
112
112
  complete -c xcsh -n "__fish_use_subcommand" -a "dns-zone" -d 'Alias for dns'
113
113
  complete -c xcsh -n "__fish_use_subcommand" -a "zones" -d 'Alias for dns'
114
- complete -c xcsh -n "__fish_use_subcommand" -a "ai" -d 'Alias for generative_ai'
115
- complete -c xcsh -n "__fish_use_subcommand" -a "genai" -d 'Alias for generative_ai'
116
- complete -c xcsh -n "__fish_use_subcommand" -a "assistant" -d 'Alias for generative_ai'
117
114
  complete -c xcsh -n "__fish_use_subcommand" -a "mk8s" -d 'Alias for managed_kubernetes'
118
115
  complete -c xcsh -n "__fish_use_subcommand" -a "appstack" -d 'Alias for managed_kubernetes'
119
116
  complete -c xcsh -n "__fish_use_subcommand" -a "k8s-mgmt" -d 'Alias for managed_kubernetes'
@@ -180,6 +177,12 @@ complete -c xcsh -n "__fish_seen_subcommand_from cloudstatus" -a "maintenance" -
180
177
  complete -c xcsh -n "__fish_seen_subcommand_from completion" -a "bash" -d 'Generate bash completion script'
181
178
  complete -c xcsh -n "__fish_seen_subcommand_from completion" -a "zsh" -d 'Generate zsh completion script'
182
179
  complete -c xcsh -n "__fish_seen_subcommand_from completion" -a "fish" -d 'Generate fish completion script'
180
+ complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "query" -d 'Query the AI assistant'
181
+ complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "chat" -d 'Interactive AI chat mode'
182
+ complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "feedback" -d 'Submit feedback for AI responses'
183
+ complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "eval" -d 'RBAC testing mode commands'
184
+ complete -c xcsh -n "__fish_seen_subcommand_from generative_ai; and __fish_seen_subcommand_from eval" -a "query" -d 'Eval mode AI query'
185
+ complete -c xcsh -n "__fish_seen_subcommand_from generative_ai; and __fish_seen_subcommand_from eval" -a "feedback" -d 'Eval mode feedback submission'
183
186
  complete -c xcsh -n "__fish_seen_subcommand_from login" -a "banner" -d 'Display xcsh banner with logo'
184
187
  complete -c xcsh -n "__fish_seen_subcommand_from login" -a "profile" -d 'Manage saved connection profiles'
185
188
  complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from profile" -a "list" -d 'List all saved profiles'
@@ -353,16 +356,6 @@ complete -c xcsh -n "__fish_seen_subcommand_from dns" -a "status" -d 'Get resour
353
356
  complete -c xcsh -n "__fish_seen_subcommand_from dns" -a "patch" -d 'Patch a resource'
354
357
  complete -c xcsh -n "__fish_seen_subcommand_from dns" -a "add-labels" -d 'Add labels to a resource'
355
358
  complete -c xcsh -n "__fish_seen_subcommand_from dns" -a "remove-labels" -d 'Remove labels from a resource'
356
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "list" -d 'List resources'
357
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "get" -d 'Get a specific resource'
358
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "create" -d 'Create a new resource'
359
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "delete" -d 'Delete a resource'
360
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "replace" -d 'Replace a resource'
361
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "apply" -d 'Apply configuration from file'
362
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "status" -d 'Get resource status'
363
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "patch" -d 'Patch a resource'
364
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "add-labels" -d 'Add labels to a resource'
365
- complete -c xcsh -n "__fish_seen_subcommand_from generative_ai" -a "remove-labels" -d 'Remove labels from a resource'
366
359
  complete -c xcsh -n "__fish_seen_subcommand_from managed_kubernetes" -a "list" -d 'List resources'
367
360
  complete -c xcsh -n "__fish_seen_subcommand_from managed_kubernetes" -a "get" -d 'Get a specific resource'
368
361
  complete -c xcsh -n "__fish_seen_subcommand_from managed_kubernetes" -a "create" -d 'Create a new resource'
package/dist/index.js CHANGED
@@ -46630,8 +46630,8 @@ function getLogoModeFromEnv(envPrefix) {
46630
46630
  var CLI_NAME = "xcsh";
46631
46631
  var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
46632
46632
  function getVersion() {
46633
- if ("v1.0.90-2601021717") {
46634
- return "v1.0.90-2601021717";
46633
+ if ("v1.0.90-2601022220") {
46634
+ return "v1.0.90-2601022220";
46635
46635
  }
46636
46636
  if (process.env.XCSH_VERSION) {
46637
46637
  return process.env.XCSH_VERSION;
@@ -147143,10 +147143,1076 @@ var completionDomain = {
147143
147143
  subcommands: /* @__PURE__ */ new Map()
147144
147144
  };
147145
147145
 
147146
+ // src/domains/generative_ai/client.ts
147147
+ var GenAIClient = class {
147148
+ constructor(apiClient) {
147149
+ this.apiClient = apiClient;
147150
+ }
147151
+ /**
147152
+ * Query the AI assistant
147153
+ *
147154
+ * @param namespace - The namespace context for the query
147155
+ * @param query - The natural language query
147156
+ * @returns The AI assistant response with query_id and response data
147157
+ */
147158
+ async query(namespace, query) {
147159
+ const request = {
147160
+ current_query: query,
147161
+ namespace
147162
+ };
147163
+ const response = await this.apiClient.post(
147164
+ `/api/gen-ai/namespaces/${namespace}/query`,
147165
+ request
147166
+ );
147167
+ if (!response.ok) {
147168
+ throw new Error(
147169
+ `GenAI query failed: ${response.statusCode} - ${JSON.stringify(response.data)}`
147170
+ );
147171
+ }
147172
+ return response.data;
147173
+ }
147174
+ /**
147175
+ * Submit feedback for a query
147176
+ *
147177
+ * @param request - The feedback request with query_id and feedback type
147178
+ */
147179
+ async feedback(request) {
147180
+ const response = await this.apiClient.post(
147181
+ `/api/gen-ai/namespaces/${request.namespace}/query_feedback`,
147182
+ request
147183
+ );
147184
+ if (!response.ok) {
147185
+ throw new Error(
147186
+ `GenAI feedback failed: ${response.statusCode} - ${JSON.stringify(response.data)}`
147187
+ );
147188
+ }
147189
+ }
147190
+ /**
147191
+ * Query the AI assistant in eval mode (for RBAC testing)
147192
+ *
147193
+ * @param namespace - The namespace context for the query
147194
+ * @param query - The natural language query
147195
+ * @returns The AI assistant response
147196
+ */
147197
+ async evalQuery(namespace, query) {
147198
+ const request = {
147199
+ current_query: query,
147200
+ namespace
147201
+ };
147202
+ const response = await this.apiClient.post(
147203
+ `/api/gen-ai/namespaces/${namespace}/eval_query`,
147204
+ request
147205
+ );
147206
+ if (!response.ok) {
147207
+ throw new Error(
147208
+ `GenAI eval query failed: ${response.statusCode} - ${JSON.stringify(response.data)}`
147209
+ );
147210
+ }
147211
+ return response.data;
147212
+ }
147213
+ /**
147214
+ * Submit feedback for an eval query
147215
+ *
147216
+ * @param request - The feedback request with query_id and feedback type
147217
+ */
147218
+ async evalFeedback(request) {
147219
+ const response = await this.apiClient.post(
147220
+ `/api/gen-ai/namespaces/${request.namespace}/eval_query_feedback`,
147221
+ request
147222
+ );
147223
+ if (!response.ok) {
147224
+ throw new Error(
147225
+ `GenAI eval feedback failed: ${response.statusCode} - ${JSON.stringify(response.data)}`
147226
+ );
147227
+ }
147228
+ }
147229
+ };
147230
+ var cachedClient = null;
147231
+ function getGenAIClient(apiClient) {
147232
+ if (!cachedClient) {
147233
+ cachedClient = new GenAIClient(apiClient);
147234
+ }
147235
+ return cachedClient;
147236
+ }
147237
+
147238
+ // src/domains/generative_ai/types.ts
147239
+ function getResponseType(response) {
147240
+ if (response.generic_response) return "generic_response";
147241
+ if (response.explain_log) return "explain_log";
147242
+ if (response.gen_dashboard_filter) return "gen_dashboard_filter";
147243
+ if (response.list_response) return "list_response";
147244
+ if (response.site_analysis_response) return "site_analysis_response";
147245
+ if (response.widget_response) return "widget_response";
147246
+ return null;
147247
+ }
147248
+ var FEEDBACK_TYPE_MAP = {
147249
+ other: "OTHER",
147250
+ inaccurate: "INACCURATE_DATA",
147251
+ irrelevant: "IRRELEVANT_CONTENT",
147252
+ poor_format: "POOR_FORMAT",
147253
+ slow: "SLOW_RESPONSE"
147254
+ };
147255
+ function getValidFeedbackTypes() {
147256
+ return Object.keys(FEEDBACK_TYPE_MAP);
147257
+ }
147258
+
147259
+ // src/domains/generative_ai/response-renderer.ts
147260
+ function renderResponse(response) {
147261
+ const lines = [];
147262
+ const responseType = getResponseType(response);
147263
+ switch (responseType) {
147264
+ case "generic_response":
147265
+ lines.push(...renderGenericResponse(response.generic_response));
147266
+ break;
147267
+ case "explain_log":
147268
+ lines.push(...renderExplainLog(response.explain_log));
147269
+ break;
147270
+ case "gen_dashboard_filter":
147271
+ lines.push(
147272
+ ...renderDashboardFilter(response.gen_dashboard_filter)
147273
+ );
147274
+ break;
147275
+ case "list_response":
147276
+ lines.push(...renderListResponse(response.list_response));
147277
+ break;
147278
+ case "site_analysis_response":
147279
+ lines.push(...renderSiteAnalysis(response.site_analysis_response));
147280
+ break;
147281
+ case "widget_response":
147282
+ lines.push(...renderWidgetResponse(response.widget_response));
147283
+ break;
147284
+ default:
147285
+ lines.push("No response content.");
147286
+ }
147287
+ if (response.follow_up_queries && response.follow_up_queries.length > 0) {
147288
+ lines.push("");
147289
+ lines.push("Suggested follow-up questions:");
147290
+ response.follow_up_queries.forEach((q, i) => {
147291
+ lines.push(` ${i + 1}. ${q}`);
147292
+ });
147293
+ }
147294
+ return lines;
147295
+ }
147296
+ function renderGenericResponse(response) {
147297
+ const lines = [];
147298
+ if (response.error) {
147299
+ lines.push(`Error: ${response.error}`);
147300
+ return lines;
147301
+ }
147302
+ if (response.text) {
147303
+ lines.push(...response.text.split("\n"));
147304
+ }
147305
+ if (response.links && response.links.length > 0) {
147306
+ lines.push("");
147307
+ lines.push("Related links:");
147308
+ for (const link3 of response.links) {
147309
+ lines.push(` - ${link3.title}: ${link3.url}`);
147310
+ }
147311
+ }
147312
+ return lines;
147313
+ }
147314
+ function renderExplainLog(response) {
147315
+ const lines = [];
147316
+ lines.push("=== Security Event Analysis ===");
147317
+ lines.push("");
147318
+ if (response.summary) {
147319
+ lines.push("Summary:");
147320
+ lines.push(` ${response.summary}`);
147321
+ lines.push("");
147322
+ }
147323
+ if (response.action) {
147324
+ lines.push(`Action Taken: ${response.action}`);
147325
+ }
147326
+ if (response.accuracy) {
147327
+ lines.push(`Accuracy: ${response.accuracy}`);
147328
+ }
147329
+ if (response.violations && response.violations.length > 0) {
147330
+ lines.push("");
147331
+ lines.push("Violations Detected:");
147332
+ for (const v of response.violations) {
147333
+ lines.push(` - ${v.name}: ${v.description}`);
147334
+ }
147335
+ }
147336
+ if (response.threat_campaigns && response.threat_campaigns.length > 0) {
147337
+ lines.push("");
147338
+ lines.push("Threat Campaigns:");
147339
+ for (const campaign of response.threat_campaigns) {
147340
+ lines.push(` - ${campaign}`);
147341
+ }
147342
+ }
147343
+ if (response.request_details) {
147344
+ lines.push("");
147345
+ lines.push("Request Details:");
147346
+ lines.push(` ${JSON.stringify(response.request_details, null, 2)}`);
147347
+ }
147348
+ return lines;
147349
+ }
147350
+ function renderDashboardFilter(response) {
147351
+ const lines = [];
147352
+ lines.push("=== Dashboard Filter ===");
147353
+ lines.push("");
147354
+ if (response.filter_expression) {
147355
+ lines.push("Filter Expression:");
147356
+ lines.push(` ${response.filter_expression}`);
147357
+ }
147358
+ if (response.dashboard_context) {
147359
+ lines.push("");
147360
+ lines.push("Dashboard Context:");
147361
+ lines.push(` ${response.dashboard_context}`);
147362
+ }
147363
+ return lines;
147364
+ }
147365
+ function renderListResponse(response) {
147366
+ const lines = [];
147367
+ if (response.formatted_list) {
147368
+ lines.push(response.formatted_list);
147369
+ return lines;
147370
+ }
147371
+ if (response.items && response.items.length > 0) {
147372
+ if (response.total_count !== void 0) {
147373
+ lines.push(`Total: ${response.total_count} items`);
147374
+ lines.push("");
147375
+ }
147376
+ for (const item of response.items) {
147377
+ lines.push(JSON.stringify(item, null, 2));
147378
+ lines.push("");
147379
+ }
147380
+ } else {
147381
+ lines.push("No items found.");
147382
+ }
147383
+ return lines;
147384
+ }
147385
+ function renderSiteAnalysis(response) {
147386
+ const lines = [];
147387
+ lines.push("=== Site Analysis ===");
147388
+ lines.push("");
147389
+ if (response.site_name) {
147390
+ lines.push(`Site: ${response.site_name}`);
147391
+ }
147392
+ if (response.health_status) {
147393
+ lines.push(`Health: ${response.health_status}`);
147394
+ }
147395
+ if (response.metrics) {
147396
+ lines.push("");
147397
+ lines.push("Metrics:");
147398
+ for (const [key, value] of Object.entries(response.metrics)) {
147399
+ lines.push(` ${key}: ${JSON.stringify(value)}`);
147400
+ }
147401
+ }
147402
+ if (response.recommendations && response.recommendations.length > 0) {
147403
+ lines.push("");
147404
+ lines.push("Recommendations:");
147405
+ for (const rec of response.recommendations) {
147406
+ lines.push(` - ${rec}`);
147407
+ }
147408
+ }
147409
+ return lines;
147410
+ }
147411
+ function renderWidgetResponse(response) {
147412
+ const lines = [];
147413
+ if (response.display_type) {
147414
+ lines.push(`Widget Type: ${response.display_type}`);
147415
+ lines.push("");
147416
+ }
147417
+ if (response.table) {
147418
+ for (const row of response.table.rows) {
147419
+ const cells = row.cells.map((cell) => {
147420
+ let value = cell.value;
147421
+ if (cell.properties?.status_style) {
147422
+ value = `[${cell.properties.status_style}] ${value}`;
147423
+ }
147424
+ return value;
147425
+ });
147426
+ lines.push(cells.join(" | "));
147427
+ }
147428
+ }
147429
+ if (response.links && response.links.length > 0) {
147430
+ lines.push("");
147431
+ lines.push("Links:");
147432
+ for (const link3 of response.links) {
147433
+ lines.push(` - ${link3.title}: ${link3.url}`);
147434
+ }
147435
+ }
147436
+ return lines;
147437
+ }
147438
+
147439
+ // src/domains/generative_ai/query.ts
147440
+ var lastQueryState = {
147441
+ namespace: "",
147442
+ lastQueryId: null,
147443
+ lastQuery: null,
147444
+ followUpQueries: [],
147445
+ isActive: false
147446
+ };
147447
+ function getLastQueryState() {
147448
+ return lastQueryState;
147449
+ }
147450
+ function updateLastQueryState(partial) {
147451
+ lastQueryState = { ...lastQueryState, ...partial };
147452
+ }
147453
+ function clearLastQueryState() {
147454
+ lastQueryState = {
147455
+ namespace: "",
147456
+ lastQueryId: null,
147457
+ lastQuery: null,
147458
+ followUpQueries: [],
147459
+ isActive: false
147460
+ };
147461
+ }
147462
+ function parseQueryArgs(args, session) {
147463
+ const { options, remainingArgs } = parseDomainOutputFlags(
147464
+ args,
147465
+ session.getOutputFormat()
147466
+ );
147467
+ let spec = false;
147468
+ let namespace = session.getNamespace();
147469
+ const questionParts = [];
147470
+ let i = 0;
147471
+ while (i < remainingArgs.length) {
147472
+ const arg = remainingArgs[i];
147473
+ if (arg === "--spec") {
147474
+ spec = true;
147475
+ } else if (arg === "--namespace" || arg === "-ns") {
147476
+ if (i + 1 < remainingArgs.length) {
147477
+ namespace = remainingArgs[i + 1] ?? namespace;
147478
+ i++;
147479
+ }
147480
+ } else {
147481
+ questionParts.push(arg ?? "");
147482
+ }
147483
+ i++;
147484
+ }
147485
+ return {
147486
+ format: options.format,
147487
+ noColor: options.noColor,
147488
+ spec,
147489
+ namespace,
147490
+ question: questionParts.join(" ")
147491
+ };
147492
+ }
147493
+ var queryCommand = {
147494
+ name: "query",
147495
+ description: "Send a natural language query to the F5 Distributed Cloud AI assistant. Ask about load balancers, WAF configurations, site status, security events, or any platform topic. Returns AI-generated responses with optional follow-up suggestions. Use --namespace to specify the context for namespace-scoped resources.",
147496
+ descriptionShort: "Query the AI assistant",
147497
+ descriptionMedium: "Send natural language queries to the AI assistant for help with F5 XC platform operations, configurations, and troubleshooting.",
147498
+ usage: "<question> [--namespace <ns>]",
147499
+ aliases: ["ask", "q"],
147500
+ async execute(args, session) {
147501
+ const { format, noColor, spec, namespace, question } = parseQueryArgs(
147502
+ args,
147503
+ session
147504
+ );
147505
+ if (spec) {
147506
+ const cmdSpec = getCommandSpec("generative_ai query");
147507
+ if (cmdSpec) {
147508
+ return successResult([formatSpec(cmdSpec)]);
147509
+ }
147510
+ }
147511
+ if (!question.trim()) {
147512
+ return errorResult(
147513
+ "Please provide a question. Usage: ai query <question>"
147514
+ );
147515
+ }
147516
+ const apiClient = session.getAPIClient();
147517
+ if (!apiClient) {
147518
+ return errorResult(
147519
+ "Not connected to API. Please configure connection first."
147520
+ );
147521
+ }
147522
+ if (!session.isTokenValidated()) {
147523
+ return errorResult(
147524
+ "Not authenticated. Please check your API token."
147525
+ );
147526
+ }
147527
+ try {
147528
+ const client = getGenAIClient(apiClient);
147529
+ const response = await client.query(namespace, question);
147530
+ updateLastQueryState({
147531
+ namespace,
147532
+ lastQueryId: response.query_id,
147533
+ lastQuery: question,
147534
+ followUpQueries: response.follow_up_queries ?? [],
147535
+ isActive: true
147536
+ });
147537
+ if (format === "none") {
147538
+ return successResult([]);
147539
+ }
147540
+ if (format === "json" || format === "yaml" || format === "tsv") {
147541
+ return successResult(
147542
+ formatDomainOutput(response, { format, noColor })
147543
+ );
147544
+ }
147545
+ const lines = renderResponse(response);
147546
+ return successResult(lines);
147547
+ } catch (error) {
147548
+ const message = error instanceof Error ? error.message : String(error);
147549
+ return errorResult(`Query failed: ${message}`);
147550
+ }
147551
+ }
147552
+ };
147553
+
147554
+ // src/domains/generative_ai/chat.ts
147555
+ import * as readline from "readline";
147556
+ function parseChatArgs(args, session) {
147557
+ const { remainingArgs } = parseDomainOutputFlags(
147558
+ args,
147559
+ session.getOutputFormat()
147560
+ );
147561
+ let spec = false;
147562
+ let namespace = session.getNamespace();
147563
+ let i = 0;
147564
+ while (i < remainingArgs.length) {
147565
+ const arg = remainingArgs[i];
147566
+ if (arg === "--spec") {
147567
+ spec = true;
147568
+ } else if (arg === "--namespace" || arg === "-ns") {
147569
+ if (i + 1 < remainingArgs.length) {
147570
+ namespace = remainingArgs[i + 1] ?? namespace;
147571
+ i++;
147572
+ }
147573
+ }
147574
+ i++;
147575
+ }
147576
+ return { spec, namespace };
147577
+ }
147578
+ function showChatHelp() {
147579
+ return [
147580
+ "",
147581
+ "=== AI Chat Commands ===",
147582
+ "",
147583
+ " /exit, /quit, /q - Exit chat mode",
147584
+ " /help, /h - Show this help",
147585
+ " /clear, /c - Clear conversation context",
147586
+ " /feedback <type> - Submit feedback for last response",
147587
+ " Types: positive, negative",
147588
+ " 1, 2, 3... - Select a follow-up question by number",
147589
+ "",
147590
+ "Just type your question to query the AI assistant.",
147591
+ ""
147592
+ ];
147593
+ }
147594
+ async function handleFeedback(input, session) {
147595
+ const state = getLastQueryState();
147596
+ if (!state.lastQueryId || !state.lastQuery) {
147597
+ return ["No previous query to provide feedback for."];
147598
+ }
147599
+ const parts = input.split(/\s+/);
147600
+ const feedbackType = parts[1]?.toLowerCase();
147601
+ if (!feedbackType) {
147602
+ return [
147603
+ "Usage: /feedback <positive|negative>",
147604
+ " Optional: /feedback negative <type> [comment]",
147605
+ " Types: other, inaccurate, irrelevant, poor_format, slow"
147606
+ ];
147607
+ }
147608
+ const apiClient = session.getAPIClient();
147609
+ if (!apiClient) {
147610
+ return ["Not connected to API."];
147611
+ }
147612
+ try {
147613
+ const client = getGenAIClient(apiClient);
147614
+ if (feedbackType === "positive" || feedbackType === "+") {
147615
+ await client.feedback({
147616
+ query: state.lastQuery,
147617
+ query_id: state.lastQueryId,
147618
+ namespace: state.namespace,
147619
+ positive_feedback: {}
147620
+ });
147621
+ return ["Positive feedback submitted. Thank you!"];
147622
+ }
147623
+ if (feedbackType === "negative" || feedbackType === "-") {
147624
+ const negType = parts[2]?.toLowerCase();
147625
+ const mappedType = negType ? FEEDBACK_TYPE_MAP[negType] : void 0;
147626
+ const comment = parts.slice(3).join(" ") || void 0;
147627
+ await client.feedback({
147628
+ query: state.lastQuery,
147629
+ query_id: state.lastQueryId,
147630
+ namespace: state.namespace,
147631
+ negative_feedback: {
147632
+ remarks: mappedType ? [mappedType] : ["OTHER"]
147633
+ },
147634
+ comment
147635
+ });
147636
+ return [
147637
+ "Negative feedback submitted. Thank you for helping improve the AI."
147638
+ ];
147639
+ }
147640
+ return [
147641
+ `Unknown feedback type: ${feedbackType}`,
147642
+ "Use 'positive' or 'negative'."
147643
+ ];
147644
+ } catch (error) {
147645
+ const message = error instanceof Error ? error.message : String(error);
147646
+ return [`Feedback failed: ${message}`];
147647
+ }
147648
+ }
147649
+ async function runChatLoop(session, namespace) {
147650
+ const apiClient = session.getAPIClient();
147651
+ if (!apiClient) {
147652
+ return ["Not connected to API. Please configure connection first."];
147653
+ }
147654
+ if (!session.isTokenValidated()) {
147655
+ return ["Not authenticated. Please check your API token."];
147656
+ }
147657
+ const client = getGenAIClient(apiClient);
147658
+ const output = [];
147659
+ output.push("");
147660
+ output.push("=== F5 XC AI Assistant Chat ===");
147661
+ output.push(`Namespace: ${namespace}`);
147662
+ output.push("Type /help for commands, /exit to quit.");
147663
+ output.push("");
147664
+ const rl = readline.createInterface({
147665
+ input: process.stdin,
147666
+ output: process.stdout,
147667
+ terminal: process.stdin.isTTY ?? false
147668
+ });
147669
+ let interrupted = false;
147670
+ rl.on("SIGINT", () => {
147671
+ interrupted = true;
147672
+ console.log("\n(Use /exit to leave chat mode)");
147673
+ rl.prompt();
147674
+ });
147675
+ const askQuestion = (prompt) => {
147676
+ return new Promise((resolve) => {
147677
+ rl.question(prompt, (answer) => {
147678
+ resolve(answer);
147679
+ });
147680
+ });
147681
+ };
147682
+ for (const line of output) {
147683
+ console.log(line);
147684
+ }
147685
+ let running = true;
147686
+ while (running && !interrupted) {
147687
+ const input = await askQuestion("ai> ");
147688
+ if (interrupted) {
147689
+ break;
147690
+ }
147691
+ const trimmed = input.trim();
147692
+ if (!trimmed) {
147693
+ continue;
147694
+ }
147695
+ if (trimmed === "/exit" || trimmed === "/quit" || trimmed === "/q") {
147696
+ console.log("Exiting chat mode.");
147697
+ running = false;
147698
+ break;
147699
+ }
147700
+ if (trimmed === "/help" || trimmed === "/h") {
147701
+ for (const line of showChatHelp()) {
147702
+ console.log(line);
147703
+ }
147704
+ continue;
147705
+ }
147706
+ if (trimmed === "/clear" || trimmed === "/c") {
147707
+ clearLastQueryState();
147708
+ console.log("Conversation context cleared.");
147709
+ continue;
147710
+ }
147711
+ if (trimmed.startsWith("/feedback")) {
147712
+ const feedbackLines = await handleFeedback(trimmed, session);
147713
+ for (const line of feedbackLines) {
147714
+ console.log(line);
147715
+ }
147716
+ continue;
147717
+ }
147718
+ if (/^\d+$/.test(trimmed)) {
147719
+ const num = parseInt(trimmed, 10);
147720
+ const state = getLastQueryState();
147721
+ if (state.followUpQueries.length > 0 && num >= 1 && num <= state.followUpQueries.length) {
147722
+ const followUp = state.followUpQueries[num - 1];
147723
+ if (followUp) {
147724
+ console.log(`
147725
+ Following up: ${followUp}
147726
+ `);
147727
+ try {
147728
+ const response = await client.query(
147729
+ namespace,
147730
+ followUp
147731
+ );
147732
+ updateLastQueryState({
147733
+ namespace,
147734
+ lastQueryId: response.query_id,
147735
+ lastQuery: followUp,
147736
+ followUpQueries: response.follow_up_queries ?? []
147737
+ });
147738
+ const lines = renderResponse(response);
147739
+ for (const line of lines) {
147740
+ console.log(line);
147741
+ }
147742
+ console.log("");
147743
+ } catch (error) {
147744
+ const message = error instanceof Error ? error.message : String(error);
147745
+ console.log(`Query failed: ${message}`);
147746
+ }
147747
+ continue;
147748
+ }
147749
+ }
147750
+ console.log(
147751
+ `Invalid selection. Choose 1-${state.followUpQueries.length} from suggested follow-ups.`
147752
+ );
147753
+ continue;
147754
+ }
147755
+ if (trimmed.startsWith("/")) {
147756
+ console.log(
147757
+ `Unknown command: ${trimmed}. Type /help for commands.`
147758
+ );
147759
+ continue;
147760
+ }
147761
+ try {
147762
+ const response = await client.query(namespace, trimmed);
147763
+ updateLastQueryState({
147764
+ namespace,
147765
+ lastQueryId: response.query_id,
147766
+ lastQuery: trimmed,
147767
+ followUpQueries: response.follow_up_queries ?? []
147768
+ });
147769
+ console.log("");
147770
+ const lines = renderResponse(response);
147771
+ for (const line of lines) {
147772
+ console.log(line);
147773
+ }
147774
+ console.log("");
147775
+ } catch (error) {
147776
+ const message = error instanceof Error ? error.message : String(error);
147777
+ console.log(`Query failed: ${message}`);
147778
+ }
147779
+ }
147780
+ rl.close();
147781
+ return ["Chat session ended."];
147782
+ }
147783
+ var chatCommand = {
147784
+ name: "chat",
147785
+ description: "Start an interactive conversation with the F5 XC AI assistant. Enter a multi-turn dialog where you can ask questions, receive responses with follow-up suggestions, and navigate through topics naturally. Use numbered responses to quickly select suggested follow-up questions. Supports in-chat feedback submission. Type /exit to return to the main CLI.",
147786
+ descriptionShort: "Interactive AI chat mode",
147787
+ descriptionMedium: "Start an interactive multi-turn conversation with the AI assistant. Supports follow-up suggestions and in-chat commands.",
147788
+ usage: "[--namespace <ns>]",
147789
+ aliases: ["interactive", "i"],
147790
+ async execute(args, session) {
147791
+ const { spec, namespace } = parseChatArgs(args, session);
147792
+ if (spec) {
147793
+ const cmdSpec = getCommandSpec("generative_ai chat");
147794
+ if (cmdSpec) {
147795
+ return successResult([formatSpec(cmdSpec)]);
147796
+ }
147797
+ }
147798
+ if (!process.stdin.isTTY) {
147799
+ return errorResult(
147800
+ "Chat mode requires an interactive terminal. Use 'ai query' for non-interactive queries."
147801
+ );
147802
+ }
147803
+ try {
147804
+ const result = await runChatLoop(session, namespace);
147805
+ return successResult(result);
147806
+ } catch (error) {
147807
+ const message = error instanceof Error ? error.message : String(error);
147808
+ return errorResult(`Chat session failed: ${message}`);
147809
+ }
147810
+ }
147811
+ };
147812
+
147813
+ // src/domains/generative_ai/feedback.ts
147814
+ function parseFeedbackArgs(args, session) {
147815
+ const { remainingArgs } = parseDomainOutputFlags(
147816
+ args,
147817
+ session.getOutputFormat()
147818
+ );
147819
+ let spec = false;
147820
+ let namespace = session.getNamespace();
147821
+ let positive = false;
147822
+ let negativeType = null;
147823
+ let comment = null;
147824
+ let queryId = null;
147825
+ let i = 0;
147826
+ while (i < remainingArgs.length) {
147827
+ const arg = remainingArgs[i];
147828
+ if (arg === "--spec") {
147829
+ spec = true;
147830
+ } else if (arg === "--namespace" || arg === "-ns") {
147831
+ if (i + 1 < remainingArgs.length) {
147832
+ namespace = remainingArgs[i + 1] ?? namespace;
147833
+ i++;
147834
+ }
147835
+ } else if (arg === "--positive" || arg === "-p") {
147836
+ positive = true;
147837
+ } else if (arg === "--negative" || arg === "-n") {
147838
+ if (i + 1 < remainingArgs.length) {
147839
+ const typeArg = remainingArgs[i + 1]?.toLowerCase();
147840
+ if (typeArg && FEEDBACK_TYPE_MAP[typeArg]) {
147841
+ negativeType = FEEDBACK_TYPE_MAP[typeArg] ?? null;
147842
+ i++;
147843
+ } else {
147844
+ negativeType = "OTHER";
147845
+ }
147846
+ } else {
147847
+ negativeType = "OTHER";
147848
+ }
147849
+ } else if (arg === "--comment" || arg === "-c") {
147850
+ if (i + 1 < remainingArgs.length) {
147851
+ comment = remainingArgs[i + 1] ?? null;
147852
+ i++;
147853
+ }
147854
+ } else if (arg === "--query-id" || arg === "-q") {
147855
+ if (i + 1 < remainingArgs.length) {
147856
+ queryId = remainingArgs[i + 1] ?? null;
147857
+ i++;
147858
+ }
147859
+ }
147860
+ i++;
147861
+ }
147862
+ return {
147863
+ spec,
147864
+ namespace,
147865
+ positive,
147866
+ negativeType,
147867
+ comment,
147868
+ queryId
147869
+ };
147870
+ }
147871
+ var feedbackCommand = {
147872
+ name: "feedback",
147873
+ description: "Submit feedback on AI assistant responses to help improve future answers. Provide positive feedback when responses are helpful, or negative feedback with a reason type when improvements are needed. Feedback is associated with the most recent query unless a specific query ID is provided. Negative feedback types include: inaccurate (wrong information), irrelevant (off-topic), poor_format (hard to read), slow (response time), or other.",
147874
+ descriptionShort: "Submit feedback for AI responses",
147875
+ descriptionMedium: "Provide positive or negative feedback for AI assistant responses. Use --negative with a type: inaccurate, irrelevant, poor_format, slow, or other.",
147876
+ usage: "--positive | --negative <type> [--comment <text>] [--query-id <id>]",
147877
+ aliases: ["fb", "rate"],
147878
+ async execute(args, session) {
147879
+ const { spec, namespace, positive, negativeType, comment, queryId } = parseFeedbackArgs(args, session);
147880
+ if (spec) {
147881
+ const cmdSpec = getCommandSpec("generative_ai feedback");
147882
+ if (cmdSpec) {
147883
+ return successResult([formatSpec(cmdSpec)]);
147884
+ }
147885
+ }
147886
+ if (!positive && !negativeType) {
147887
+ const validTypes = getValidFeedbackTypes().join(", ");
147888
+ return errorResult(
147889
+ `Please specify feedback type:
147890
+ --positive (-p) Rate the response positively
147891
+ --negative (-n) <type> Rate negatively with reason
147892
+
147893
+ Negative types: ${validTypes}`
147894
+ );
147895
+ }
147896
+ const state = getLastQueryState();
147897
+ const targetQueryId = queryId ?? state.lastQueryId;
147898
+ const targetQuery = state.lastQuery;
147899
+ if (!targetQueryId) {
147900
+ return errorResult(
147901
+ "No query to provide feedback for. Make a query first, or use --query-id to specify one."
147902
+ );
147903
+ }
147904
+ if (!targetQuery && !queryId) {
147905
+ return errorResult(
147906
+ "Could not find the original query. Use --query-id to specify the query ID."
147907
+ );
147908
+ }
147909
+ const apiClient = session.getAPIClient();
147910
+ if (!apiClient) {
147911
+ return errorResult(
147912
+ "Not connected to API. Please configure connection first."
147913
+ );
147914
+ }
147915
+ if (!session.isTokenValidated()) {
147916
+ return errorResult(
147917
+ "Not authenticated. Please check your API token."
147918
+ );
147919
+ }
147920
+ try {
147921
+ const client = getGenAIClient(apiClient);
147922
+ if (positive) {
147923
+ await client.feedback({
147924
+ query: targetQuery ?? "",
147925
+ query_id: targetQueryId,
147926
+ namespace: state.namespace || namespace,
147927
+ positive_feedback: {},
147928
+ comment: comment ?? void 0
147929
+ });
147930
+ return successResult([
147931
+ "Positive feedback submitted successfully.",
147932
+ `Query ID: ${targetQueryId}`
147933
+ ]);
147934
+ }
147935
+ await client.feedback({
147936
+ query: targetQuery ?? "",
147937
+ query_id: targetQueryId,
147938
+ namespace: state.namespace || namespace,
147939
+ negative_feedback: {
147940
+ remarks: negativeType ? [negativeType] : ["OTHER"]
147941
+ },
147942
+ comment: comment ?? void 0
147943
+ });
147944
+ return successResult([
147945
+ "Negative feedback submitted successfully.",
147946
+ `Query ID: ${targetQueryId}`,
147947
+ `Reason: ${negativeType ?? "OTHER"}`,
147948
+ ...comment ? [`Comment: ${comment}`] : []
147949
+ ]);
147950
+ } catch (error) {
147951
+ const message = error instanceof Error ? error.message : String(error);
147952
+ return errorResult(`Feedback submission failed: ${message}`);
147953
+ }
147954
+ }
147955
+ };
147956
+
147957
+ // src/domains/generative_ai/eval.ts
147958
+ function parseEvalQueryArgs(args, session) {
147959
+ const { options, remainingArgs } = parseDomainOutputFlags(
147960
+ args,
147961
+ session.getOutputFormat()
147962
+ );
147963
+ let spec = false;
147964
+ let namespace = session.getNamespace();
147965
+ const questionParts = [];
147966
+ let i = 0;
147967
+ while (i < remainingArgs.length) {
147968
+ const arg = remainingArgs[i];
147969
+ if (arg === "--spec") {
147970
+ spec = true;
147971
+ } else if (arg === "--namespace" || arg === "-ns") {
147972
+ if (i + 1 < remainingArgs.length) {
147973
+ namespace = remainingArgs[i + 1] ?? namespace;
147974
+ i++;
147975
+ }
147976
+ } else {
147977
+ questionParts.push(arg ?? "");
147978
+ }
147979
+ i++;
147980
+ }
147981
+ return {
147982
+ format: options.format,
147983
+ noColor: options.noColor,
147984
+ spec,
147985
+ namespace,
147986
+ question: questionParts.join(" ")
147987
+ };
147988
+ }
147989
+ var evalQueryCommand = {
147990
+ name: "query",
147991
+ description: "Send a query to the AI assistant using the eval endpoint. This endpoint is used for RBAC testing and validation purposes, allowing administrators to test permission scenarios without affecting production query analytics.",
147992
+ descriptionShort: "Eval mode AI query",
147993
+ descriptionMedium: "Query the AI assistant in eval mode for RBAC testing and permission validation.",
147994
+ usage: "<question> [--namespace <ns>]",
147995
+ aliases: ["q"],
147996
+ async execute(args, session) {
147997
+ const { format, noColor, spec, namespace, question } = parseEvalQueryArgs(args, session);
147998
+ if (spec) {
147999
+ const cmdSpec = getCommandSpec("generative_ai eval query");
148000
+ if (cmdSpec) {
148001
+ return successResult([formatSpec(cmdSpec)]);
148002
+ }
148003
+ }
148004
+ if (!question.trim()) {
148005
+ return errorResult(
148006
+ "Please provide a question. Usage: ai eval query <question>"
148007
+ );
148008
+ }
148009
+ const apiClient = session.getAPIClient();
148010
+ if (!apiClient) {
148011
+ return errorResult(
148012
+ "Not connected to API. Please configure connection first."
148013
+ );
148014
+ }
148015
+ if (!session.isTokenValidated()) {
148016
+ return errorResult(
148017
+ "Not authenticated. Please check your API token."
148018
+ );
148019
+ }
148020
+ try {
148021
+ const client = getGenAIClient(apiClient);
148022
+ const response = await client.evalQuery(namespace, question);
148023
+ updateLastQueryState({
148024
+ namespace,
148025
+ lastQueryId: response.query_id,
148026
+ lastQuery: question,
148027
+ followUpQueries: response.follow_up_queries ?? [],
148028
+ isActive: true
148029
+ });
148030
+ if (format === "none") {
148031
+ return successResult([]);
148032
+ }
148033
+ if (format === "json" || format === "yaml" || format === "tsv") {
148034
+ return successResult(
148035
+ formatDomainOutput(response, { format, noColor })
148036
+ );
148037
+ }
148038
+ const lines = ["[EVAL MODE]", "", ...renderResponse(response)];
148039
+ return successResult(lines);
148040
+ } catch (error) {
148041
+ const message = error instanceof Error ? error.message : String(error);
148042
+ return errorResult(`Eval query failed: ${message}`);
148043
+ }
148044
+ }
148045
+ };
148046
+ function parseEvalFeedbackArgs(args, session) {
148047
+ const { remainingArgs } = parseDomainOutputFlags(
148048
+ args,
148049
+ session.getOutputFormat()
148050
+ );
148051
+ let spec = false;
148052
+ let namespace = session.getNamespace();
148053
+ let positive = false;
148054
+ let negativeType = null;
148055
+ let comment = null;
148056
+ let queryId = null;
148057
+ let i = 0;
148058
+ while (i < remainingArgs.length) {
148059
+ const arg = remainingArgs[i];
148060
+ if (arg === "--spec") {
148061
+ spec = true;
148062
+ } else if (arg === "--namespace" || arg === "-ns") {
148063
+ if (i + 1 < remainingArgs.length) {
148064
+ namespace = remainingArgs[i + 1] ?? namespace;
148065
+ i++;
148066
+ }
148067
+ } else if (arg === "--positive" || arg === "-p") {
148068
+ positive = true;
148069
+ } else if (arg === "--negative" || arg === "-n") {
148070
+ if (i + 1 < remainingArgs.length) {
148071
+ const typeArg = remainingArgs[i + 1]?.toLowerCase();
148072
+ if (typeArg && FEEDBACK_TYPE_MAP[typeArg]) {
148073
+ negativeType = FEEDBACK_TYPE_MAP[typeArg] ?? null;
148074
+ i++;
148075
+ } else {
148076
+ negativeType = "OTHER";
148077
+ }
148078
+ } else {
148079
+ negativeType = "OTHER";
148080
+ }
148081
+ } else if (arg === "--comment" || arg === "-c") {
148082
+ if (i + 1 < remainingArgs.length) {
148083
+ comment = remainingArgs[i + 1] ?? null;
148084
+ i++;
148085
+ }
148086
+ } else if (arg === "--query-id" || arg === "-q") {
148087
+ if (i + 1 < remainingArgs.length) {
148088
+ queryId = remainingArgs[i + 1] ?? null;
148089
+ i++;
148090
+ }
148091
+ }
148092
+ i++;
148093
+ }
148094
+ return {
148095
+ spec,
148096
+ namespace,
148097
+ positive,
148098
+ negativeType,
148099
+ comment,
148100
+ queryId
148101
+ };
148102
+ }
148103
+ var evalFeedbackCommand = {
148104
+ name: "feedback",
148105
+ description: "Submit feedback for an eval mode query. Use this endpoint when providing feedback for queries made through the eval endpoint, ensuring proper RBAC testing analytics separation.",
148106
+ descriptionShort: "Eval mode feedback submission",
148107
+ descriptionMedium: "Submit feedback for eval mode AI queries, keeping RBAC testing analytics separate.",
148108
+ usage: "--positive | --negative <type> [--comment <text>] [--query-id <id>]",
148109
+ aliases: ["fb"],
148110
+ async execute(args, session) {
148111
+ const { spec, namespace, positive, negativeType, comment, queryId } = parseEvalFeedbackArgs(args, session);
148112
+ if (spec) {
148113
+ const cmdSpec = getCommandSpec("generative_ai eval feedback");
148114
+ if (cmdSpec) {
148115
+ return successResult([formatSpec(cmdSpec)]);
148116
+ }
148117
+ }
148118
+ if (!positive && !negativeType) {
148119
+ const validTypes = getValidFeedbackTypes().join(", ");
148120
+ return errorResult(
148121
+ `Please specify feedback type:
148122
+ --positive (-p) Rate the response positively
148123
+ --negative (-n) <type> Rate negatively with reason
148124
+
148125
+ Negative types: ${validTypes}`
148126
+ );
148127
+ }
148128
+ const state = getLastQueryState();
148129
+ const targetQueryId = queryId ?? state.lastQueryId;
148130
+ const targetQuery = state.lastQuery;
148131
+ if (!targetQueryId) {
148132
+ return errorResult(
148133
+ "No query to provide feedback for. Make an eval query first, or use --query-id to specify one."
148134
+ );
148135
+ }
148136
+ const apiClient = session.getAPIClient();
148137
+ if (!apiClient) {
148138
+ return errorResult(
148139
+ "Not connected to API. Please configure connection first."
148140
+ );
148141
+ }
148142
+ if (!session.isTokenValidated()) {
148143
+ return errorResult(
148144
+ "Not authenticated. Please check your API token."
148145
+ );
148146
+ }
148147
+ try {
148148
+ const client = getGenAIClient(apiClient);
148149
+ if (positive) {
148150
+ await client.evalFeedback({
148151
+ query: targetQuery ?? "",
148152
+ query_id: targetQueryId,
148153
+ namespace: state.namespace || namespace,
148154
+ positive_feedback: {},
148155
+ comment: comment ?? void 0
148156
+ });
148157
+ return successResult([
148158
+ "[EVAL MODE] Positive feedback submitted successfully.",
148159
+ `Query ID: ${targetQueryId}`
148160
+ ]);
148161
+ }
148162
+ await client.evalFeedback({
148163
+ query: targetQuery ?? "",
148164
+ query_id: targetQueryId,
148165
+ namespace: state.namespace || namespace,
148166
+ negative_feedback: {
148167
+ remarks: negativeType ? [negativeType] : ["OTHER"]
148168
+ },
148169
+ comment: comment ?? void 0
148170
+ });
148171
+ return successResult([
148172
+ "[EVAL MODE] Negative feedback submitted successfully.",
148173
+ `Query ID: ${targetQueryId}`,
148174
+ `Reason: ${negativeType ?? "OTHER"}`,
148175
+ ...comment ? [`Comment: ${comment}`] : []
148176
+ ]);
148177
+ } catch (error) {
148178
+ const message = error instanceof Error ? error.message : String(error);
148179
+ return errorResult(`Eval feedback submission failed: ${message}`);
148180
+ }
148181
+ }
148182
+ };
148183
+ var evalSubcommands = {
148184
+ name: "eval",
148185
+ description: "Eval mode commands for RBAC testing and permission validation. Use these endpoints to test AI assistant queries and feedback without affecting production analytics. Useful for administrators validating access controls.",
148186
+ descriptionShort: "RBAC testing mode commands",
148187
+ descriptionMedium: "Query and provide feedback in eval mode for RBAC testing and permission validation.",
148188
+ commands: /* @__PURE__ */ new Map([
148189
+ ["query", evalQueryCommand],
148190
+ ["feedback", evalFeedbackCommand]
148191
+ ]),
148192
+ defaultCommand: evalQueryCommand
148193
+ };
148194
+
148195
+ // src/domains/generative_ai/index.ts
148196
+ var generativeAiDomain = {
148197
+ name: "generative_ai",
148198
+ description: "Interact with the F5 Distributed Cloud AI assistant for natural language queries about platform operations. Ask questions about load balancers, WAF configurations, site status, security events, or any platform topic. Supports single queries with follow-up suggestions, interactive multi-turn chat sessions, and feedback submission to improve AI responses.",
148199
+ descriptionShort: "AI assistant queries and feedback",
148200
+ descriptionMedium: "Query the AI assistant for help with F5 XC platform operations, configurations, security analysis, and troubleshooting.",
148201
+ defaultCommand: queryCommand,
148202
+ commands: /* @__PURE__ */ new Map([
148203
+ ["query", queryCommand],
148204
+ ["chat", chatCommand],
148205
+ ["feedback", feedbackCommand]
148206
+ ]),
148207
+ subcommands: /* @__PURE__ */ new Map([["eval", evalSubcommands]])
148208
+ };
148209
+ var generativeAiAliases = ["ai", "genai", "assistant"];
148210
+
147146
148211
  // src/domains/index.ts
147147
148212
  customDomains.register(loginDomain);
147148
148213
  customDomains.register(cloudstatusDomain);
147149
148214
  customDomains.register(completionDomain);
148215
+ customDomains.register(generativeAiDomain);
147150
148216
  for (const domain of customDomains.all()) {
147151
148217
  completionRegistry.registerDomain(fromCustomDomain(domain));
147152
148218
  }
@@ -147159,6 +148225,9 @@ var domainAliases = /* @__PURE__ */ new Map();
147159
148225
  for (const alias of cloudstatusAliases) {
147160
148226
  domainAliases.set(alias, "cloudstatus");
147161
148227
  }
148228
+ for (const alias of generativeAiAliases) {
148229
+ domainAliases.set(alias, "generative_ai");
148230
+ }
147162
148231
  function resolveDomainAlias(name) {
147163
148232
  return domainAliases.get(name) ?? name;
147164
148233
  }
@@ -149927,7 +150996,7 @@ function App2({ initialSession } = {}) {
149927
150996
  }
149928
150997
 
149929
150998
  // src/headless/controller.ts
149930
- import * as readline from "readline";
150999
+ import * as readline2 from "readline";
149931
151000
 
149932
151001
  // src/headless/protocol.ts
149933
151002
  function parseInput2(line) {
@@ -150202,7 +151271,7 @@ var HeadlessController = class {
150202
151271
  */
150203
151272
  async run() {
150204
151273
  await this.initialize();
150205
- this.rl = readline.createInterface({
151274
+ this.rl = readline2.createInterface({
150206
151275
  input: process.stdin,
150207
151276
  output: process.stdout,
150208
151277
  terminal: false
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinmordasiewicz/f5xc-xcsh",
3
- "version": "1.0.90-2601021717",
3
+ "version": "1.0.90-2601022220",
4
4
  "description": "F5 Distributed Cloud Shell - Interactive CLI for F5 XC",
5
5
  "type": "module",
6
6
  "bin": {