@robinmordasiewicz/f5xc-xcsh 6.28.0 → 6.30.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/dist/index.js CHANGED
@@ -44108,23 +44108,23 @@ var generatedDomains = /* @__PURE__ */ new Map([
44108
44108
  ["admin_console_and_ui", {
44109
44109
  name: "admin_console_and_ui",
44110
44110
  displayName: "Admin Console And Ui",
44111
- description: "Provides management capabilities for static components used in the F5 XC admin console and user interface. Enables operations to deploy, retrieve, update, and list static UI assets within namespace boundaries. Supports configuration of console interface elements, component metadata management, and asset lifecycle operations. Use this domain to manage custom UI components, static resources, and interface configurations that extend or customize the admin console experience.",
44112
- descriptionShort: "Static UI component and console asset management",
44113
- descriptionMedium: "Manage static components for the admin console interface. Deploy, retrieve, and list UI assets and configuration elements within namespaces.",
44114
- aliases: [],
44111
+ description: "Set up static resource definitions that control administrative dashboard appearance. Register named entries using object references, status tracking fields, and view settings. Fetch individual records through dedicated get operations or enumerate available entries with pagination and sorting. Handle request validation through typed error responses and support multiple output codes for success states. Define custom initialization blocks and namespace-scoped boundaries for organization.",
44112
+ descriptionShort: "Manage static UI assets for admin console",
44113
+ descriptionMedium: "Deploy and list dashboard widgets within namespaces. Create named visual resources with initialization parameters and structured configuration data.",
44114
+ aliases: ["console-ui", "ui-assets", "static-components"],
44115
44115
  complexity: "simple",
44116
44116
  isPreview: false,
44117
44117
  requiresTier: "Standard",
44118
- category: "Other",
44119
- useCases: [],
44120
- relatedDomains: []
44118
+ category: "Platform",
44119
+ useCases: ["Manage static UI components for admin console", "Deploy and retrieve UI assets within namespaces", "Configure console interface elements", "Manage custom UI component metadata"],
44120
+ relatedDomains: ["admin", "system"]
44121
44121
  }],
44122
44122
  ["api", {
44123
44123
  name: "api",
44124
44124
  displayName: "Api",
44125
- description: "Comprehensive API lifecycle management including automatic discovery and cataloging of APIs across your infrastructure, security testing to identify vulnerabilities and validate behavior, credential management for secure API access, and policy-driven API grouping. Define testing policies to continuously validate API security posture, organize APIs into logical groups for governance, and integrate with WAF and network security controls. Supports marking endpoints as non-API traffic and...",
44126
- descriptionShort: "API discovery, security testing, and credential management",
44127
- descriptionMedium: "Discover and catalog APIs, test security behavior, manage credentials, and define API groups with testing policies for comprehensive API lifecycle...",
44125
+ description: "Catalog services automatically to maintain an inventory of operations and their characteristics. Organize related resources by function or ownership through logical groupings. Establish verification procedures that confirm authentication requirements and expected response structures. Link definitions with load balancers for traffic routing decisions. Flag non-standard paths for exclusion from automated scanning. Monitor resource status and metadata throughout deployment zones.",
44126
+ descriptionShort: "Discover, catalog, and test service interfaces",
44127
+ descriptionMedium: "Define interface groups and discovery policies. Set up verification rules to check security posture and expected patterns across environments.",
44128
44128
  aliases: ["apisec", "api-discovery"],
44129
44129
  complexity: "advanced",
44130
44130
  isPreview: false,
@@ -44200,9 +44200,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44200
44200
  ["bigip", {
44201
44201
  name: "bigip",
44202
44202
  displayName: "Bigip",
44203
- description: "Configure and manage BigIP F5 appliance integration with Distributed Cloud infrastructure. Create and deploy iRule scripts for advanced traffic manipulation, manage data groups for dynamic configuration, configure Access Policy Manager (APM) settings for authentication and access control, and define BigIP virtual servers. Provides metrics collection for APM performance monitoring and enables seamless hybrid deployments combining traditional BigIP infrastructure with cloud-native services...",
44204
- descriptionShort: "BigIP appliance management, iRules, and data groups",
44205
- descriptionMedium: "Manage BigIP F5 appliances including iRule script configuration, data groups, APM policies, and virtual server integration with Distributed Cloud.",
44203
+ description: "Define custom rule-based policies governing routing decisions and request handling. Build organized collections for network ranges, string patterns, and key-value entries. Map cloud services to physical appliances through connector setups. Link identity workflows using access modules. Track performance metrics and coordinate synchronization between components.",
44204
+ descriptionShort: "Manage iRules, data groups, and virtual servers",
44205
+ descriptionMedium: "Configure traffic logic scripts and structured list entries. Establish appliance bindings and access module integrations.",
44206
44206
  aliases: ["f5-bigip", "irule", "ltm"],
44207
44207
  complexity: "moderate",
44208
44208
  isPreview: false,
@@ -44214,23 +44214,23 @@ var generatedDomains = /* @__PURE__ */ new Map([
44214
44214
  ["billing_and_usage", {
44215
44215
  name: "billing_and_usage",
44216
44216
  displayName: "Billing And Usage",
44217
- description: "Comprehensive billing and usage management for F5 XC tenants. Handle subscription plan transitions between tiers, configure primary and secondary payment methods, and download invoice PDFs. Monitor resource quota limits and current usage across namespaces. Supports custom invoice listing, quota configuration per namespace, and contact management for billing communications. Essential for financial operations, capacity planning, and subscription lifecycle management.",
44218
- descriptionShort: "Subscription billing, payment methods, and usage tracking",
44219
- descriptionMedium: "Manage subscription plans, payment methods, invoices, and resource quotas. Track usage limits and billing transitions across namespaces.",
44220
- aliases: [],
44217
+ description: "Set up payment methods with primary and secondary designations for redundancy. Initiate plan transitions between subscription tiers with state tracking. Download invoice PDFs and query custom invoice lists by date range or status. Define quota limits per namespace and monitor current usage against allocated capacity. Swap payment method roles without service interruption.",
44218
+ descriptionShort: "Manage subscription plans and payment methods",
44219
+ descriptionMedium: "Configure billing transitions and payment processing. Track invoices and monitor resource quota consumption across namespaces.",
44220
+ aliases: ["billing-usage", "quotas", "usage-tracking"],
44221
44221
  complexity: "moderate",
44222
44222
  isPreview: false,
44223
44223
  requiresTier: "Standard",
44224
- category: "Other",
44225
- useCases: [],
44226
- relatedDomains: []
44224
+ category: "Platform",
44225
+ useCases: ["Manage subscription plans and billing transitions", "Configure payment methods and invoices", "Track resource quota usage across namespaces", "Monitor usage limits and capacity"],
44226
+ relatedDomains: ["system", "users"]
44227
44227
  }],
44228
44228
  ["blindfold", {
44229
44229
  name: "blindfold",
44230
44230
  displayName: "Blindfold",
44231
- description: "Configure and manage cryptographic secret protection with policy-based access controls. Create secret policies and policy rules that govern how sensitive data is encrypted, shared, and accessed across namespaces. Retrieve public keys for encryption operations, process policy information for secret sharing workflows, and decrypt secrets with proper authorization. Monitor secret access through comprehensive audit logs with aggregation and scrolling capabilities. Enforce data protection...",
44232
- descriptionShort: "Secret encryption and policy-based data protection",
44233
- descriptionMedium: "Manage encryption keys, secret policies, and sensitive data protection. Configure policy rules for secure secret sharing with audit logging.",
44231
+ description: "Define policy rules with label matching and combining algorithms. Set up transformers and matchers to control data safeguarding. Track access patterns through timestamped records with scroll queries and date groupings. Retrieve public keys for cryptographic operations and process policy information for decryption workflows.",
44232
+ descriptionShort: "Manage secret encryption and policy rules",
44233
+ descriptionMedium: "Configure protection policies and access controls for sensitive data. Monitor usage through detailed logs and date-based rollups.",
44234
44234
  aliases: ["bf", "encrypt", "secrets"],
44235
44235
  complexity: "moderate",
44236
44236
  isPreview: false,
@@ -44242,23 +44242,23 @@ var generatedDomains = /* @__PURE__ */ new Map([
44242
44242
  ["bot_and_threat_defense", {
44243
44243
  name: "bot_and_threat_defense",
44244
44244
  displayName: "Bot And Threat Defense",
44245
- description: "Manage comprehensive bot and threat defense capabilities including Shape bot defense instance configuration, threat protection manager (TPM) categories for threat classification, and API key provisioning for automated defense systems. Create and manage TPM categories to organize threats by type, configure bot defense instances per namespace, and handle TPM manager lifecycle operations. Supports preauthorization and provisioning workflows for integrating threat intelligence services with...",
44246
- descriptionShort: "Bot detection, threat categorization, and defense management",
44247
- descriptionMedium: "Configure bot defense instances, manage threat categories, and provision TPM API keys for automated threat detection and mitigation.",
44248
- aliases: [],
44245
+ description: "Deploy Shape bot defense instances with namespace-scoped configuration for automated threat detection. Create TPM categories to classify and organize threat types across your security infrastructure. Generate and manage provisioning keys for programmatic access to defense systems. Set up threat managers to coordinate detection rules, integrate with WAF policies, and enable real-time protection against malicious traffic patterns.",
44246
+ descriptionShort: "Configure bot protection and threat categories",
44247
+ descriptionMedium: "Manage bot defense instances and threat classification per namespace. Provision automated defense keys for security integration.",
44248
+ aliases: ["threat-defense", "tpm", "shape-bot"],
44249
44249
  complexity: "moderate",
44250
44250
  isPreview: false,
44251
- requiresTier: "Standard",
44252
- category: "Other",
44253
- useCases: [],
44254
- relatedDomains: []
44251
+ requiresTier: "Advanced",
44252
+ category: "Security",
44253
+ useCases: ["Configure bot defense instances per namespace", "Manage TPM threat categories for classification", "Provision API keys for automated defense systems", "Integrate threat intelligence services"],
44254
+ relatedDomains: ["bot_defense", "shape", "waf"]
44255
44255
  }],
44256
44256
  ["cdn", {
44257
44257
  name: "cdn",
44258
44258
  displayName: "Cdn",
44259
- description: "Create cache rules with expression-based matching for paths, headers, cookies, and query parameters. Deploy load balancers optimized for content distribution with configurable TTL settings and cache eligibility options. Monitor access logs and metrics for delivery performance. Purge cached content on demand and track service operation status across namespaces.",
44260
- descriptionShort: "Configure content delivery and caching rules",
44261
- descriptionMedium: "Define cache rules and load balancers for content distribution. Set TTL policies, path matching, and header-based caching decisions.",
44259
+ description: "Create cache rules with cookie, header, and query parameter matching to control content eligibility. Configure load balancers with origin pool routing, access logging, and metrics collection. Manage cache purge operations for immediate content invalidation. Monitor service operation status and aggregate access logs for performance analysis. Define path matchers and expressions for granular cache behavior control across namespaces.",
44260
+ descriptionShort: "Configure caching rules and load balancers",
44261
+ descriptionMedium: "Define cache TTL policies and path matching rules. Set up load balancers with origin pools and purge controls for content delivery.",
44262
44262
  aliases: ["cache", "content"],
44263
44263
  complexity: "advanced",
44264
44264
  isPreview: false,
@@ -44270,23 +44270,23 @@ var generatedDomains = /* @__PURE__ */ new Map([
44270
44270
  ["ce_management", {
44271
44271
  name: "ce_management",
44272
44272
  displayName: "Ce Management",
44273
- description: "Configure and manage Customer Edge (CE) site infrastructure across distributed deployments. Define network interfaces with DHCP, IPv6, and dedicated management settings. Organize sites into fleets for coordinated management. Handle site registration workflows including token-based registration, image downloads, and suggested configuration values. Monitor and execute site upgrades with pre-upgrade checks and status tracking. Supports both dedicated and Ethernet interface types with...",
44274
- descriptionShort: "Customer Edge site lifecycle and network configuration",
44275
- descriptionMedium: "Manage Customer Edge sites including network interfaces, fleet configurations, site upgrades, and registration workflows for distributed deployments.",
44276
- aliases: [],
44273
+ description: "Define network connectivity parameters including address allocation ranges, dual-stack protocol support, and isolated administrative ports for out-of-band access. Group physical locations under common policy templates for streamlined oversight. Onboard new deployments through secure credential workflows with expiration policies. Execute controlled software transitions featuring pre-flight validation, rollback capabilities, and progress tracking to maintain service continuity.",
44274
+ descriptionShort: "Manage Customer Edge sites and network interfaces",
44275
+ descriptionMedium: "Configure DHCP pools, IPv6 addressing, and dedicated management ports. Handle site tokens with lifecycle controls and software version transitions.",
44276
+ aliases: ["ce-mgmt", "edge-management", "ce-lifecycle"],
44277
44277
  complexity: "advanced",
44278
44278
  isPreview: false,
44279
44279
  requiresTier: "Standard",
44280
- category: "Other",
44281
- useCases: [],
44282
- relatedDomains: []
44280
+ category: "Infrastructure",
44281
+ useCases: ["Manage Customer Edge site lifecycle", "Configure network interfaces and fleet settings", "Handle site registration and token workflows", "Execute site upgrades with pre-upgrade checks"],
44282
+ relatedDomains: ["customer_edge", "sites"]
44283
44283
  }],
44284
44284
  ["certificates", {
44285
44285
  name: "certificates",
44286
44286
  displayName: "Certificates",
44287
- description: "Comprehensive certificate lifecycle management for securing application communications. Configure SSL/TLS certificates and certificate chains for endpoints, manage trusted Certificate Authority (CA) lists for client verification, and maintain Certificate Revocation Lists (CRLs) to invalidate compromised certificates. Supports certificate manifests for organized deployment across namespaces, enabling mTLS authentication, HTTPS termination, and secure service-to-service communication patterns.",
44288
- descriptionShort: "SSL/TLS certificate and trusted CA management",
44289
- descriptionMedium: "Manage SSL/TLS certificates, certificate chains, trusted CA lists, and certificate revocation lists for secure communications.",
44287
+ description: "Create PKI artifacts organizing cryptographic identity materials by namespace for multi-tenant isolation. Deploy keypair bundles with issuer hierarchies for TLS termination. Establish verification anchor collections governing which external parties can authenticate. Maintain deny-lists blocking compromised identities from initiating sessions. Organize resources within independent security boundaries supporting granular access control.",
44288
+ descriptionShort: "Manage SSL/TLS certificate chains and trusted CAs",
44289
+ descriptionMedium: "Configure certificate manifests linking keys to credential bundles. Define trust anchors for validating client authenticity during mutual TLS.",
44290
44290
  aliases: ["cert", "certs", "ssl", "tls"],
44291
44291
  complexity: "moderate",
44292
44292
  isPreview: false,
@@ -44298,9 +44298,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44298
44298
  ["cloud_infrastructure", {
44299
44299
  name: "cloud_infrastructure",
44300
44300
  displayName: "Cloud Infrastructure",
44301
- description: "Establish and manage connectivity to major cloud providers including AWS, Azure, and GCP. Configure cloud credentials and authentication for secure provider access. Create and manage VPC attachments, transit gateways, and route tables for cross-cloud networking. Support elastic provisioning with automatic resource discovery and reapplication workflows. Monitor cloud connection metrics and segment performance. Integrate with Customer Edge sites for hybrid cloud deployments across multiple...",
44302
- descriptionShort: "Multi-cloud provider connectivity and credential management",
44303
- descriptionMedium: "Connect to AWS, Azure, and GCP cloud providers. Manage cloud credentials, VPC attachments, transit gateways, and cross-cloud networking with...",
44301
+ description: "Establish connections to AWS, Azure, and GCP environments with secure authentication and network discovery. Define gateway links, edge site peering, and elastic provisioning workflows. Monitor segment performance and connection health across geographic regions. Create automated VPC attachment policies with intelligent path selection between customer locations and cloud workloads.",
44302
+ descriptionShort: "Connect and manage multi-cloud providers",
44303
+ descriptionMedium: "Configure cloud provider credentials and VPC attachments. Manage AWS transit gateways, Azure route tables, and cross-cloud connectivity.",
44304
44304
  aliases: ["cloud", "infra", "provider"],
44305
44305
  complexity: "moderate",
44306
44306
  isPreview: false,
@@ -44312,9 +44312,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44312
44312
  ["container_services", {
44313
44313
  name: "container_services",
44314
44314
  displayName: "Container Services",
44315
- description: "Container Services (XCCS) enables deployment and management of containerized applications across distributed edge sites without requiring full Kubernetes complexity. Create virtual Kubernetes clusters for isolated multi-tenant environments, define workload flavors for resource allocation, and deploy container workloads with simplified orchestration. Monitor workload usage and PVC metrics, manage namespace isolation, and integrate with site infrastructure for edge-native container...",
44316
- descriptionShort: "Edge container workloads and virtual Kubernetes management",
44317
- descriptionMedium: "Deploy and manage containerized workloads at the edge with simplified orchestration. Configure virtual Kubernetes clusters, workload flavors, and...",
44315
+ description: "Create definitions for applications running on distributed infrastructure. Establish standardized templates controlling resource consumption and disk limits. Set up partitioned execution contexts supporting namespace separation and multi-tenant isolation. Track persistent volume claims and usage metrics. Connect with mesh networking for traffic routing.",
44316
+ descriptionShort: "Deploy containerized workloads across sites",
44317
+ descriptionMedium: "Run services with simplified orchestration. Define blueprints governing processor and storage allocation.",
44318
44318
  aliases: ["vk8s", "containers", "workloads"],
44319
44319
  complexity: "moderate",
44320
44320
  isPreview: false,
@@ -44326,16 +44326,16 @@ var generatedDomains = /* @__PURE__ */ new Map([
44326
44326
  ["data_and_privacy_security", {
44327
44327
  name: "data_and_privacy_security",
44328
44328
  displayName: "Data And Privacy Security",
44329
- description: "Manage comprehensive data privacy and security controls including sensitive data detection policies, custom data type definitions, and log management analytics (LMA) region configurations. Define patterns for identifying PII, financial data, and other sensitive information with configurable actions for masking, alerting, or blocking. Configure LMA regions with Elasticsearch, Kafka, or ClickHouse backends for centralized security logging and compliance auditing. Integrate geo-configurations...",
44330
- descriptionShort: "Sensitive data detection, classification, and privacy...",
44331
- descriptionMedium: "Configure data types, sensitive data policies, and LMA regions for detecting, classifying, and protecting personally identifiable information and...",
44332
- aliases: [],
44329
+ description: "Set up sensitive data policies that identify and protect personally identifiable information across traffic flows. Create custom data type definitions matching organizational privacy standards and industry regulations. Configure LMA region parameters including Clickhouse, Elastic, and Kafka integrations. Deploy geo-configurations enforcing data residency rules and regional compliance mandates. Monitor detection status through condition tracking and secret management with blindfold encryption.",
44330
+ descriptionShort: "Configure sensitive data detection and privacy policies",
44331
+ descriptionMedium: "Define custom data types for PII classification. Manage LMA regions and geo-configurations to meet regulatory compliance requirements.",
44332
+ aliases: ["data-privacy", "pii", "sensitive-data", "lma"],
44333
44333
  complexity: "simple",
44334
44334
  isPreview: false,
44335
- requiresTier: "Standard",
44336
- category: "Other",
44337
- useCases: [],
44338
- relatedDomains: []
44335
+ requiresTier: "Advanced",
44336
+ category: "Security",
44337
+ useCases: ["Configure sensitive data detection policies", "Define custom data types for PII classification", "Manage LMA region configurations", "Integrate geo-configurations for compliance"],
44338
+ relatedDomains: ["blindfold", "client_side_defense"]
44339
44339
  }],
44340
44340
  ["data_intelligence", {
44341
44341
  name: "data_intelligence",
@@ -44354,9 +44354,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44354
44354
  ["ddos", {
44355
44355
  name: "ddos",
44356
44356
  displayName: "Ddos",
44357
- description: "Comprehensive DDoS protection and infrastructure security management. Configure deny list rules to block malicious traffic sources, create firewall rule groups for granular traffic filtering, and manage protection tunnels for secure infrastructure connectivity. The infraprotect APIs enable proactive threat mitigation through customizable security policies, real-time tunnel status monitoring, and namespace-scoped rule management. Integrates with network security and virtual load balancing for...",
44358
- descriptionShort: "DDoS protection and infrastructure security policies",
44359
- descriptionMedium: "Configure DDoS protection policies, deny lists, and firewall rules. Monitor infrastructure threats and manage protection tunnels for network security.",
44357
+ description: "Deploy definitions that block IP addresses and network segments from accessing protected resources. Organize by threat type or source classification. Manage secure channels routing suspicious packets for analysis before reaching origin servers. Update status for real-time visibility into active defenses. Add items during attacks and monitor health metrics.",
44358
+ descriptionShort: "Configure blocking policies and tunnel protection",
44359
+ descriptionMedium: "Set up firewall configurations with deny list rules. Filter malicious traffic through inspection points.",
44360
44360
  aliases: ["dos", "ddos-protect"],
44361
44361
  complexity: "advanced",
44362
44362
  isPreview: false,
@@ -44368,9 +44368,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44368
44368
  ["dns", {
44369
44369
  name: "dns",
44370
44370
  displayName: "Dns",
44371
- description: "Create and manage authoritative zones with support for standard record types including A, AAAA, CNAME, CAA, CERT, and AFSDB. Import existing configurations through BIND file uploads or zone transfers. Define health check policies that monitor backend availability and automatically adjust record responses. Export zone files for backup or migration. Access request logs and performance metrics to analyze query patterns and troubleshoot resolution issues across namespaces.",
44372
- descriptionShort: "Manage zones, records, and resolution policies",
44373
- descriptionMedium: "Configure zone imports from BIND files or AXFR transfers. Set up health checks for load-balanced records and monitor query metrics.",
44371
+ description: "Set up primary and secondary zones with support for A, AAAA, CNAME, CAA, CERT, and AFSDB record types. Define health checks to monitor target availability and enable automatic failover between record destinations. Clone existing domains, import zone configurations from external servers, or export zone files for backup. Track query metrics and request logs to analyze resolution patterns across namespaces.",
44372
+ descriptionShort: "Manage zones, records, and load balancing",
44373
+ descriptionMedium: "Configure authoritative name services with record sets and health checks. Import zones from BIND files or transfer via AXFR protocol.",
44374
44374
  aliases: ["dns-zone", "zones"],
44375
44375
  complexity: "advanced",
44376
44376
  isPreview: false,
@@ -44432,9 +44432,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44432
44432
  ["generative_ai", {
44433
44433
  name: "generative_ai",
44434
44434
  displayName: "Generative Ai",
44435
- description: "Generative AI services providing intelligent automation and analysis capabilities. Configure AI assistant policies and submit queries with feedback tracking for continuous improvement. Enable flow anomaly detection powered by machine learning. Manage AI data collection through the BFDP subsystem including feature enablement, token management, and subscription controls. Supports IP allocation for GIA services. Integrates dashboard visualization with customizable displays, filters, and link...",
44436
- descriptionShort: "AI-powered features, assistants, and data collection",
44437
- descriptionMedium: "Access generative AI capabilities including AI assistant queries, flow anomaly detection, and AI data collection with feedback mechanisms.",
44435
+ description: "Set up query evaluation and response handling for intelligent assistant workflows. Manage rating collection with positive and negative outcome tracking. Subscribe to data streams for traffic pattern detection and behavioral analysis. Allocate and deallocate IP resources for ML infrastructure. Control feature enablement and token management for telemetry collection paths.",
44436
+ descriptionShort: "Access AI assistant queries and feedback",
44437
+ descriptionMedium: "Configure machine learning interactions and collect response ratings. Enable flow pattern monitoring through data subscription channels.",
44438
44438
  aliases: ["ai", "genai", "assistant"],
44439
44439
  complexity: "simple",
44440
44440
  isPreview: true,
@@ -44446,9 +44446,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44446
44446
  ["managed_kubernetes", {
44447
44447
  name: "managed_kubernetes",
44448
44448
  displayName: "Managed Kubernetes",
44449
- description: "Configure and manage Managed Kubernetes (XCKS) security and access controls. Define cluster roles with fine-grained permissions for API resources and non-resource URLs. Create role bindings to associate users and groups with cluster-wide permissions. Enforce pod security standards through admission controllers with configurable enforcement levels. Manage private container registries for secure image distribution. Integrates with external Kubernetes clusters including EKS, AKS, and GKE for...",
44450
- descriptionShort: "Kubernetes RBAC, pod security, and container registries",
44451
- descriptionMedium: "Manage Kubernetes cluster roles, RBAC bindings, pod security admission policies, and container registries for enterprise deployments.",
44449
+ description: "Create granular access controls for namespace resources and non-resource URLs. Map permissions to users, groups, or service accounts through binding configurations. Deploy security admission enforcement using baseline, restricted, or privileged profiles. Register private image sources with credential management for secure pulls. Integrate with external managed solutions including EKS, AKS, and GKE infrastructure.",
44450
+ descriptionShort: "Configure Kubernetes RBAC and pod security policies",
44451
+ descriptionMedium: "Define permission boundaries for workload access. Set up private image repositories with authentication for enterprise deployments.",
44452
44452
  aliases: ["mk8s", "appstack", "k8s-mgmt"],
44453
44453
  complexity: "moderate",
44454
44454
  isPreview: false,
@@ -44460,9 +44460,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44460
44460
  ["marketplace", {
44461
44461
  name: "marketplace",
44462
44462
  displayName: "Marketplace",
44463
- description: "Access and manage the marketplace ecosystem including third-party integrations, add-on services, and external connectors. Configure connection types for direct, GRE tunnel, and IPSec connectivity with customizable IKE parameters and DPD keepalive settings. Manage navigation tiles for custom UI extensions, activate and monitor add-on service status across namespaces, and integrate with external platforms like Terraform. Supports TPM policy management and configuration management instances for...",
44464
- descriptionShort: "Third-party integrations, add-ons, and extensions",
44465
- descriptionMedium: "Manage marketplace extensions, external connectors, and third-party add-on services. Configure Terraform integrations and TPM policies.",
44463
+ description: "Set up secure tunnel connections using IKEv1/IKEv2 parameters, GRE encapsulation with source and destination addressing, or dedicated link types. Manage DPD keep-alive timers and tunnel termination points for reliable connectivity. Activate purchasable services with namespace-scoped status tracking. Create custom portal widgets for interface integration and configure Cloud Manager instances for Terraform and infrastructure automation workflows.",
44464
+ descriptionShort: "Manage third-party integrations and add-ons",
44465
+ descriptionMedium: "Configure connector tunnels with IPSec, GRE, or direct links. Deploy purchasable services and portal customizations across namespaces.",
44466
44466
  aliases: ["market", "addons", "extensions"],
44467
44467
  complexity: "moderate",
44468
44468
  isPreview: false,
@@ -44474,9 +44474,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44474
44474
  ["network", {
44475
44475
  name: "network",
44476
44476
  displayName: "Network",
44477
- description: "Comprehensive network infrastructure management including BGP routing with ASN configuration and peering policies, IPsec tunnel establishment with full IKE phase 1 and phase 2 parameter control, and network connector configuration for hybrid cloud connectivity. Supports SRv6 segment routing, subnet management, DC cluster groups for data center integration, static and dynamic route definitions, and IP prefix set policies. Enables secure site-to-site VPN connections, multi-cloud network...",
44478
- descriptionShort: "BGP routing, IPsec tunnels, and network connectivity",
44479
- descriptionMedium: "Configure BGP routing policies, IPsec tunnels with IKE phases, network connectors, SRv6, and IP prefix sets for secure site-to-site connectivity.",
44477
+ description: "Deploy secure site connectivity using IPsec tunnels with customizable IKE phase settings, encryption algorithms, and DH groups. Configure BGP routing with peer state monitoring, ASN management, and traffic policies. Set up SRv6 segments, IP prefix sets, and subnet definitions. Manage DC cluster groups for data center integration and define routes for traffic steering across distributed infrastructure.",
44478
+ descriptionShort: "Configure BGP routing, tunnels, and connectivity",
44479
+ descriptionMedium: "Manage IPsec tunnels and IKE configurations. Define BGP peers, ASN assignments, and routing policies for site-to-site connections.",
44480
44480
  aliases: ["net", "routing", "bgp"],
44481
44481
  complexity: "advanced",
44482
44482
  isPreview: false,
@@ -44488,9 +44488,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44488
44488
  ["network_security", {
44489
44489
  name: "network_security",
44490
44490
  displayName: "Network Security",
44491
- description: "Network security controls for protecting traffic at the network layer. Configure network firewalls with stateful inspection and ACL rules. Define NAT policies for address translation, port forwarding, and dynamic pool management. Create network policy sets for segmentation and micro-segmentation between workloads. Implement policy-based routing to direct traffic based on source, destination, or application criteria. Manage segment connections for multi-site network isolation. Configure...",
44492
- descriptionShort: "Network firewall, NAT, ACL, and policy-based routing",
44493
- descriptionMedium: "Configure network firewalls, NAT policies, ACLs, and policy-based routing. Manage network segmentation, port forwarding, and forward proxy policies.",
44491
+ description: "Manage firewall configurations with match criteria and action rules. Create NAT policies using dynamic pools and port configurations for address translation. Define segment connections to isolate traffic between network zones. Configure policy-based routing to direct packets based on source, destination, or protocol attributes. Set up forward proxy policies and access control lists to govern outbound connections.",
44492
+ descriptionShort: "Configure firewalls, NAT, and routing policies",
44493
+ descriptionMedium: "Define network firewall rules and NAT policies. Set up policy-based routing with segment connections for traffic control.",
44494
44494
  aliases: ["netsec", "nfw"],
44495
44495
  complexity: "advanced",
44496
44496
  isPreview: false,
@@ -44502,9 +44502,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44502
44502
  ["nginx_one", {
44503
44503
  name: "nginx_one",
44504
44504
  displayName: "Nginx One",
44505
- description: "Integrate and manage NGINX One platform capabilities including subscription lifecycle management, NGINX Plus instance provisioning, and server configuration. Configure dataplane servers, manage nginx instances with WAF and API discovery specifications, and enable service discovery integrations. Supports NGINX Configuration Sync Gateway (CSG) configurations for centralized management workflows. Typical operations include subscribing to NGINX One services, retrieving server status and...",
44506
- descriptionShort: "NGINX One platform integration and instance management",
44507
- descriptionMedium: "Manage NGINX One platform subscriptions, configure NGINX Plus instances and servers, and integrate service discovery with centralized...",
44505
+ description: "Set up load balancing configurations with backend server definitions and routing logic. Create monitoring schedules for availability tracking across distributed nodes. Build request handling pipelines with rate controls and authentication layers. Track instance performance metrics and traffic patterns. Coordinate failover mechanisms using weighted distribution and priority-based selection.",
44506
+ descriptionShort: "Configure NGINX proxy instances and deployments",
44507
+ descriptionMedium: "Manage upstream server pools and health monitors. Define SSL termination rules and connection parameters for gateway endpoints.",
44508
44508
  aliases: ["nginx", "nms", "nginx-plus"],
44509
44509
  complexity: "simple",
44510
44510
  isPreview: false,
@@ -44516,9 +44516,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44516
44516
  ["object_storage", {
44517
44517
  name: "object_storage",
44518
44518
  displayName: "Object Storage",
44519
- description: "Manage versioned object storage for mobile application components and platform integrations. Upload and retrieve mobile app shield configurations, SDK integrations, and custom artifacts organized by namespace and object type. Support for multiple versions of each object enables rollback and version-specific deployments. Presigned URLs provide secure, time-limited access for direct object downloads. Object types include mobile-app-shield for application protection, mobile-integrator for...",
44520
- descriptionShort: "Object storage for mobile SDK artifacts and integrations",
44521
- descriptionMedium: "Store and retrieve versioned objects including mobile app shields, SDK integrations, and custom artifacts with presigned URL access.",
44519
+ description: "Deploy binary artifacts and configuration bundles with automatic version tracking and lifecycle policies. Organize content by category including protection signatures, SDK packages, and third-party connector files. Enable time-limited download links for secure distribution without credential exposure. Track revision history for audit trails and support rollback to previous artifact versions when needed.",
44520
+ descriptionShort: "Manage stored objects and bucket versioning",
44521
+ descriptionMedium: "Create versioned content within tenant buckets. Generate secure access URLs for SDK distributions and application protection resources.",
44522
44522
  aliases: ["storage", "s3", "buckets"],
44523
44523
  complexity: "simple",
44524
44524
  isPreview: false,
@@ -44530,9 +44530,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44530
44530
  ["observability", {
44531
44531
  name: "observability",
44532
44532
  displayName: "Observability",
44533
- description: "Comprehensive synthetic monitoring and observability capabilities for proactive infrastructure health assessment. Configure DNS monitors to validate resolution across AWS regions, set up HTTP monitors for endpoint availability testing, and track SSL/TLS certificate expiration status. Access real-time health summaries at global and namespace levels, review historical monitoring data, and generate detailed reports for DNS and HTTP monitors. Integrate with dashboards to visualize monitoring...",
44534
- descriptionShort: "Synthetic monitoring, health checks, and observability...",
44535
- descriptionMedium: "Configure synthetic monitoring with DNS and HTTP health checks. Track certificate status, monitor global health summaries, and analyze monitoring...",
44533
+ description: "Deploy synthetic monitors to validate DNS resolution and HTTP service health from multiple geographic locations. Define monitoring schedules, response time thresholds, and alerting conditions for proactive issue detection. Access health summaries, historical trends, and detailed reports for certificate status and service availability. Integrate monitoring data with dashboards to visualize health patterns and identify performance degradation before user impact.",
44534
+ descriptionShort: "Configure synthetic monitors and health checks",
44535
+ descriptionMedium: "Set up DNS and HTTP monitoring with alerting thresholds. Track certificate expiration and service availability across regions.",
44536
44536
  aliases: ["obs", "monitoring", "synth"],
44537
44537
  complexity: "advanced",
44538
44538
  isPreview: false,
@@ -44544,9 +44544,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44544
44544
  ["rate_limiting", {
44545
44545
  name: "rate_limiting",
44546
44546
  displayName: "Rate Limiting",
44547
- description: "Manage rate limiting policies to protect applications from traffic surges and abuse. Configure rate limiters with customizable thresholds, time periods, and enforcement actions including blocking or throttling. Implement policers using leaky bucket algorithms for smooth traffic shaping. Define protocol-specific policers for granular control over different traffic types. Integrate with virtual hosts and load balancers to enforce rate limits at the edge, preventing resource exhaustion and...",
44548
- descriptionShort: "Traffic rate limiting, policers, and throttling controls",
44549
- descriptionMedium: "Configure rate limiters and policers to control traffic flow. Define request thresholds, leaky bucket algorithms, and enforcement actions for API...",
44547
+ description: "Create rate limiter policies with configurable time periods using seconds, minutes, or hours granularity. Deploy policers and protocol policers to enforce bandwidth constraints across namespaces. Define limit values, burst allowances, and blocking behaviors when thresholds trigger. Integrate with load balancers and security policies for layered traffic management and abuse prevention.",
44548
+ descriptionShort: "Configure traffic throttling and policer rules",
44549
+ descriptionMedium: "Define request limits and burst thresholds for traffic control. Set up leaky bucket algorithms and block actions for exceeded quotas.",
44550
44550
  aliases: ["ratelimit", "throttle", "policer"],
44551
44551
  complexity: "simple",
44552
44552
  isPreview: false,
@@ -44558,23 +44558,23 @@ var generatedDomains = /* @__PURE__ */ new Map([
44558
44558
  ["secops_and_incident_response", {
44559
44559
  name: "secops_and_incident_response",
44560
44560
  displayName: "Secops And Incident Response",
44561
- description: "Security operations and incident response capabilities for detecting and mitigating malicious user activity. Create mitigation policies that define automated responses based on user threat levels, including blocking, challenging, or rate limiting suspicious users. Configure rules that match specific malicious user types and threat severity levels to appropriate mitigation actions. Supports namespace-scoped configurations for managing security policies across different application...",
44562
- descriptionShort: "Malicious user detection and automated threat mitigation",
44563
- descriptionMedium: "Configure automated responses to malicious user behavior. Define mitigation rules based on threat levels and apply actions like blocking or rate...",
44564
- aliases: [],
44561
+ description: "Manage incident response workflows that detect and mitigate malicious users automatically. Create rules matching threat levels to actions like blocking, rate limiting, or alerting. Set up mitigation policies per namespace to isolate security responses. Define thresholds for user behavior analysis and configure graduated responses based on severity. Integrate with bot defense and WAF systems for coordinated protection across application layers.",
44562
+ descriptionShort: "Configure automated threat mitigation rules",
44563
+ descriptionMedium: "Define malicious user detection policies and response actions. Apply blocking or rate limiting based on threat levels.",
44564
+ aliases: ["secops", "incident-response", "mitigation"],
44565
44565
  complexity: "simple",
44566
44566
  isPreview: false,
44567
- requiresTier: "Standard",
44568
- category: "Other",
44569
- useCases: [],
44570
- relatedDomains: []
44567
+ requiresTier: "Advanced",
44568
+ category: "Security",
44569
+ useCases: ["Configure automated threat mitigation policies", "Define rules for malicious user detection", "Manage incident response workflows", "Apply blocking or rate limiting to threats"],
44570
+ relatedDomains: ["bot_defense", "waf", "network_security"]
44571
44571
  }],
44572
44572
  ["service_mesh", {
44573
44573
  name: "service_mesh",
44574
44574
  displayName: "Service Mesh",
44575
- description: "Manage service mesh infrastructure including endpoint discovery and intelligent routing between distributed services. Define application types with learned API schemas, security risk classifications, and authentication configurations. Configure NFV (Network Function Virtualization) services with lifecycle management including force-delete operations. Leverage machine learning capabilities for automatic API endpoint detection, schema learning, and traffic pattern analysis. Integrate with...",
44576
- descriptionShort: "Service mesh connectivity, discovery, and NFV management",
44577
- descriptionMedium: "Configure service mesh networking with endpoint discovery, application type definitions, API endpoint learning, and NFV service lifecycle management.",
44575
+ description: "Create classifications to organize services and support automatic identification of interconnected components. Set up analysis pipelines to understand patterns and build intelligent routing rules. Define network function virtualization for regional architectures. Configure authentication settings including location, state, and type recognition.",
44576
+ descriptionShort: "Configure application types and discovery",
44577
+ descriptionMedium: "Manage NFV integrations and workload categories. Enable traffic learning across distributed deployments.",
44578
44578
  aliases: ["mesh", "svc-mesh"],
44579
44579
  complexity: "advanced",
44580
44580
  isPreview: false,
@@ -44586,9 +44586,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44586
44586
  ["shape", {
44587
44587
  name: "shape",
44588
44588
  displayName: "Shape",
44589
- description: "Shape Security integration for advanced bot defense and threat prevention capabilities. Configure bot infrastructure deployments with policy management, deployment history tracking, and status monitoring. Manage mobile SDK attributes for application shielding and integrator configurations. Subscribe to bot defense add-ons and client-side defense services. Includes SafeAP policy configuration, threat recognition rules, and automated bot mitigation across namespaces with comprehensive...",
44590
- descriptionShort: "Bot defense and threat prevention with Shape Security",
44591
- descriptionMedium: "Configure Shape Security policies for bot defense, threat recognition, and mobile SDK protection. Manage bot infrastructure deployments and SafeAP...",
44589
+ description: "Set up bot defense infrastructure across namespaces with deployment tracking and status monitoring. Integrate mobile SDK attributes for app shielding and device recognition. Subscribe to threat intelligence services for real-time protection updates. Define cluster states and location-based policies for distributed bot mitigation. Track deployment history and manage policy configurations through centralized infrastructure objects.",
44590
+ descriptionShort: "Configure bot defense and threat prevention",
44591
+ descriptionMedium: "Deploy bot infrastructure with mobile SDK integration. Manage subscription services and policy enforcement for automated threat protection.",
44592
44592
  aliases: ["shape-sec", "safeap"],
44593
44593
  complexity: "advanced",
44594
44594
  isPreview: false,
@@ -44600,9 +44600,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44600
44600
  ["sites", {
44601
44601
  name: "sites",
44602
44602
  displayName: "Sites",
44603
- description: "Comprehensive site infrastructure management for deploying F5 XC across multiple cloud providers and edge locations. Configure AWS Transit Gateway sites with VPN tunnels, VPC IP prefixes, and security settings. Manage virtual sites for logical grouping and policy application. Deploy Secure Mesh sites for networking-focused edge deployments, integrate external Kubernetes clusters as Customer Edge nodes, and configure cloud-specific resources including AWS VPC, Azure VNet, and GCP VPC sites....",
44604
- descriptionShort: "Multi-cloud site deployment and edge infrastructure",
44605
- descriptionMedium: "Deploy and manage F5 XC sites across AWS, Azure, and GCP. Configure AWS TGW sites, virtual sites, managed Kubernetes, and Customer Edge integrations.",
44603
+ description: "Create virtual and physical edge deployments spanning multiple providers. Establish AWS Transit Gateway connections and secure tunnel configurations for hybrid connectivity. Integrate external container orchestration systems as customer edge nodes with managed control planes. Define virtual groupings using label selectors to apply consistent policies across distributed infrastructure. Enable secure mesh communication between edge nodes and cloud workloads with automated certificate management.",
44604
+ descriptionShort: "Deploy and manage edge infrastructure",
44605
+ descriptionMedium: "Configure cloud provider resources on AWS, Azure, and GCP. Set up VPC peering, transit gateways, and VPN tunnels for hybrid environments.",
44606
44606
  aliases: ["site", "deployment"],
44607
44607
  complexity: "advanced",
44608
44608
  isPreview: false,
@@ -44666,9 +44666,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44666
44666
  ["statistics", {
44667
44667
  name: "statistics",
44668
44668
  displayName: "Statistics",
44669
- description: "Comprehensive operational analytics and monitoring capabilities for distributed cloud infrastructure. Configure alert policies with custom matchers and grouping rules to detect anomalies across namespaces. Manage alert receivers with confirmation, testing, and verification workflows for reliable notification delivery. Access flow statistics, view historical alerts, generate reports and graphs for capacity planning, track service topology and discovery patterns, and monitor real-time status...",
44670
- descriptionShort: "Flow statistics, alerts, logs, and operational analytics",
44671
- descriptionMedium: "Access flow statistics and analytics, configure alert policies and receivers, view logs, generate reports and graphs, and monitor site status.",
44669
+ description: "Set up alert policies with custom matchers, label filters, and group-by rules for targeted notifications. Define routing channels via email, webhook, or integration receivers with confirmation and verification workflows. Access flow analytics, historical alert data, and namespace-scoped metrics. Build capacity planning graphs and operational summaries. Observe deployment health and service discovery mapping across distributed environments.",
44670
+ descriptionShort: "Monitor alerts, logs, and flow analytics",
44671
+ descriptionMedium: "Configure alerting policies and notification receivers. Track service topology, build dashboards, and view site health summaries.",
44672
44672
  aliases: ["stats", "metrics", "logs"],
44673
44673
  complexity: "advanced",
44674
44674
  isPreview: false,
@@ -44680,9 +44680,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44680
44680
  ["support", {
44681
44681
  name: "support",
44682
44682
  displayName: "Support",
44683
- description: "Manage the complete customer support ticket lifecycle including creation, commenting, priority adjustment, escalation, and closure. Submit specialized requests such as tax exemption verification. Access site-level diagnostic capabilities including TCP dump capture, listing, and management for network troubleshooting. Integrates with operational workflows to enable support teams to gather diagnostic data directly from distributed sites while maintaining ticket-based tracking of all customer...",
44684
- descriptionShort: "Customer support ticket lifecycle and site diagnostics",
44685
- descriptionMedium: "Create, track, and manage support tickets with escalation workflows. Includes site diagnostic tools for packet capture and troubleshooting.",
44683
+ description: "Open new cases and assign severity ratings based on business impact. Append notes throughout resolution workflows. Mark items as closed or reinstate them if symptoms recur. Execute diagnostic packet captures on deployed sites for network troubleshooting. Handle tax exemption verification through certificate submission.",
44684
+ descriptionShort: "Create and track customer tickets",
44685
+ descriptionMedium: "Submit requests with file uploads and priority levels. Add comments and escalate critical incidents to engineering teams.",
44686
44686
  aliases: ["tickets", "help-desk"],
44687
44687
  complexity: "moderate",
44688
44688
  isPreview: false,
@@ -44708,16 +44708,16 @@ var generatedDomains = /* @__PURE__ */ new Map([
44708
44708
  ["tenant_and_identity", {
44709
44709
  name: "tenant_and_identity",
44710
44710
  displayName: "Tenant And Identity",
44711
- description: "Comprehensive user and tenant identity management for F5 Distributed Cloud. Configure user settings including profile images, notification preferences (admin and combined), and view preferences. Manage user sessions with listing and control capabilities. Handle OTP (one-time password) administration including admin resets. Support identity management (IDM) enable/disable operations. Process initial access requests for new users. Manage customer support ticket attachments and interactions for...",
44712
- descriptionShort: "User settings, notifications, sessions, and identity...",
44713
- descriptionMedium: "Manage user profiles, notification preferences, session controls, OTP settings, and customer support interactions. Configure identity management...",
44714
- aliases: [],
44711
+ description: "Set up granular alert routing for administrative and combined channels with personalized delivery options. Control active login sessions and enforce one-time password resets for security compliance. Define display layouts and avatar images for customized user experiences. Process onboarding access submissions and toggle account management features. Coordinate support ticket attachments and client relationship interactions across managed tenant hierarchies.",
44712
+ descriptionShort: "Manage user profiles and session controls",
44713
+ descriptionMedium: "Configure OTP resets and admin alert channels. Handle view settings and profile customization for platform participants.",
44714
+ aliases: ["tenant-identity", "idm", "user-settings"],
44715
44715
  complexity: "advanced",
44716
44716
  isPreview: false,
44717
44717
  requiresTier: "Standard",
44718
- category: "Other",
44719
- useCases: [],
44720
- relatedDomains: []
44718
+ category: "Platform",
44719
+ useCases: ["Manage user profiles and notification preferences", "Configure session controls and OTP settings", "Handle identity management operations", "Process initial user access requests"],
44720
+ relatedDomains: ["users", "authentication", "system"]
44721
44721
  }],
44722
44722
  ["threat_campaign", {
44723
44723
  name: "threat_campaign",
@@ -44736,9 +44736,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44736
44736
  ["users", {
44737
44737
  name: "users",
44738
44738
  displayName: "Users",
44739
- description: "Comprehensive user and identity management for the F5 XC platform. Create and manage registration tokens for site and node onboarding, including cloud-init configuration retrieval. Define known label keys and values to establish consistent resource tagging taxonomies across namespaces. Configure implicit labels for automatic resource classification. Supports full lifecycle management of user-related configuration objects with metadata tracking, state management, and condition monitoring for...",
44740
- descriptionShort: "User accounts, tokens, and label management",
44741
- descriptionMedium: "Manage user accounts, registration tokens, and label systems. Configure known and implicit labels for resource organization and user identification.",
44739
+ description: "Deploy namespace-scoped access credentials with lifecycle state tracking for secure machine enrollment. Build hierarchical tagging frameworks that enable systematic organization of infrastructure elements. Retrieve automated provisioning payloads for streamlined node initialization. Enable system-level automatic tagging that applies predefined metadata to newly created objects without operator action.",
44740
+ descriptionShort: "Manage account tokens and label settings",
44741
+ descriptionMedium: "Configure credential issuance and cloud-init provisioning. Establish key-value taxonomies for consistent resource categorization across deployments.",
44742
44742
  aliases: ["user", "accounts", "iam"],
44743
44743
  complexity: "simple",
44744
44744
  isPreview: false,
@@ -44750,9 +44750,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44750
44750
  ["virtual", {
44751
44751
  name: "virtual",
44752
44752
  displayName: "Virtual",
44753
- description: "Set up load balancing for HTTP, TCP, and UDP protocols with origin pool configuration and weighted routing. Create service policies to control access patterns and enforce rate limits on incoming requests. Deploy geo-location routing for region-aware traffic steering. Configure health checks to monitor backend availability and trigger automatic failover. Manage proxy forwarding rules and threat protection including malware scanning and campaign blocking.",
44754
- descriptionShort: "Configure HTTP and TCP load balancers",
44755
- descriptionMedium: "Manage origin pools and routing rules. Define rate limiting, service policies, and health checks for traffic distribution.",
44753
+ description: "Deploy load balancers across protocols with origin pool management and service discovery. Set up geo-location routing to direct traffic based on client location. Define rate limiter policies to control request volume and protect services from abuse. Configure health checks for origin monitoring and automatic failover. Manage service policies for access control and traffic filtering. Enable malware protection and threat campaign blocking for security enforcement.",
44754
+ descriptionShort: "Configure load balancers and origin pools",
44755
+ descriptionMedium: "Create HTTP, TCP, and UDP load balancers with origin pools. Define routing rules, health checks, and rate limiting policies.",
44756
44756
  aliases: ["lb", "loadbalancer", "vhost"],
44757
44757
  complexity: "advanced",
44758
44758
  isPreview: false,
@@ -44830,9 +44830,9 @@ var generatedDomains = /* @__PURE__ */ new Map([
44830
44830
  ["waf", {
44831
44831
  name: "waf",
44832
44832
  displayName: "Waf",
44833
- description: "Deploy protection against common web attacks including injection, cross-site scripting, and protocol violations. Set up bot detection with configurable actions for automated traffic handling. Create exclusion policies to whitelist trusted requests and reduce false positives. Monitor security events and rule hits through metrics collection to analyze threat patterns and refine defensive configurations for virtual hosts.",
44834
- descriptionShort: "Configure web application firewall rules and policies",
44835
- descriptionMedium: "Manage application security through attack detection and blocking settings. Define custom response codes and signature-based threat mitigation.",
44833
+ description: "Set up firewall configurations with attack type settings and violation detection. Create exclusion policies to tune false positives and customize blocking responses. Deploy staged signatures before production release and monitor rule hits through security event metrics. Integrate with virtual hosts for layered protection using AI-based risk blocking and anonymization settings for sensitive data handling.",
44834
+ descriptionShort: "Configure application firewall rules and bot protection",
44835
+ descriptionMedium: "Define security policies for web applications. Manage attack signatures, exclusion rules, and threat detection settings.",
44836
44836
  aliases: ["firewall", "appfw"],
44837
44837
  complexity: "advanced",
44838
44838
  isPreview: false,
@@ -45309,8 +45309,8 @@ function getLogoModeFromEnv(envPrefix) {
45309
45309
  var CLI_NAME = "xcsh";
45310
45310
  var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
45311
45311
  function getVersion() {
45312
- if ("6.28.0") {
45313
- return "6.28.0";
45312
+ if ("6.30.0") {
45313
+ return "6.30.0";
45314
45314
  }
45315
45315
  if (process.env.XCSH_VERSION) {
45316
45316
  return process.env.XCSH_VERSION;
@@ -45579,6 +45579,15 @@ var ProfileManager = class {
45579
45579
  return null;
45580
45580
  }
45581
45581
  }
45582
+ /**
45583
+ * Clear the active profile (used for force delete)
45584
+ */
45585
+ async clearActive() {
45586
+ try {
45587
+ await fs2.unlink(this.config.activeProfileFile);
45588
+ } catch {
45589
+ }
45590
+ }
45582
45591
  /**
45583
45592
  * Set the active profile
45584
45593
  */
@@ -45694,16 +45703,54 @@ var APIError = class extends Error {
45694
45703
  };
45695
45704
 
45696
45705
  // src/api/client.ts
45706
+ var DEFAULT_RETRY_CONFIG = {
45707
+ maxRetries: 3,
45708
+ initialDelayMs: 1e3,
45709
+ maxDelayMs: 1e4,
45710
+ backoffMultiplier: 2,
45711
+ jitter: true
45712
+ };
45713
+ var RETRYABLE_STATUS_CODES = /* @__PURE__ */ new Set([
45714
+ 408,
45715
+ // Request Timeout
45716
+ 429,
45717
+ // Too Many Requests
45718
+ 500,
45719
+ // Internal Server Error
45720
+ 502,
45721
+ // Bad Gateway
45722
+ 503,
45723
+ // Service Unavailable
45724
+ 504
45725
+ // Gateway Timeout
45726
+ ]);
45727
+ function calculateBackoffDelay(attempt, config) {
45728
+ const exponentialDelay = config.initialDelayMs * Math.pow(config.backoffMultiplier, attempt);
45729
+ const cappedDelay = Math.min(exponentialDelay, config.maxDelayMs);
45730
+ if (config.jitter) {
45731
+ const jitterFactor = 1 + Math.random() * 0.25;
45732
+ return Math.floor(cappedDelay * jitterFactor);
45733
+ }
45734
+ return cappedDelay;
45735
+ }
45736
+ function sleep(ms) {
45737
+ return new Promise((resolve) => setTimeout(resolve, ms));
45738
+ }
45697
45739
  var APIClient = class {
45698
45740
  serverUrl;
45699
45741
  apiToken;
45700
45742
  timeout;
45701
45743
  debug;
45744
+ retryConfig;
45702
45745
  constructor(config) {
45703
45746
  this.serverUrl = config.serverUrl.replace(/\/+$/, "");
45704
45747
  this.apiToken = config.apiToken ?? "";
45705
45748
  this.timeout = config.timeout ?? 3e4;
45706
45749
  this.debug = config.debug ?? false;
45750
+ this.retryConfig = {
45751
+ ...DEFAULT_RETRY_CONFIG,
45752
+ ...config.retry
45753
+ };
45707
45754
  }
45708
45755
  /**
45709
45756
  * Check if client has authentication configured
@@ -45734,25 +45781,21 @@ var APIClient = class {
45734
45781
  return url;
45735
45782
  }
45736
45783
  /**
45737
- * Execute an HTTP request
45784
+ * Check if an error is retryable
45738
45785
  */
45739
- async request(options) {
45740
- const url = this.buildUrl(options.path, options.query);
45741
- const headers = {
45742
- "Content-Type": "application/json",
45743
- Accept: "application/json",
45744
- ...options.headers
45745
- };
45746
- if (this.apiToken) {
45747
- headers["Authorization"] = `APIToken ${this.apiToken}`;
45786
+ isRetryableError(error) {
45787
+ if (error instanceof APIError) {
45788
+ return RETRYABLE_STATUS_CODES.has(error.statusCode);
45748
45789
  }
45749
- const body = options.body ? JSON.stringify(options.body) : null;
45750
- if (this.debug) {
45751
- console.error(`DEBUG: ${options.method} ${url}`);
45752
- if (body) {
45753
- console.error(`DEBUG: Request body: ${body}`);
45754
- }
45790
+ if (error instanceof Error) {
45791
+ return error.name === "AbortError" || error.message.includes("fetch failed") || error.message.includes("network") || error.message.includes("ECONNREFUSED") || error.message.includes("ENOTFOUND") || error.message.includes("ETIMEDOUT");
45755
45792
  }
45793
+ return false;
45794
+ }
45795
+ /**
45796
+ * Execute a single HTTP request attempt
45797
+ */
45798
+ async executeRequest(options, url, headers, body) {
45756
45799
  const controller = new AbortController();
45757
45800
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
45758
45801
  try {
@@ -45801,7 +45844,7 @@ var APIClient = class {
45801
45844
  if (error instanceof Error && error.name === "AbortError") {
45802
45845
  throw new APIError(
45803
45846
  `Request timed out after ${this.timeout}ms`,
45804
- 0,
45847
+ 408,
45805
45848
  void 0,
45806
45849
  `${options.method} ${options.path}`
45807
45850
  );
@@ -45817,6 +45860,58 @@ var APIClient = class {
45817
45860
  throw error;
45818
45861
  }
45819
45862
  }
45863
+ /**
45864
+ * Execute an HTTP request with retry logic
45865
+ */
45866
+ async request(options) {
45867
+ const url = this.buildUrl(options.path, options.query);
45868
+ const headers = {
45869
+ "Content-Type": "application/json",
45870
+ Accept: "application/json",
45871
+ ...options.headers
45872
+ };
45873
+ if (this.apiToken) {
45874
+ headers["Authorization"] = `APIToken ${this.apiToken}`;
45875
+ }
45876
+ const body = options.body ? JSON.stringify(options.body) : null;
45877
+ if (this.debug) {
45878
+ console.error(`DEBUG: ${options.method} ${url}`);
45879
+ if (body) {
45880
+ console.error(`DEBUG: Request body: ${body}`);
45881
+ }
45882
+ }
45883
+ let lastError;
45884
+ for (let attempt = 0; attempt <= this.retryConfig.maxRetries; attempt++) {
45885
+ try {
45886
+ return await this.executeRequest(
45887
+ options,
45888
+ url,
45889
+ headers,
45890
+ body
45891
+ );
45892
+ } catch (error) {
45893
+ lastError = error instanceof Error ? error : new Error(String(error));
45894
+ const isRetryable = this.isRetryableError(error);
45895
+ const hasRetriesLeft = attempt < this.retryConfig.maxRetries;
45896
+ if (isRetryable && hasRetriesLeft) {
45897
+ const delay = calculateBackoffDelay(
45898
+ attempt,
45899
+ this.retryConfig
45900
+ );
45901
+ if (this.debug) {
45902
+ const statusInfo = error instanceof APIError ? ` (${error.statusCode})` : "";
45903
+ console.error(
45904
+ `DEBUG: Request failed${statusInfo}, retrying in ${delay}ms (attempt ${attempt + 1}/${this.retryConfig.maxRetries})`
45905
+ );
45906
+ }
45907
+ await sleep(delay);
45908
+ continue;
45909
+ }
45910
+ throw error;
45911
+ }
45912
+ }
45913
+ throw lastError ?? new Error("Request failed after all retries");
45914
+ }
45820
45915
  /**
45821
45916
  * GET request
45822
45917
  */
@@ -45880,621 +45975,8 @@ var APIClient = class {
45880
45975
  }
45881
45976
  };
45882
45977
 
45883
- // src/subscription/types.ts
45884
- var Tier = {
45885
- NoTier: "NO_TIER",
45886
- Basic: "BASIC",
45887
- // Discontinued - maps to Standard
45888
- Standard: "STANDARD",
45889
- // Active tier
45890
- Advanced: "ADVANCED",
45891
- // Active tier
45892
- Premium: "PREMIUM"
45893
- // Discontinued - maps to Advanced
45894
- };
45895
- var AddonState = {
45896
- None: "AS_NONE",
45897
- Pending: "AS_PENDING",
45898
- Subscribed: "AS_SUBSCRIBED",
45899
- Error: "AS_ERROR"
45900
- };
45901
- var AccessStatus = {
45902
- Allowed: "AS_AC_ALLOWED",
45903
- Denied: "AS_AC_PBAC_DENY",
45904
- UpgradeRequired: "AS_AC_PBAC_DENY_UPGRADE_PLAN",
45905
- ContactSales: "AS_AC_PBAC_DENY_CONTACT_SALES",
45906
- InternalService: "AS_AC_PBAC_DENY_INTERNAL_SVC",
45907
- Unknown: "AS_AC_UNKNOWN",
45908
- EOL: "AS_AC_EOL"
45909
- };
45910
- var ActivationType = {
45911
- Self: "self",
45912
- PartiallyManaged: "partially_managed",
45913
- Managed: "managed"
45914
- };
45915
- var SubscriptionState = {
45916
- Pending: "SUBSCRIPTION_PENDING",
45917
- Enabled: "SUBSCRIPTION_ENABLED",
45918
- DisablePending: "SUBSCRIPTION_DISABLE_PENDING",
45919
- Disabled: "SUBSCRIPTION_DISABLED"
45920
- };
45921
- var ValidationStatus = {
45922
- Pass: "PASS",
45923
- Fail: "FAIL",
45924
- Warning: "WARNING"
45925
- };
45926
- var QuotaStatus = {
45927
- OK: "OK",
45928
- Warning: "WARNING",
45929
- Exceeded: "EXCEEDED"
45930
- };
45931
- function isAddonActive(addon) {
45932
- return addon.state === AddonState.Subscribed;
45933
- }
45934
- function isAddonAvailable(addon) {
45935
- return addon.accessStatus === AccessStatus.Allowed && addon.state !== AddonState.Subscribed;
45936
- }
45937
- function isAddonDenied(addon) {
45938
- return addon.accessStatus === AccessStatus.Denied || addon.accessStatus === AccessStatus.UpgradeRequired || addon.accessStatus === AccessStatus.ContactSales || addon.accessStatus === AccessStatus.InternalService;
45939
- }
45940
- function isQuotaExceeded(quota) {
45941
- return quota.usage >= quota.limit;
45942
- }
45943
- function isQuotaAtRisk(quota) {
45944
- return quota.percentage >= 80 && quota.percentage < 100;
45945
- }
45946
- function getQuotaRemainingCapacity(quota) {
45947
- const remaining = quota.limit - quota.usage;
45948
- return remaining < 0 ? 0 : remaining;
45949
- }
45950
- function getTierDescription(tier) {
45951
- switch (tier) {
45952
- case Tier.NoTier:
45953
- return "No Tier";
45954
- case Tier.Basic:
45955
- return "Standard";
45956
- // Basic discontinued, maps to Standard
45957
- case Tier.Standard:
45958
- return "Standard";
45959
- case Tier.Advanced:
45960
- return "Advanced";
45961
- case Tier.Premium:
45962
- return "Advanced";
45963
- // Premium discontinued, maps to Advanced
45964
- default:
45965
- return "Unknown";
45966
- }
45967
- }
45968
- function getStateDescription(state) {
45969
- switch (state) {
45970
- case AddonState.None:
45971
- return "Not Subscribed";
45972
- case AddonState.Pending:
45973
- return "Pending";
45974
- case AddonState.Subscribed:
45975
- return "Subscribed";
45976
- case AddonState.Error:
45977
- return "Error";
45978
- default:
45979
- return "Unknown";
45980
- }
45981
- }
45982
- function getAccessStatusDescription(status) {
45983
- switch (status) {
45984
- case AccessStatus.Allowed:
45985
- return "Allowed";
45986
- case AccessStatus.Denied:
45987
- return "Denied";
45988
- case AccessStatus.UpgradeRequired:
45989
- return "Upgrade Required";
45990
- case AccessStatus.ContactSales:
45991
- return "Contact Sales";
45992
- case AccessStatus.InternalService:
45993
- return "Internal Service";
45994
- case AccessStatus.Unknown:
45995
- return "Unknown";
45996
- case AccessStatus.EOL:
45997
- return "End of Life";
45998
- default:
45999
- return "Unknown";
46000
- }
46001
- }
46002
- function getQuotaStatusFromPercentage(percentage) {
46003
- if (percentage >= 100) {
46004
- return QuotaStatus.Exceeded;
46005
- }
46006
- if (percentage >= 80) {
46007
- return QuotaStatus.Warning;
46008
- }
46009
- return QuotaStatus.OK;
46010
- }
46011
-
46012
- // src/subscription/client.ts
46013
- var SubscriptionClient = class {
46014
- apiClient;
46015
- constructor(apiClient) {
46016
- this.apiClient = apiClient;
46017
- }
46018
- /**
46019
- * Format display name from service name
46020
- * e.g., "client-side-defense" -> "Client Side Defense"
46021
- */
46022
- formatDisplayName(name) {
46023
- return name.split("-").map(
46024
- (word) => word.length > 0 ? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() : ""
46025
- ).join(" ");
46026
- }
46027
- /**
46028
- * Normalize tier value
46029
- */
46030
- normalizeTier(tier) {
46031
- const normalized = tier.toUpperCase().trim();
46032
- switch (normalized) {
46033
- case "NO_TIER":
46034
- case "NOTIER":
46035
- case "":
46036
- return "NO_TIER";
46037
- case "BASIC":
46038
- return "BASIC";
46039
- case "STANDARD":
46040
- return "STANDARD";
46041
- case "ADVANCED":
46042
- return "ADVANCED";
46043
- case "PREMIUM":
46044
- return "PREMIUM";
46045
- default:
46046
- return tier;
46047
- }
46048
- }
46049
- /**
46050
- * Normalize state value
46051
- */
46052
- normalizeState(state) {
46053
- const normalized = state.toUpperCase().trim();
46054
- switch (normalized) {
46055
- case "AS_NONE":
46056
- case "NONE":
46057
- case "":
46058
- return AddonState.None;
46059
- case "AS_PENDING":
46060
- case "PENDING":
46061
- return AddonState.Pending;
46062
- case "AS_SUBSCRIBED":
46063
- case "SUBSCRIBED":
46064
- return AddonState.Subscribed;
46065
- case "AS_ERROR":
46066
- case "ERROR":
46067
- return AddonState.Error;
46068
- default:
46069
- return state;
46070
- }
46071
- }
46072
- /**
46073
- * Normalize access status value
46074
- */
46075
- normalizeAccessStatus(status) {
46076
- const normalized = status.toUpperCase().trim();
46077
- switch (normalized) {
46078
- case "AS_AC_ALLOWED":
46079
- case "ALLOWED":
46080
- case "":
46081
- return AccessStatus.Allowed;
46082
- case "AS_AC_PBAC_DENY":
46083
- case "DENIED":
46084
- case "DENY":
46085
- return AccessStatus.Denied;
46086
- case "AS_AC_PBAC_DENY_UPGRADE_PLAN":
46087
- case "UPGRADE_REQUIRED":
46088
- case "UPGRADE_PLAN":
46089
- return AccessStatus.UpgradeRequired;
46090
- case "AS_AC_PBAC_DENY_CONTACT_SALES":
46091
- case "CONTACT_SALES":
46092
- return AccessStatus.ContactSales;
46093
- case "AS_AC_PBAC_DENY_INTERNAL_SVC":
46094
- case "INTERNAL_SERVICE":
46095
- return AccessStatus.InternalService;
46096
- default:
46097
- return status;
46098
- }
46099
- }
46100
- /**
46101
- * Determine tier from tenant type
46102
- */
46103
- determineTierFromTenantType(tenantType) {
46104
- switch (tenantType.toUpperCase()) {
46105
- case "ENTERPRISE":
46106
- return "Advanced";
46107
- case "FREEMIUM":
46108
- return "Standard";
46109
- default:
46110
- return "Standard";
46111
- }
46112
- }
46113
- /**
46114
- * Get subscription plans
46115
- */
46116
- async getPlans(namespace = "system") {
46117
- try {
46118
- const path = `/api/web/namespaces/${namespace}/plans`;
46119
- const response = await this.apiClient.get(path);
46120
- const plans = [];
46121
- for (const item of response.data?.items ?? []) {
46122
- if (!item?.metadata?.name) continue;
46123
- const plan = {
46124
- name: item.metadata.name,
46125
- displayName: item.spec?.display_name ?? item.metadata.name,
46126
- includedServices: item.spec?.included_services?.map(
46127
- (s) => s.name ?? ""
46128
- ) ?? [],
46129
- allowedServices: item.spec?.allowed_services?.map((s) => s.name ?? "") ?? []
46130
- };
46131
- if (item.spec?.description) {
46132
- plan.description = item.spec.description;
46133
- }
46134
- plans.push(plan);
46135
- }
46136
- return plans;
46137
- } catch {
46138
- return [];
46139
- }
46140
- }
46141
- /**
46142
- * Get addon service activation status
46143
- */
46144
- async getAddonServiceActivationStatus(addonName) {
46145
- try {
46146
- const path = `/api/web/namespaces/system/addon_services/${addonName}/activation-status`;
46147
- const response = await this.apiClient.get(path);
46148
- return {
46149
- name: addonName,
46150
- displayName: this.formatDisplayName(addonName),
46151
- tier: this.normalizeTier(response.data.tier ?? ""),
46152
- state: this.normalizeState(response.data.state ?? ""),
46153
- accessStatus: this.normalizeAccessStatus(
46154
- response.data.access_status ?? ""
46155
- )
46156
- };
46157
- } catch {
46158
- return null;
46159
- }
46160
- }
46161
- /**
46162
- * Get addon services
46163
- */
46164
- async getAddonServices(namespace = "system") {
46165
- const path = `/api/web/namespaces/${namespace}/addon_services`;
46166
- const response = await this.apiClient.get(path);
46167
- const addons = [];
46168
- for (const item of response.data.items ?? []) {
46169
- let addon = {
46170
- name: item.name,
46171
- displayName: this.formatDisplayName(item.name),
46172
- tier: "",
46173
- state: AddonState.None,
46174
- accessStatus: AccessStatus.Allowed
46175
- };
46176
- if (item.description) {
46177
- addon.description = item.description;
46178
- }
46179
- if (item.namespace) {
46180
- addon.namespace = item.namespace;
46181
- }
46182
- if (item.disabled) {
46183
- addon.state = AddonState.None;
46184
- addon.accessStatus = AccessStatus.Denied;
46185
- }
46186
- const activationStatus = await this.getAddonServiceActivationStatus(
46187
- item.name
46188
- );
46189
- if (activationStatus) {
46190
- addon = {
46191
- ...addon,
46192
- state: activationStatus.state,
46193
- accessStatus: activationStatus.accessStatus,
46194
- tier: activationStatus.tier
46195
- };
46196
- }
46197
- addons.push(addon);
46198
- }
46199
- return addons;
46200
- }
46201
- /**
46202
- * Get quota usage information (tenant-level)
46203
- */
46204
- async getQuotaInfo() {
46205
- const path = "/api/web/namespaces/system/quota/usage";
46206
- const response = await this.apiClient.get(path);
46207
- const objects = [];
46208
- const quotaMap = response.data.objects ?? response.data.quota_usage ?? {};
46209
- for (const [name, entry] of Object.entries(quotaMap)) {
46210
- const limit = entry.limit?.maximum ?? 0;
46211
- const usage = entry.usage?.current ?? 0;
46212
- if (limit < 0 || usage < 0) {
46213
- continue;
46214
- }
46215
- const percentage = limit > 0 ? usage / limit * 100 : 0;
46216
- const quotaItem = {
46217
- name,
46218
- displayName: entry.display_name ?? name,
46219
- objectType: name,
46220
- limit,
46221
- usage,
46222
- percentage,
46223
- status: getQuotaStatusFromPercentage(percentage)
46224
- };
46225
- if (entry.description) {
46226
- quotaItem.description = entry.description;
46227
- }
46228
- objects.push(quotaItem);
46229
- }
46230
- return {
46231
- namespace: "tenant",
46232
- // Quotas are tenant-level
46233
- objects
46234
- };
46235
- }
46236
- /**
46237
- * Get current usage plan
46238
- */
46239
- async getCurrentUsagePlan() {
46240
- const path = "/api/web/namespaces/system/usage_plans/current";
46241
- const response = await this.apiClient.get(path);
46242
- for (const plan of response.data.plans ?? []) {
46243
- if (plan.current) {
46244
- return plan;
46245
- }
46246
- }
46247
- if (response.data.plans && response.data.plans.length > 0) {
46248
- return response.data.plans[0] ?? null;
46249
- }
46250
- return null;
46251
- }
46252
- /**
46253
- * Get subscription tier from current plan
46254
- */
46255
- async getTierFromCurrentPlan() {
46256
- const plan = await this.getCurrentUsagePlan();
46257
- if (!plan) {
46258
- return "Standard";
46259
- }
46260
- return this.determineTierFromTenantType(plan.tenant_type);
46261
- }
46262
- /**
46263
- * Get complete subscription information
46264
- */
46265
- async getSubscriptionInfo() {
46266
- const plans = await this.getPlans("system");
46267
- const addons = await this.getAddonServices("system");
46268
- const quotaInfo = await this.getQuotaInfo();
46269
- let tier;
46270
- try {
46271
- tier = await this.getTierFromCurrentPlan();
46272
- } catch {
46273
- tier = this.determineTierFromPlansAndAddons(plans, addons);
46274
- }
46275
- const activeAddons = addons.filter(isAddonActive);
46276
- const availableAddons = addons.filter(isAddonAvailable);
46277
- let atRisk = 0;
46278
- let exceeded = 0;
46279
- for (const q of quotaInfo.objects) {
46280
- if (isQuotaExceeded(q)) {
46281
- exceeded++;
46282
- } else if (isQuotaAtRisk(q)) {
46283
- atRisk++;
46284
- }
46285
- }
46286
- const quotaSummary = {
46287
- totalLimits: quotaInfo.objects.length,
46288
- limitsAtRisk: atRisk,
46289
- limitsExceeded: exceeded,
46290
- objects: quotaInfo.objects
46291
- };
46292
- const info = {
46293
- tier,
46294
- activeAddons,
46295
- availableAddons,
46296
- quotaSummary,
46297
- plan: plans[0] ?? {
46298
- name: "unknown",
46299
- displayName: "Unknown"
46300
- }
46301
- };
46302
- return info;
46303
- }
46304
- /**
46305
- * Determine tier from plans and addons (legacy fallback)
46306
- */
46307
- determineTierFromPlansAndAddons(plans, addons) {
46308
- for (const plan of plans) {
46309
- const nameLower = plan.name.toLowerCase();
46310
- const displayLower = plan.displayName.toLowerCase();
46311
- if (nameLower.includes("advanced") || displayLower.includes("advanced")) {
46312
- return "Advanced";
46313
- }
46314
- if (nameLower.includes("enterprise") || displayLower.includes("enterprise")) {
46315
- return "Advanced";
46316
- }
46317
- }
46318
- for (const addon of addons) {
46319
- if (isAddonActive(addon) && (addon.tier === "ADVANCED" || addon.tier === "PREMIUM")) {
46320
- return "Advanced";
46321
- }
46322
- }
46323
- return "Standard";
46324
- }
46325
- /**
46326
- * Validate resource deployment
46327
- */
46328
- async validateResource(req) {
46329
- const result = {
46330
- valid: true,
46331
- checks: [],
46332
- warnings: [],
46333
- errors: []
46334
- };
46335
- if (req.resourceType && req.count && req.count > 0) {
46336
- const quotaInfo = await this.getQuotaInfo();
46337
- let found = false;
46338
- for (const q of quotaInfo.objects) {
46339
- if (q.objectType?.toLowerCase() === req.resourceType.toLowerCase() || q.name.toLowerCase() === req.resourceType.toLowerCase()) {
46340
- found = true;
46341
- const remaining = getQuotaRemainingCapacity(q);
46342
- const check = {
46343
- type: "quota",
46344
- resource: req.resourceType,
46345
- current: q.usage,
46346
- requested: req.count,
46347
- limit: q.limit,
46348
- result: ValidationStatus.Pass
46349
- };
46350
- if (req.count > remaining) {
46351
- check.result = ValidationStatus.Fail;
46352
- check.message = `Quota exceeded: ${req.resourceType} would have ${Math.floor(q.usage + req.count)}/${q.limit} (requesting ${req.count}, only ${Math.floor(remaining)} available)`;
46353
- result.valid = false;
46354
- result.errors?.push(check.message);
46355
- } else if ((q.usage + req.count) / q.limit >= 0.8) {
46356
- check.result = ValidationStatus.Warning;
46357
- check.message = `Quota warning: ${req.resourceType} will be at ${Math.round((q.usage + req.count) / q.limit * 100)}% after deployment`;
46358
- result.warnings?.push(check.message);
46359
- } else {
46360
- check.message = `Quota OK: ${req.resourceType} has sufficient capacity (${Math.floor(remaining)} available)`;
46361
- }
46362
- result.checks.push(check);
46363
- break;
46364
- }
46365
- }
46366
- if (!found) {
46367
- result.checks.push({
46368
- type: "quota",
46369
- resource: req.resourceType,
46370
- requested: req.count,
46371
- result: ValidationStatus.Warning,
46372
- message: `No quota limit found for resource type: ${req.resourceType}`
46373
- });
46374
- }
46375
- }
46376
- if (req.feature) {
46377
- const addons = await this.getAddonServices("system");
46378
- let found = false;
46379
- for (const addon of addons) {
46380
- if (addon.name.toLowerCase() === req.feature.toLowerCase()) {
46381
- found = true;
46382
- const check = {
46383
- type: "feature",
46384
- feature: req.feature,
46385
- currentTier: addon.tier,
46386
- status: getStateDescription(addon.state),
46387
- result: ValidationStatus.Pass
46388
- };
46389
- if (isAddonActive(addon)) {
46390
- check.message = `Feature '${req.feature}' is active (tier: ${addon.tier})`;
46391
- } else if (addon.accessStatus === AccessStatus.UpgradeRequired) {
46392
- check.result = ValidationStatus.Fail;
46393
- check.message = `Feature '${req.feature}' requires a plan upgrade`;
46394
- result.valid = false;
46395
- result.errors?.push(check.message);
46396
- } else if (addon.accessStatus === AccessStatus.ContactSales) {
46397
- check.result = ValidationStatus.Fail;
46398
- check.message = `Feature '${req.feature}' requires contacting F5 sales`;
46399
- result.valid = false;
46400
- result.errors?.push(check.message);
46401
- } else if (isAddonAvailable(addon)) {
46402
- check.result = ValidationStatus.Warning;
46403
- check.message = `Feature '${req.feature}' is available but not subscribed`;
46404
- result.warnings?.push(check.message);
46405
- } else {
46406
- check.result = ValidationStatus.Fail;
46407
- check.message = `Feature '${req.feature}' is not available (access: ${getAccessStatusDescription(addon.accessStatus)})`;
46408
- result.valid = false;
46409
- result.errors?.push(check.message);
46410
- }
46411
- result.checks.push(check);
46412
- break;
46413
- }
46414
- }
46415
- if (!found) {
46416
- result.checks.push({
46417
- type: "feature",
46418
- feature: req.feature,
46419
- result: ValidationStatus.Warning,
46420
- message: `Feature '${req.feature}' not found in addon services`
46421
- });
46422
- }
46423
- }
46424
- return result;
46425
- }
46426
- /**
46427
- * Filter addons by criteria
46428
- */
46429
- filterAddons(addons, filter) {
46430
- if (!filter) {
46431
- return addons;
46432
- }
46433
- switch (filter.toLowerCase()) {
46434
- case "active":
46435
- return addons.filter(isAddonActive);
46436
- case "available":
46437
- return addons.filter(isAddonAvailable);
46438
- case "denied":
46439
- return addons.filter(
46440
- (a) => a.accessStatus === AccessStatus.Denied || a.accessStatus === AccessStatus.UpgradeRequired || a.accessStatus === AccessStatus.ContactSales || a.accessStatus === AccessStatus.InternalService
46441
- );
46442
- default:
46443
- return addons;
46444
- }
46445
- }
46446
- /**
46447
- * Get pending activation requests
46448
- */
46449
- async getPendingActivations(namespace = "system") {
46450
- const addons = await this.getAddonServices(namespace);
46451
- const result = {
46452
- pendingActivations: [],
46453
- activeAddons: [],
46454
- totalPending: 0
46455
- };
46456
- for (const addon of addons) {
46457
- if (addon.state === AddonState.Pending) {
46458
- const pending = {
46459
- addonService: addon.name,
46460
- subscriptionState: SubscriptionState.Pending,
46461
- message: this.getActivationMessage(
46462
- addon.activationType ?? ""
46463
- )
46464
- };
46465
- if (addon.namespace) {
46466
- pending.namespace = addon.namespace;
46467
- }
46468
- if (addon.activationType) {
46469
- pending.activationType = addon.activationType;
46470
- }
46471
- result.pendingActivations.push(pending);
46472
- }
46473
- if (isAddonActive(addon)) {
46474
- result.activeAddons.push(addon.name);
46475
- }
46476
- }
46477
- result.totalPending = result.pendingActivations.length;
46478
- return result;
46479
- }
46480
- /**
46481
- * Get activation message based on type
46482
- */
46483
- getActivationMessage(activationType) {
46484
- switch (activationType) {
46485
- case ActivationType.Self:
46486
- return "Self-activation in progress";
46487
- case ActivationType.PartiallyManaged:
46488
- return "Awaiting partial backend processing";
46489
- case ActivationType.Managed:
46490
- return "Awaiting SRE approval";
46491
- default:
46492
- return "Activation pending";
46493
- }
46494
- }
46495
- };
46496
-
46497
45978
  // src/repl/session.ts
45979
+ var NAMESPACE_CACHE_TTL = 5 * 60 * 1e3;
46498
45980
  var REPLSession = class {
46499
45981
  _history = null;
46500
45982
  _namespace;
@@ -46511,7 +45993,8 @@ var REPLSession = class {
46511
45993
  _profileManager;
46512
45994
  _activeProfile = null;
46513
45995
  _activeProfileName = null;
46514
- _tier = "";
45996
+ _namespaceCache = [];
45997
+ _namespaceCacheTime = 0;
46515
45998
  constructor(config = {}) {
46516
45999
  this._namespace = config.namespace ?? this.getDefaultNamespace();
46517
46000
  this._contextPath = new ContextPath();
@@ -46548,24 +46031,12 @@ var REPLSession = class {
46548
46031
  await this.loadActiveProfile();
46549
46032
  if (this._apiClient?.isAuthenticated()) {
46550
46033
  await this.fetchUserInfo();
46551
- await this.fetchTier();
46552
46034
  }
46553
46035
  }
46554
46036
  /**
46555
- * Fetch subscription tier from the API
46037
+ * Fetch user info from the API
46556
46038
  */
46557
- async fetchTier() {
46558
- if (!this._apiClient) return;
46559
- try {
46560
- const subscriptionClient = new SubscriptionClient(this._apiClient);
46561
- this._tier = await subscriptionClient.getTierFromCurrentPlan();
46562
- } catch {
46563
- }
46564
- }
46565
- /**
46566
- * Fetch user info from the API
46567
- */
46568
- async fetchUserInfo() {
46039
+ async fetchUserInfo() {
46569
46040
  if (!this._apiClient) return;
46570
46041
  try {
46571
46042
  const response = await this._apiClient.get("/api/web/custom/user/info");
@@ -46577,6 +46048,7 @@ var REPLSession = class {
46577
46048
  }
46578
46049
  /**
46579
46050
  * Load the active profile from profile manager
46051
+ * Note: Environment variables take priority over profile settings
46580
46052
  */
46581
46053
  async loadActiveProfile() {
46582
46054
  try {
@@ -46586,14 +46058,17 @@ var REPLSession = class {
46586
46058
  if (profile) {
46587
46059
  this._activeProfileName = activeName;
46588
46060
  this._activeProfile = profile;
46589
- if (profile.apiUrl) {
46061
+ const envUrl = process.env[`${ENV_PREFIX}_API_URL`];
46062
+ const envToken = process.env[`${ENV_PREFIX}_API_TOKEN`];
46063
+ const envNamespace = process.env[`${ENV_PREFIX}_NAMESPACE`];
46064
+ if (!envUrl && profile.apiUrl) {
46590
46065
  this._serverUrl = profile.apiUrl;
46591
46066
  this._tenant = this.extractTenant(profile.apiUrl);
46592
46067
  }
46593
- if (profile.apiToken) {
46068
+ if (!envToken && profile.apiToken) {
46594
46069
  this._apiToken = profile.apiToken;
46595
46070
  }
46596
- if (profile.defaultNamespace) {
46071
+ if (!envNamespace && profile.defaultNamespace) {
46597
46072
  this._namespace = profile.defaultNamespace;
46598
46073
  }
46599
46074
  if (this._serverUrl) {
@@ -46678,12 +46153,6 @@ var REPLSession = class {
46678
46153
  setUsername(username) {
46679
46154
  this._username = username;
46680
46155
  }
46681
- /**
46682
- * Get the subscription tier (Standard/Advanced)
46683
- */
46684
- getTier() {
46685
- return this._tier;
46686
- }
46687
46156
  /**
46688
46157
  * Get the context validator
46689
46158
  */
@@ -46768,6 +46237,7 @@ var REPLSession = class {
46768
46237
  if (!result.success) {
46769
46238
  return false;
46770
46239
  }
46240
+ this.clearNamespaceCache();
46771
46241
  this._activeProfileName = profileName;
46772
46242
  this._activeProfile = profile;
46773
46243
  if (profile.apiUrl) {
@@ -46798,6 +46268,30 @@ var REPLSession = class {
46798
46268
  this._activeProfileName = null;
46799
46269
  this._activeProfile = null;
46800
46270
  }
46271
+ /**
46272
+ * Get cached namespaces (returns empty array if cache is stale/empty)
46273
+ */
46274
+ getNamespaceCache() {
46275
+ const now = Date.now();
46276
+ if (this._namespaceCache.length > 0 && now - this._namespaceCacheTime < NAMESPACE_CACHE_TTL) {
46277
+ return this._namespaceCache;
46278
+ }
46279
+ return [];
46280
+ }
46281
+ /**
46282
+ * Set namespace cache
46283
+ */
46284
+ setNamespaceCache(namespaces) {
46285
+ this._namespaceCache = namespaces;
46286
+ this._namespaceCacheTime = Date.now();
46287
+ }
46288
+ /**
46289
+ * Clear namespace cache (called when switching profiles)
46290
+ */
46291
+ clearNamespaceCache() {
46292
+ this._namespaceCache = [];
46293
+ this._namespaceCacheTime = 0;
46294
+ }
46801
46295
  /**
46802
46296
  * Add a command to history
46803
46297
  */
@@ -47366,6 +46860,9 @@ var DomainRegistry = class {
47366
46860
  const subgroup = domain.subcommands.get(firstArg);
47367
46861
  if (subgroup) {
47368
46862
  if (restArgs.length === 0) {
46863
+ if (subgroup.defaultCommand) {
46864
+ return subgroup.defaultCommand.execute([], session);
46865
+ }
47369
46866
  return this.showSubcommandHelp(domain, subgroup);
47370
46867
  }
47371
46868
  const cmdName = restArgs[0]?.toLowerCase() ?? "";
@@ -47429,7 +46926,7 @@ var DomainRegistry = class {
47429
46926
  if (name.toLowerCase().startsWith(partial.toLowerCase())) {
47430
46927
  suggestions.push({
47431
46928
  text: name,
47432
- description: group.description,
46929
+ description: group.descriptionShort,
47433
46930
  category: "subcommand"
47434
46931
  });
47435
46932
  }
@@ -47438,7 +46935,7 @@ var DomainRegistry = class {
47438
46935
  if (name.toLowerCase().startsWith(partial.toLowerCase())) {
47439
46936
  suggestions.push({
47440
46937
  text: name,
47441
- description: cmd.description,
46938
+ description: cmd.descriptionShort,
47442
46939
  category: "command"
47443
46940
  });
47444
46941
  }
@@ -47452,7 +46949,7 @@ var DomainRegistry = class {
47452
46949
  if (name.toLowerCase().startsWith(partial.toLowerCase())) {
47453
46950
  suggestions.push({
47454
46951
  text: name,
47455
- description: cmd.description,
46952
+ description: cmd.descriptionShort,
47456
46953
  category: "command"
47457
46954
  });
47458
46955
  }
@@ -47555,7 +47052,9 @@ function rawStdoutResult(content) {
47555
47052
  // src/domains/login/profile/list.ts
47556
47053
  var listCommand = {
47557
47054
  name: "list",
47558
- description: "List all saved profiles",
47055
+ description: "Display all saved connection profiles with their tenant URLs and authentication types. Highlights the currently active profile for easy identification when managing multiple tenants.",
47056
+ descriptionShort: "List all saved profiles",
47057
+ descriptionMedium: "Show all profiles with tenant URLs, auth types, and active status indicator.",
47559
47058
  aliases: ["ls"],
47560
47059
  async execute(_args, _session) {
47561
47060
  const manager = getProfileManager();
@@ -47590,7 +47089,9 @@ var listCommand = {
47590
47089
  // src/domains/login/profile/show.ts
47591
47090
  var showCommand = {
47592
47091
  name: "show",
47593
- description: "Show profile details (sensitive data masked)",
47092
+ description: "Display detailed configuration for a specific profile. Shows tenant URL, authentication method, and namespace settings with sensitive credentials securely masked for safe viewing.",
47093
+ descriptionShort: "Show profile details (masked credentials)",
47094
+ descriptionMedium: "Display profile configuration with tenant URL, auth type, and masked credentials.",
47594
47095
  usage: "<name>",
47595
47096
  aliases: ["get", "view"],
47596
47097
  async execute(args, _session) {
@@ -47646,7 +47147,9 @@ var showCommand = {
47646
47147
  // src/domains/login/profile/create.ts
47647
47148
  var createCommand2 = {
47648
47149
  name: "create",
47649
- description: "Create a new profile",
47150
+ description: "Create a new connection profile with tenant URL and authentication credentials. Profiles store all settings needed to connect to a tenant, including optional default namespace for scoped operations.",
47151
+ descriptionShort: "Create a new connection profile",
47152
+ descriptionMedium: "Create a profile with tenant URL, authentication token, and optional default namespace.",
47650
47153
  usage: "<name> --url <api-url> --token <api-token> [--namespace <ns>]",
47651
47154
  aliases: ["add", "new"],
47652
47155
  async execute(args, _session) {
@@ -47696,10 +47199,11 @@ var createCommand2 = {
47696
47199
  if (!apiToken) {
47697
47200
  return errorResult("Missing required --token option");
47698
47201
  }
47202
+ const sanitizedToken = apiToken.replace(/^["']|["']$/g, "");
47699
47203
  const profile = {
47700
47204
  name,
47701
47205
  apiUrl,
47702
- apiToken
47206
+ apiToken: sanitizedToken
47703
47207
  };
47704
47208
  if (defaultNamespace) {
47705
47209
  profile.defaultNamespace = defaultNamespace;
@@ -47719,26 +47223,22 @@ var createCommand2 = {
47719
47223
  // src/domains/login/profile/use.ts
47720
47224
  var useCommand = {
47721
47225
  name: "use",
47722
- description: "Switch to a different profile",
47226
+ description: "Switch the active connection to a different saved profile. Updates the session context to use the new profile's tenant URL, credentials, and default namespace for all subsequent operations.",
47227
+ descriptionShort: "Switch to a different profile",
47228
+ descriptionMedium: "Activate a profile and update session context with its tenant and namespace settings.",
47723
47229
  usage: "<name>",
47724
47230
  aliases: ["switch", "activate"],
47725
47231
  async execute(args, session) {
47726
- const manager = getProfileManager();
47727
47232
  const name = args[0];
47728
47233
  if (!name) {
47729
47234
  return errorResult("Usage: login profile use <name>");
47730
47235
  }
47731
47236
  try {
47732
- const result = await manager.setActive(name);
47733
- if (!result.success) {
47734
- return errorResult(result.message);
47735
- }
47736
- const profile = await manager.get(name);
47737
- if (profile) {
47738
- if (profile.defaultNamespace) {
47739
- session.setNamespace(profile.defaultNamespace);
47740
- }
47237
+ const success = await session.switchProfile(name);
47238
+ if (!success) {
47239
+ return errorResult(`Profile '${name}' not found.`);
47741
47240
  }
47241
+ const profile = session.getActiveProfile();
47742
47242
  return successResult(
47743
47243
  [
47744
47244
  `Switched to profile '${name}'.`,
@@ -47766,7 +47266,9 @@ var useCommand = {
47766
47266
  // src/domains/login/profile/delete.ts
47767
47267
  var deleteCommand = {
47768
47268
  name: "delete",
47769
- description: "Delete a saved profile",
47269
+ description: "Delete a saved connection profile permanently. Requires --force flag to delete the currently active profile to prevent accidental disconnection from active tenant.",
47270
+ descriptionShort: "Delete a saved profile",
47271
+ descriptionMedium: "Remove a saved profile permanently. Use --force to delete active profile.",
47770
47272
  usage: "<name> [--force]",
47771
47273
  aliases: ["rm", "remove"],
47772
47274
  async execute(args, _session) {
@@ -47794,6 +47296,7 @@ var deleteCommand = {
47794
47296
  ].join("\n")
47795
47297
  );
47796
47298
  }
47299
+ await manager.clearActive();
47797
47300
  }
47798
47301
  const result = await manager.delete(name);
47799
47302
  if (!result.success) {
@@ -47815,10 +47318,66 @@ var deleteCommand = {
47815
47318
  }
47816
47319
  };
47817
47320
 
47321
+ // src/domains/login/profile/active.ts
47322
+ var activeCommand = {
47323
+ name: "active",
47324
+ description: "Display the currently active profile configuration including tenant URL, authentication method, and default namespace. Shows masked credentials for security while confirming connection settings.",
47325
+ descriptionShort: "Display active profile configuration",
47326
+ descriptionMedium: "Show current active profile details including tenant URL, auth type, and namespace settings.",
47327
+ async execute(_args, _session) {
47328
+ const manager = getProfileManager();
47329
+ try {
47330
+ const activeName = await manager.getActive();
47331
+ if (!activeName) {
47332
+ return successResult([
47333
+ "No active profile set.",
47334
+ "",
47335
+ "Run 'login profile list' to see available profiles.",
47336
+ "Run 'login profile use <name>' to activate a profile."
47337
+ ]);
47338
+ }
47339
+ const profile = await manager.get(activeName);
47340
+ if (!profile) {
47341
+ return errorResult(
47342
+ `Active profile '${activeName}' not found. Run 'login profile list' to see available profiles.`
47343
+ );
47344
+ }
47345
+ const masked = manager.maskProfile(profile);
47346
+ const output = [
47347
+ `Active Profile: ${profile.name}`,
47348
+ ``,
47349
+ ` API URL: ${masked.apiUrl}`
47350
+ ];
47351
+ if (masked.apiToken) {
47352
+ output.push(` API Token: ${masked.apiToken}`);
47353
+ }
47354
+ if (masked.p12Bundle) {
47355
+ output.push(` P12 Bundle: ${masked.p12Bundle}`);
47356
+ }
47357
+ if (masked.cert) {
47358
+ output.push(` Certificate: ${masked.cert}`);
47359
+ }
47360
+ if (masked.key) {
47361
+ output.push(` Private Key: ${masked.key}`);
47362
+ }
47363
+ if (masked.defaultNamespace) {
47364
+ output.push(` Namespace: ${masked.defaultNamespace}`);
47365
+ }
47366
+ return successResult(output);
47367
+ } catch (error) {
47368
+ return errorResult(
47369
+ `Failed to get active profile: ${error instanceof Error ? error.message : "Unknown error"}`
47370
+ );
47371
+ }
47372
+ }
47373
+ };
47374
+
47818
47375
  // src/domains/login/context/index.ts
47819
47376
  var showCommand2 = {
47820
47377
  name: "show",
47821
- description: "Show current default namespace context",
47378
+ description: "Display the currently active namespace context used for scoping operations. Shows both the namespace value and its source (environment variable, profile default, or session configuration).",
47379
+ descriptionShort: "Show current default namespace",
47380
+ descriptionMedium: "Display active namespace context and its configuration source.",
47822
47381
  usage: "",
47823
47382
  aliases: ["current", "get"],
47824
47383
  async execute(_args, session) {
@@ -47843,7 +47402,9 @@ function determineNamespaceSource(namespace) {
47843
47402
  }
47844
47403
  var setCommand = {
47845
47404
  name: "set",
47846
- description: "Set default namespace context for API operations",
47405
+ description: "Change the default namespace context for all subsequent operations. Updates the session scope so operations target the specified namespace unless explicitly overridden.",
47406
+ descriptionShort: "Set default namespace context",
47407
+ descriptionMedium: "Switch namespace context for scoped operations without specifying namespace each time.",
47847
47408
  usage: "<namespace>",
47848
47409
  aliases: ["use", "switch"],
47849
47410
  async execute(args, session) {
@@ -47868,12 +47429,19 @@ var setCommand = {
47868
47429
  return successResult(lines, true);
47869
47430
  },
47870
47431
  async completion(partial, _args, session) {
47432
+ const cached = session.getNamespaceCache();
47433
+ if (cached.length > 0) {
47434
+ return cached.filter(
47435
+ (ns) => ns.toLowerCase().startsWith(partial.toLowerCase())
47436
+ );
47437
+ }
47871
47438
  const client = session.getAPIClient();
47872
47439
  if (client?.isAuthenticated()) {
47873
47440
  try {
47874
47441
  const response = await client.get("/api/web/namespaces");
47875
47442
  if (response.ok && response.data?.items) {
47876
- const namespaces = response.data.items.map((item) => item.name).filter((name) => !!name);
47443
+ const namespaces = response.data.items.map((item) => item.name).filter((name) => !!name).sort();
47444
+ session.setNamespaceCache(namespaces);
47877
47445
  return namespaces.filter(
47878
47446
  (ns) => ns.toLowerCase().startsWith(partial.toLowerCase())
47879
47447
  );
@@ -47887,7 +47455,9 @@ var setCommand = {
47887
47455
  };
47888
47456
  var listCommand2 = {
47889
47457
  name: "list",
47890
- description: "List available namespaces",
47458
+ description: "Fetch and display all available namespaces from the tenant. Requires authenticated connection. Shows current namespace indicator and provides switch command guidance.",
47459
+ descriptionShort: "List available namespaces",
47460
+ descriptionMedium: "Query tenant for available namespaces with current context indicator.",
47891
47461
  usage: "",
47892
47462
  aliases: ["ls"],
47893
47463
  async execute(_args, session) {
@@ -47909,6 +47479,7 @@ var listCommand2 = {
47909
47479
  return errorResult("Failed to fetch namespaces from API.");
47910
47480
  }
47911
47481
  const namespaces = response.data.items.map((item) => item.name).filter((name) => !!name).sort();
47482
+ session.setNamespaceCache(namespaces);
47912
47483
  const lines = ["Available namespaces:", ""];
47913
47484
  for (const ns of namespaces) {
47914
47485
  if (ns === currentNamespace) {
@@ -47928,7 +47499,9 @@ var listCommand2 = {
47928
47499
  };
47929
47500
  var contextSubcommands = {
47930
47501
  name: "context",
47931
- description: "Manage default namespace context for API operations",
47502
+ description: "Manage default namespace context for scoping operations. Set, display, and list namespaces to control which namespace is used when no explicit namespace is specified in commands.",
47503
+ descriptionShort: "Manage default namespace context",
47504
+ descriptionMedium: "Set, display, and list namespaces for scoping operations without explicit namespace flags.",
47932
47505
  commands: /* @__PURE__ */ new Map([
47933
47506
  ["show", showCommand2],
47934
47507
  ["set", setCommand],
@@ -47960,11 +47533,6 @@ var EnvVarRegistry = [
47960
47533
  description: "Output format (json, yaml, table)",
47961
47534
  relatedFlag: "-o"
47962
47535
  },
47963
- {
47964
- name: `${ENV_PREFIX}_SUBSCRIPTION_TIER`,
47965
- description: "Subscription tier for feature validation",
47966
- relatedFlag: ""
47967
- },
47968
47536
  {
47969
47537
  name: `${ENV_PREFIX}_LOGO`,
47970
47538
  description: "Logo display mode (auto, image, ascii, both, none)",
@@ -48338,7 +47906,9 @@ function parseLogoArg(args) {
48338
47906
  }
48339
47907
  var bannerCommand = {
48340
47908
  name: "banner",
48341
- description: "Display the xcsh banner with optional logo mode",
47909
+ description: "Render the xcsh startup banner with customizable logo display. Supports multiple render modes including image, ASCII, Unicode, and sixel graphics based on terminal capabilities.",
47910
+ descriptionShort: "Display xcsh banner with logo",
47911
+ descriptionMedium: "Show startup banner with configurable logo mode (image, ASCII, sixel) based on terminal.",
48342
47912
  usage: "[--logo <mode>]",
48343
47913
  async execute(args, _session) {
48344
47914
  if (args.includes("--help") || args.includes("-h")) {
@@ -48411,25 +47981,8 @@ var bannerCommand = {
48411
47981
  }
48412
47982
  };
48413
47983
 
48414
- // src/domains/login/whoami/types.ts
48415
- function toDisplayTier(tier) {
48416
- const normalized = tier.toUpperCase();
48417
- switch (normalized) {
48418
- case "STANDARD":
48419
- case "BASIC":
48420
- return "Standard";
48421
- case "ADVANCED":
48422
- case "PREMIUM":
48423
- // Legacy mapping
48424
- case "ENTERPRISE":
48425
- return "Advanced";
48426
- default:
48427
- return void 0;
48428
- }
48429
- }
48430
-
48431
47984
  // src/domains/login/whoami/service.ts
48432
- async function getWhoamiInfo(session, options = {}) {
47985
+ async function getWhoamiInfo(session, _options = {}) {
48433
47986
  const info = {
48434
47987
  serverUrl: session.getServerUrl(),
48435
47988
  namespace: session.getNamespace(),
@@ -48450,32 +48003,6 @@ async function getWhoamiInfo(session, options = {}) {
48450
48003
  info.username = username;
48451
48004
  }
48452
48005
  }
48453
- const apiClient = session.getAPIClient();
48454
- if (apiClient) {
48455
- const subscriptionClient = new SubscriptionClient(apiClient);
48456
- try {
48457
- const tierValue = await subscriptionClient.getTierFromCurrentPlan();
48458
- const displayTier = toDisplayTier(tierValue);
48459
- if (displayTier) {
48460
- info.tier = displayTier;
48461
- }
48462
- } catch {
48463
- }
48464
- if (options.includeQuotas || options.verbose) {
48465
- try {
48466
- const subscriptionInfo = await subscriptionClient.getSubscriptionInfo();
48467
- info.quotas = subscriptionInfo.quotaSummary;
48468
- } catch {
48469
- }
48470
- }
48471
- if (options.includeAddons || options.verbose) {
48472
- try {
48473
- const addons = await subscriptionClient.getAddonServices();
48474
- info.addons = addons.filter(isAddonActive);
48475
- } catch {
48476
- }
48477
- }
48478
- }
48479
48006
  return info;
48480
48007
  }
48481
48008
 
@@ -48487,41 +48014,19 @@ function formatWhoami(info, options = {}) {
48487
48014
  if (options.json) {
48488
48015
  return formatWhoamiJson(info);
48489
48016
  }
48490
- return formatWhoamiBox(info, options);
48017
+ return formatWhoamiBox(info);
48491
48018
  }
48492
48019
  function formatWhoamiJson(info) {
48493
48020
  const output = {};
48494
48021
  if (info.tenant) output.tenant = info.tenant;
48495
48022
  if (info.username) output.username = info.username;
48496
48023
  if (info.email) output.email = info.email;
48497
- if (info.tier) output.tier = info.tier;
48498
48024
  output.namespace = info.namespace;
48499
48025
  output.serverUrl = info.serverUrl;
48500
48026
  output.isAuthenticated = info.isAuthenticated;
48501
- if (info.quotas) {
48502
- output.quotas = {
48503
- totalLimits: info.quotas.totalLimits,
48504
- limitsAtRisk: info.quotas.limitsAtRisk,
48505
- limitsExceeded: info.quotas.limitsExceeded,
48506
- objects: info.quotas.objects?.map((q) => ({
48507
- name: q.name,
48508
- displayName: q.displayName,
48509
- usage: q.usage,
48510
- limit: q.limit,
48511
- percentage: Math.round(q.percentage)
48512
- }))
48513
- };
48514
- }
48515
- if (info.addons && info.addons.length > 0) {
48516
- output.addons = info.addons.map((a) => ({
48517
- name: a.name,
48518
- displayName: a.displayName,
48519
- state: a.state
48520
- }));
48521
- }
48522
48027
  return [JSON.stringify(output, null, 2)];
48523
48028
  }
48524
- function formatWhoamiBox(info, options) {
48029
+ function formatWhoamiBox(info) {
48525
48030
  const lines = [];
48526
48031
  const red = colors.red;
48527
48032
  const reset = colors.reset;
@@ -48531,9 +48036,7 @@ function formatWhoamiBox(info, options) {
48531
48036
  bottomLeft: "\u2570",
48532
48037
  bottomRight: "\u256F",
48533
48038
  horizontal: "\u2500",
48534
- vertical: "\u2502",
48535
- leftT: "\u251C",
48536
- rightT: "\u2524"
48039
+ vertical: "\u2502"
48537
48040
  };
48538
48041
  const contentLines = [];
48539
48042
  if (info.tenant) {
@@ -48544,46 +48047,19 @@ function formatWhoamiBox(info, options) {
48544
48047
  } else if (info.username) {
48545
48048
  contentLines.push({ label: "User", value: info.username });
48546
48049
  }
48547
- if (info.tier) {
48548
- contentLines.push({ label: "Tier", value: info.tier });
48549
- }
48550
48050
  contentLines.push({ label: "Namespace", value: info.namespace });
48551
48051
  contentLines.push({ label: "Server", value: info.serverUrl });
48552
48052
  contentLines.push({
48553
48053
  label: "Auth",
48554
48054
  value: info.isAuthenticated ? "\u2713 Authenticated" : "Not authenticated"
48555
48055
  });
48556
- const quotaLines = [];
48557
- if (info.quotas && info.quotas.objects && (options.includeQuotas || options.verbose)) {
48558
- for (const quota of info.quotas.objects.slice(0, 10)) {
48559
- const pct = Math.round(quota.percentage);
48560
- quotaLines.push(
48561
- `${quota.displayName}: ${quota.usage}/${quota.limit} (${pct}%)`
48562
- );
48563
- }
48564
- if (info.quotas.objects.length > 10) {
48565
- const remaining = info.quotas.objects.length - 10;
48566
- quotaLines.push(`... and ${remaining} more`);
48567
- }
48568
- }
48569
- const addonLines = [];
48570
- if (info.addons && info.addons.length > 0 && (options.includeAddons || options.verbose)) {
48571
- for (const addon of info.addons) {
48572
- addonLines.push(`\u2713 ${addon.displayName}`);
48573
- }
48574
- }
48575
48056
  const maxLabelWidth = Math.max(...contentLines.map((c) => c.label.length));
48576
48057
  const formattedContent = contentLines.map((c) => {
48577
48058
  const paddedLabel = c.label.padEnd(maxLabelWidth);
48578
48059
  return `${paddedLabel}: ${c.value}`;
48579
48060
  });
48580
- const headerTitles = ["Connection Info", "Quota Usage", "Active Addons"];
48581
- const allTextLines = [
48582
- ...formattedContent,
48583
- ...quotaLines,
48584
- ...addonLines,
48585
- ...headerTitles
48586
- ];
48061
+ const headerTitle = "Connection Info";
48062
+ const allTextLines = [...formattedContent, headerTitle];
48587
48063
  const maxContentWidth = Math.max(...allTextLines.map((l) => l.length));
48588
48064
  const innerWidth = maxContentWidth + 2;
48589
48065
  const title = " Connection Info ";
@@ -48599,36 +48075,6 @@ function formatWhoamiBox(info, options) {
48599
48075
  `${red}${BOX.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX.vertical}${reset}`
48600
48076
  );
48601
48077
  }
48602
- if (quotaLines.length > 0) {
48603
- const quotaTitle = " Quota Usage ";
48604
- const quotaRemaining = innerWidth - quotaTitle.length;
48605
- const quotaLeft = 1;
48606
- const quotaRight = Math.max(0, quotaRemaining - quotaLeft);
48607
- lines.push(
48608
- `${red}${BOX.leftT}${BOX.horizontal.repeat(quotaLeft)}${reset}${quotaTitle}${red}${BOX.horizontal.repeat(quotaRight)}${BOX.rightT}${reset}`
48609
- );
48610
- for (const text of quotaLines) {
48611
- const padding = innerWidth - text.length;
48612
- lines.push(
48613
- `${red}${BOX.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX.vertical}${reset}`
48614
- );
48615
- }
48616
- }
48617
- if (addonLines.length > 0) {
48618
- const addonTitle = " Active Addons ";
48619
- const addonRemaining = innerWidth - addonTitle.length;
48620
- const addonLeft = 1;
48621
- const addonRight = Math.max(0, addonRemaining - addonLeft);
48622
- lines.push(
48623
- `${red}${BOX.leftT}${BOX.horizontal.repeat(addonLeft)}${reset}${addonTitle}${red}${BOX.horizontal.repeat(addonRight)}${BOX.rightT}${reset}`
48624
- );
48625
- for (const text of addonLines) {
48626
- const padding = innerWidth - text.length;
48627
- lines.push(
48628
- `${red}${BOX.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX.vertical}${reset}`
48629
- );
48630
- }
48631
- }
48632
48078
  lines.push(
48633
48079
  `${red}${BOX.bottomLeft}${BOX.horizontal.repeat(innerWidth)}${BOX.bottomRight}${reset}`
48634
48080
  );
@@ -48638,7 +48084,9 @@ function formatWhoamiBox(info, options) {
48638
48084
  // src/domains/login/whoami/index.ts
48639
48085
  var whoamiCommand = {
48640
48086
  name: "show",
48641
- description: "Show connection and identity information",
48087
+ description: "Display current connection status and authenticated identity information. Shows active profile, tenant URL, username, tenant details, and session context including namespace targeting.",
48088
+ descriptionShort: "Show connection and identity info",
48089
+ descriptionMedium: "Display active profile, tenant URL, user identity, and current namespace context.",
48642
48090
  async execute(_args, session) {
48643
48091
  try {
48644
48092
  const info = await getWhoamiInfo(session);
@@ -48655,14 +48103,17 @@ var whoamiCommand = {
48655
48103
  // src/domains/login/index.ts
48656
48104
  var profileSubcommands = {
48657
48105
  name: "profile",
48658
- description: "Manage saved connection profiles",
48106
+ description: "Manage saved connection profiles for tenant authentication. Create, list, activate, and delete profiles that store tenant URL, credentials, and default namespace settings for seamless tenant switching.",
48107
+ descriptionShort: "Manage saved connection profiles",
48108
+ descriptionMedium: "Create, list, switch, and delete saved authentication profiles for multi-tenant management.",
48659
48109
  commands: /* @__PURE__ */ new Map([
48660
48110
  ["list", listCommand],
48661
48111
  ["show", showCommand],
48662
48112
  ["create", createCommand2],
48663
48113
  ["use", useCommand],
48664
48114
  ["delete", deleteCommand]
48665
- ])
48115
+ ]),
48116
+ defaultCommand: activeCommand
48666
48117
  };
48667
48118
  var loginDomain = {
48668
48119
  name: "login",
@@ -49022,7 +48473,9 @@ function getClient() {
49022
48473
  }
49023
48474
  var statusCommand = {
49024
48475
  name: "status",
49025
- description: "Get overall F5 Cloud status indicator",
48476
+ description: "Retrieve the current overall health indicator for F5 Distributed Cloud services. Returns status level (operational, degraded, major outage) with description. Use --quiet for script-friendly exit code output.",
48477
+ descriptionShort: "Get overall cloud status indicator",
48478
+ descriptionMedium: "Check overall service health status. Use --quiet for exit code suitable for scripts.",
49026
48479
  usage: "[--quiet]",
49027
48480
  aliases: ["st"],
49028
48481
  async execute(args, session) {
@@ -49071,7 +48524,9 @@ var statusCommand = {
49071
48524
  };
49072
48525
  var summaryCommand = {
49073
48526
  name: "summary",
49074
- description: "Get complete status summary including components and incidents",
48527
+ description: "Display comprehensive status overview combining overall health, component statuses, active incidents, and scheduled maintenance in a single report. Use --brief for condensed statistics output.",
48528
+ descriptionShort: "Get complete status summary",
48529
+ descriptionMedium: "Show combined overview of health, components, incidents, and maintenance windows.",
49075
48530
  usage: "[--brief]",
49076
48531
  aliases: ["sum"],
49077
48532
  async execute(args, session) {
@@ -49098,7 +48553,9 @@ var summaryCommand = {
49098
48553
  };
49099
48554
  var componentsCommand = {
49100
48555
  name: "components",
49101
- description: "List all components and their status",
48556
+ description: "List all service components with their current operational status. Shows each component's health level. Use --degraded-only to filter for components experiencing issues.",
48557
+ descriptionShort: "List all components and status",
48558
+ descriptionMedium: "Display service component health. Use --degraded-only to show only affected components.",
49102
48559
  usage: "[--degraded-only]",
49103
48560
  aliases: ["comp"],
49104
48561
  async execute(args, session) {
@@ -49139,7 +48596,9 @@ var componentsCommand = {
49139
48596
  };
49140
48597
  var incidentsCommand = {
49141
48598
  name: "incidents",
49142
- description: "List active and recent incidents",
48599
+ description: "Track service incidents with their impact levels, status, and latest updates. Shows both active and recently resolved incidents. Use --active-only to filter for ongoing issues requiring attention.",
48600
+ descriptionShort: "List active and recent incidents",
48601
+ descriptionMedium: "Display incidents with impact levels and updates. Use --active-only for ongoing issues.",
49143
48602
  usage: "[--active-only]",
49144
48603
  aliases: ["inc"],
49145
48604
  async execute(args, session) {
@@ -49178,7 +48637,9 @@ var incidentsCommand = {
49178
48637
  };
49179
48638
  var maintenanceCommand = {
49180
48639
  name: "maintenance",
49181
- description: "List scheduled and active maintenance windows",
48640
+ description: "View scheduled and in-progress maintenance windows with their timing and affected services. Plan around downtime windows. Use --upcoming to filter for future maintenance only.",
48641
+ descriptionShort: "List scheduled maintenance windows",
48642
+ descriptionMedium: "Show maintenance schedules and timing. Use --upcoming for future windows only.",
49182
48643
  usage: "[--upcoming]",
49183
48644
  aliases: ["maint"],
49184
48645
  async execute(args, session) {
@@ -49351,717 +48812,297 @@ var cloudstatusDomain = {
49351
48812
  };
49352
48813
  var cloudstatusAliases = ["cs", "status"];
49353
48814
 
49354
- // src/extensions/types.ts
49355
- var RESERVED_API_ACTIONS = /* @__PURE__ */ new Set([
49356
- "list",
49357
- "get",
49358
- "create",
49359
- "delete",
49360
- "replace",
49361
- "apply",
49362
- "status",
49363
- "patch",
49364
- "add-labels",
49365
- "remove-labels"
49366
- ]);
49367
- function isReservedAction(name) {
49368
- return RESERVED_API_ACTIONS.has(name.toLowerCase());
49369
- }
49370
- function validateExtension(extension) {
49371
- const conflicts = [];
49372
- for (const [name] of extension.commands) {
49373
- if (isReservedAction(name)) {
49374
- conflicts.push(name);
48815
+ // src/completion/registry.ts
48816
+ var CompletionRegistry = class {
48817
+ tree = /* @__PURE__ */ new Map();
48818
+ aliases = /* @__PURE__ */ new Map();
48819
+ /**
48820
+ * Register a domain with its completion subtree
48821
+ * Later registrations for same name take precedence (custom > api)
48822
+ */
48823
+ registerDomain(node) {
48824
+ this.tree.set(node.name, node);
48825
+ if (node.aliases) {
48826
+ for (const alias of node.aliases) {
48827
+ this.aliases.set(alias, node.name);
48828
+ }
49375
48829
  }
49376
48830
  }
49377
- if (conflicts.length > 0) {
49378
- throw new Error(
49379
- `Extension "${extension.targetDomain}" has commands that conflict with API actions: ${conflicts.join(", ")}. Use unique names or submit a feature request to upstream.`
49380
- );
49381
- }
49382
- }
49383
-
49384
- // src/extensions/registry.ts
49385
- var ExtensionRegistry = class {
49386
- extensions = /* @__PURE__ */ new Map();
49387
- mergedCache = /* @__PURE__ */ new Map();
49388
48831
  /**
49389
- * Register a domain extension
49390
- *
49391
- * @param extension - Extension definition to register
49392
- * @throws Error if extension has command name conflicts with API actions
48832
+ * Add or merge children into an existing domain
48833
+ * Used for extensions that augment API domains
49393
48834
  */
49394
- register(extension) {
49395
- validateExtension(extension);
49396
- this.extensions.set(extension.targetDomain, extension);
49397
- this.mergedCache.delete(extension.targetDomain);
48835
+ mergeChildren(domainName, children) {
48836
+ const existing = this.tree.get(domainName);
48837
+ if (!existing) {
48838
+ return;
48839
+ }
48840
+ if (!existing.children) {
48841
+ existing.children = /* @__PURE__ */ new Map();
48842
+ }
48843
+ for (const [name, node] of children) {
48844
+ existing.children.set(name, node);
48845
+ }
49398
48846
  }
49399
48847
  /**
49400
- * Get extension for a domain
49401
- *
49402
- * @param domain - Canonical domain name
49403
- * @returns Extension if registered, undefined otherwise
48848
+ * Get the complete completion tree
49404
48849
  */
49405
- getExtension(domain) {
49406
- return this.extensions.get(domain);
48850
+ getTree() {
48851
+ return this.tree;
49407
48852
  }
49408
48853
  /**
49409
- * Check if a domain has an extension
48854
+ * Get all registered domains as array (sorted by name)
49410
48855
  */
49411
- hasExtension(domain) {
49412
- return this.extensions.has(domain);
48856
+ getDomains() {
48857
+ return Array.from(this.tree.values()).sort(
48858
+ (a, b) => a.name.localeCompare(b.name)
48859
+ );
49413
48860
  }
49414
48861
  /**
49415
- * Get merged domain view combining API domain + extension
49416
- *
49417
- * Resolution priority:
49418
- * 1. Check if canonical domain exists in generated domains
49419
- * 2. Check if extension exists for this domain
49420
- * 3. Merge if both exist, or return standalone if only one
49421
- *
49422
- * @param domain - Canonical domain name or alias
49423
- * @returns Merged domain view or undefined if neither exists
48862
+ * Resolve alias to canonical name
49424
48863
  */
49425
- getMergedDomain(domain) {
49426
- const canonical = aliasRegistry.get(domain) ?? domain;
49427
- const cached = this.mergedCache.get(canonical);
49428
- if (cached) {
49429
- return cached;
49430
- }
49431
- const domainInfo = domainRegistry.get(canonical);
49432
- const extension = this.extensions.get(canonical);
49433
- if (!domainInfo && !extension) {
49434
- return void 0;
49435
- }
49436
- const merged = this.buildMergedDomain(canonical, domainInfo, extension);
49437
- this.mergedCache.set(canonical, merged);
49438
- return merged;
48864
+ resolveAlias(nameOrAlias) {
48865
+ return this.aliases.get(nameOrAlias) ?? nameOrAlias;
49439
48866
  }
49440
48867
  /**
49441
- * Build a merged domain from API domain info and/or extension
48868
+ * Get a domain by name or alias
49442
48869
  */
49443
- buildMergedDomain(name, domainInfo, extension) {
49444
- const hasGeneratedDomain = !!domainInfo;
49445
- const hasExtension = !!extension;
49446
- let source;
49447
- if (hasGeneratedDomain && hasExtension) {
49448
- source = "merged";
49449
- } else if (hasGeneratedDomain) {
49450
- source = "generated";
49451
- } else {
49452
- source = "extension";
49453
- }
49454
- const displayName = domainInfo?.displayName ?? this.toDisplayName(extension?.targetDomain ?? name);
49455
- const description = domainInfo?.description ?? extension?.description ?? `Commands for ${displayName}`;
49456
- const merged = {
49457
- name,
49458
- displayName,
49459
- description,
49460
- source,
49461
- hasGeneratedDomain,
49462
- hasExtension,
49463
- extensionCommands: extension?.commands ?? /* @__PURE__ */ new Map(),
49464
- extensionSubcommands: extension?.subcommands ?? /* @__PURE__ */ new Map()
49465
- };
49466
- if (domainInfo) {
49467
- merged.metadata = domainInfo;
49468
- }
49469
- return merged;
48870
+ get(nameOrAlias) {
48871
+ const canonical = this.resolveAlias(nameOrAlias);
48872
+ return this.tree.get(canonical);
49470
48873
  }
49471
48874
  /**
49472
- * Convert snake_case domain name to display name
48875
+ * Check if a domain exists (by name or alias)
49473
48876
  */
49474
- toDisplayName(name) {
49475
- return name.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
48877
+ has(nameOrAlias) {
48878
+ const canonical = this.resolveAlias(nameOrAlias);
48879
+ return this.tree.has(canonical);
49476
48880
  }
49477
48881
  /**
49478
- * Get all domains with extensions (for iteration)
48882
+ * Get all aliases
49479
48883
  */
49480
- getExtendedDomains() {
49481
- return Array.from(this.extensions.keys());
48884
+ getAliases() {
48885
+ return new Map(this.aliases);
49482
48886
  }
49483
48887
  /**
49484
- * Get all merged domains (generated + extended)
49485
- *
49486
- * Returns domains that either:
49487
- * - Have generated API commands (from upstream)
49488
- * - Have extension commands (xcsh-specific)
49489
- * - Have both (merged)
48888
+ * Get domain suggestions for completion
49490
48889
  */
49491
- getAllMergedDomains() {
49492
- const domains = /* @__PURE__ */ new Set();
49493
- for (const name of domainRegistry.keys()) {
49494
- domains.add(name);
48890
+ getDomainSuggestions(prefix = "") {
48891
+ const suggestions = [];
48892
+ const lowerPrefix = prefix.toLowerCase();
48893
+ for (const node of this.tree.values()) {
48894
+ if (node.hidden) continue;
48895
+ if (!prefix || node.name.toLowerCase().startsWith(lowerPrefix)) {
48896
+ suggestions.push({
48897
+ text: node.name,
48898
+ description: node.description,
48899
+ category: "domain"
48900
+ });
48901
+ }
48902
+ if (node.aliases) {
48903
+ for (const alias of node.aliases) {
48904
+ if (!prefix || alias.toLowerCase().startsWith(lowerPrefix)) {
48905
+ suggestions.push({
48906
+ text: alias,
48907
+ description: `Alias for ${node.name}`,
48908
+ category: "domain"
48909
+ });
48910
+ }
48911
+ }
48912
+ }
49495
48913
  }
49496
- for (const name of this.extensions.keys()) {
49497
- domains.add(name);
49498
- }
49499
- const merged = [];
49500
- for (const name of domains) {
49501
- const domain = this.getMergedDomain(name);
49502
- if (domain) {
49503
- merged.push(domain);
49504
- }
49505
- }
49506
- return merged.sort((a, b) => a.name.localeCompare(b.name));
48914
+ return suggestions.sort((a, b) => a.text.localeCompare(b.text));
49507
48915
  }
49508
48916
  /**
49509
- * Get extension command by name
49510
- *
49511
- * @param domain - Canonical domain name
49512
- * @param command - Command name
49513
- * @returns Command definition if found
48917
+ * Get child suggestions for a domain
49514
48918
  */
49515
- getExtensionCommand(domain, command) {
49516
- const extension = this.getExtension(domain);
49517
- if (!extension) {
49518
- return void 0;
49519
- }
49520
- const cmd = extension.commands.get(command);
49521
- if (cmd) {
49522
- return cmd;
48919
+ getChildSuggestions(domainName, prefix = "") {
48920
+ const node = this.get(domainName);
48921
+ if (!node?.children) {
48922
+ return [];
49523
48923
  }
49524
- for (const [, cmdDef] of extension.commands) {
49525
- if (cmdDef.aliases?.includes(command)) {
49526
- return cmdDef;
48924
+ const suggestions = [];
48925
+ const lowerPrefix = prefix.toLowerCase();
48926
+ for (const child of node.children.values()) {
48927
+ if (child.hidden) continue;
48928
+ if (!prefix || child.name.toLowerCase().startsWith(lowerPrefix)) {
48929
+ suggestions.push({
48930
+ text: child.name,
48931
+ description: child.description,
48932
+ category: child.children ? "subcommand" : "action"
48933
+ });
49527
48934
  }
49528
48935
  }
49529
- return void 0;
49530
- }
49531
- /**
49532
- * Get extension subcommand group
49533
- *
49534
- * @param domain - Canonical domain name
49535
- * @param subcommand - Subcommand group name
49536
- * @returns Subcommand group if found
49537
- */
49538
- getExtensionSubcommand(domain, subcommand) {
49539
- const extension = this.getExtension(domain);
49540
- return extension?.subcommands?.get(subcommand);
49541
- }
49542
- /**
49543
- * Check if a command exists in extension
49544
- */
49545
- hasExtensionCommand(domain, command) {
49546
- return this.getExtensionCommand(domain, command) !== void 0;
48936
+ return suggestions.sort((a, b) => a.text.localeCompare(b.text));
49547
48937
  }
49548
48938
  /**
49549
- * Get all extension command names for a domain
49550
- * Used for tab completion
48939
+ * Get nested child suggestions (e.g., login profile <TAB>)
49551
48940
  */
49552
- getExtensionCommandNames(domain) {
49553
- const extension = this.getExtension(domain);
49554
- if (!extension) {
48941
+ getNestedChildSuggestions(domainName, path, prefix = "") {
48942
+ let node = this.get(domainName);
48943
+ if (!node) {
49555
48944
  return [];
49556
48945
  }
49557
- const names = [];
49558
- for (const [name, cmd] of extension.commands) {
49559
- names.push(name);
49560
- if (cmd.aliases) {
49561
- names.push(...cmd.aliases);
48946
+ for (const segment of path) {
48947
+ if (!node.children) {
48948
+ return [];
48949
+ }
48950
+ const child = node.children.get(segment);
48951
+ if (!child) {
48952
+ return [];
49562
48953
  }
48954
+ node = child;
49563
48955
  }
49564
- return names;
49565
- }
49566
- /**
49567
- * Clear the merged domain cache
49568
- * Call this if generated domains change
49569
- */
49570
- clearCache() {
49571
- this.mergedCache.clear();
48956
+ if (!node.children) {
48957
+ return [];
48958
+ }
48959
+ const suggestions = [];
48960
+ const lowerPrefix = prefix.toLowerCase();
48961
+ for (const child of node.children.values()) {
48962
+ if (child.hidden) continue;
48963
+ if (!prefix || child.name.toLowerCase().startsWith(lowerPrefix)) {
48964
+ suggestions.push({
48965
+ text: child.name,
48966
+ description: child.description,
48967
+ category: "command"
48968
+ });
48969
+ }
48970
+ }
48971
+ return suggestions.sort((a, b) => a.text.localeCompare(b.text));
49572
48972
  }
49573
48973
  /**
49574
- * Get registry statistics
48974
+ * Clear the registry (useful for testing)
49575
48975
  */
49576
- getStats() {
49577
- let standaloneCount = 0;
49578
- let mergedCount = 0;
49579
- for (const [domain] of this.extensions) {
49580
- if (domainRegistry.has(domain)) {
49581
- mergedCount++;
49582
- } else {
49583
- standaloneCount++;
49584
- }
49585
- }
49586
- return {
49587
- extensionCount: this.extensions.size,
49588
- standaloneCount,
49589
- mergedCount
49590
- };
48976
+ clear() {
48977
+ this.tree.clear();
48978
+ this.aliases.clear();
49591
48979
  }
49592
48980
  };
49593
- var extensionRegistry = new ExtensionRegistry();
49594
-
49595
- // src/extensions/subscription/index.ts
49596
- var clientCache = /* @__PURE__ */ new Map();
49597
- function getClient2(apiClient) {
49598
- const key = apiClient.getServerUrl();
49599
- let client = clientCache.get(key);
49600
- if (!client) {
49601
- client = new SubscriptionClient(apiClient);
49602
- clientCache.set(key, client);
48981
+ var completionRegistry = new CompletionRegistry();
48982
+
48983
+ // src/completion/adapters.ts
48984
+ var actionDescriptions = {
48985
+ list: "List resources",
48986
+ get: "Get a specific resource",
48987
+ create: "Create a new resource",
48988
+ delete: "Delete a resource",
48989
+ replace: "Replace a resource",
48990
+ apply: "Apply configuration from file",
48991
+ status: "Get resource status",
48992
+ patch: "Patch a resource",
48993
+ "add-labels": "Add labels to a resource",
48994
+ "remove-labels": "Remove labels from a resource"
48995
+ };
48996
+ function fromCommand(cmd) {
48997
+ const node = {
48998
+ name: cmd.name,
48999
+ description: cmd.descriptionShort,
49000
+ source: "custom"
49001
+ };
49002
+ if (cmd.aliases && cmd.aliases.length > 0) {
49003
+ node.aliases = cmd.aliases;
49603
49004
  }
49604
- return client;
49005
+ return node;
49605
49006
  }
49606
- var overviewCommand = {
49607
- name: "overview",
49608
- description: "Display subscription tier, active addons, and quota summary",
49609
- usage: "[--json]",
49610
- aliases: ["show", "info"],
49611
- async execute(args, session) {
49612
- const jsonOutput = args.includes("--json");
49613
- const format = session.getOutputFormat();
49614
- const apiClient = session.getAPIClient();
49615
- if (!apiClient) {
49616
- return errorResult("Not authenticated. Use 'login' command first.");
49617
- }
49618
- try {
49619
- const client = getClient2(apiClient);
49620
- const info = await client.getSubscriptionInfo();
49621
- if (jsonOutput || format === "json") {
49622
- return successResult([JSON.stringify(info, null, 2)]);
49623
- }
49624
- const lines = [];
49625
- lines.push("=== Subscription Overview ===");
49626
- lines.push("");
49627
- lines.push(`Tier: ${info.tier}`);
49628
- if (info.plan) {
49629
- lines.push(`Plan: ${info.plan.displayName}`);
49630
- if (info.plan.description) {
49631
- lines.push(`Description: ${info.plan.description}`);
49632
- }
49633
- }
49634
- lines.push("");
49635
- lines.push("--- Active Addons ---");
49636
- if (info.activeAddons.length === 0) {
49637
- lines.push(" No active addons");
49638
- } else {
49639
- for (const addon of info.activeAddons) {
49640
- lines.push(
49641
- ` - ${addon.displayName} (${getTierDescription(addon.tier)})`
49642
- );
49643
- }
49644
- }
49645
- lines.push("");
49646
- lines.push("--- Quota Summary ---");
49647
- lines.push(` Total Limits: ${info.quotaSummary.totalLimits}`);
49648
- lines.push(` At Risk (>80%): ${info.quotaSummary.limitsAtRisk}`);
49649
- lines.push(` Exceeded: ${info.quotaSummary.limitsExceeded}`);
49650
- if (info.quotaSummary.limitsExceeded > 0) {
49651
- lines.push("");
49652
- lines.push(" Warning: Some quotas are exceeded!");
49653
- }
49654
- return successResult(lines);
49655
- } catch (err) {
49656
- const message = err instanceof Error ? err.message : String(err);
49657
- return errorResult(`Failed to get subscription info: ${message}`);
49658
- }
49007
+ function fromSubcommandGroup(group) {
49008
+ const children = /* @__PURE__ */ new Map();
49009
+ for (const [name, cmd] of group.commands) {
49010
+ children.set(name, fromCommand(cmd));
49659
49011
  }
49660
- };
49661
- var addonsCommand = {
49662
- name: "addons",
49663
- description: "List addon services and their subscription status",
49664
- usage: "[--filter active|available|denied] [--all] [--json]",
49665
- aliases: ["services"],
49666
- async execute(args, session) {
49667
- const jsonOutput = args.includes("--json");
49668
- const showAll = args.includes("--all");
49669
- const format = session.getOutputFormat();
49670
- let filter = "";
49671
- const filterIdx = args.indexOf("--filter");
49672
- if (filterIdx !== -1) {
49673
- const filterArg = args[filterIdx + 1];
49674
- if (filterArg) {
49675
- filter = filterArg;
49676
- }
49677
- }
49678
- const apiClient = session.getAPIClient();
49679
- if (!apiClient) {
49680
- return errorResult("Not authenticated. Use 'login' command first.");
49681
- }
49682
- try {
49683
- const client = getClient2(apiClient);
49684
- let addons = await client.getAddonServices("system");
49685
- if (filter) {
49686
- addons = client.filterAddons(addons, filter);
49687
- } else if (!showAll) {
49688
- addons = addons.filter(
49689
- (a) => isAddonActive(a) || isAddonAvailable(a)
49690
- );
49691
- }
49692
- if (jsonOutput || format === "json") {
49693
- return successResult([JSON.stringify(addons, null, 2)]);
49694
- }
49695
- if (addons.length === 0) {
49696
- return successResult([
49697
- `No addon services found${filter ? ` (filter: ${filter})` : ""}`
49698
- ]);
49699
- }
49700
- const lines = [];
49701
- lines.push("=== Addon Services ===");
49702
- lines.push("");
49703
- const active = addons.filter(isAddonActive);
49704
- const available = addons.filter(isAddonAvailable);
49705
- const denied = addons.filter(isAddonDenied);
49706
- const other = addons.filter(
49707
- (a) => !isAddonActive(a) && !isAddonAvailable(a) && !isAddonDenied(a)
49708
- );
49709
- if (active.length > 0) {
49710
- lines.push("--- Active ---");
49711
- for (const addon of active) {
49712
- lines.push(` [OK] ${addon.displayName}`);
49713
- lines.push(
49714
- ` Tier: ${getTierDescription(addon.tier)}`
49715
- );
49716
- }
49717
- lines.push("");
49718
- }
49719
- if (available.length > 0) {
49720
- lines.push("--- Available ---");
49721
- for (const addon of available) {
49722
- lines.push(` [ ] ${addon.displayName}`);
49723
- lines.push(
49724
- ` Status: ${getStateDescription(addon.state)}`
49725
- );
49726
- }
49727
- lines.push("");
49728
- }
49729
- if (denied.length > 0 && (showAll || filter === "denied")) {
49730
- lines.push("--- Access Denied ---");
49731
- for (const addon of denied) {
49732
- lines.push(` [X] ${addon.displayName}`);
49733
- lines.push(
49734
- ` Reason: ${getAccessStatusDescription(addon.accessStatus)}`
49735
- );
49736
- }
49737
- lines.push("");
49738
- }
49739
- if (other.length > 0 && showAll) {
49740
- lines.push("--- Other ---");
49741
- for (const addon of other) {
49742
- lines.push(` [-] ${addon.displayName}`);
49743
- lines.push(
49744
- ` State: ${getStateDescription(addon.state)}`
49745
- );
49746
- lines.push(
49747
- ` Access: ${getAccessStatusDescription(addon.accessStatus)}`
49748
- );
49749
- }
49750
- }
49751
- return successResult(lines);
49752
- } catch (err) {
49753
- const message = err instanceof Error ? err.message : String(err);
49754
- return errorResult(`Failed to get addon services: ${message}`);
49012
+ const node = {
49013
+ name: group.name,
49014
+ description: group.descriptionShort,
49015
+ source: "custom"
49016
+ };
49017
+ if (children.size > 0) {
49018
+ node.children = children;
49019
+ }
49020
+ return node;
49021
+ }
49022
+ function fromCustomDomain(domain) {
49023
+ const children = /* @__PURE__ */ new Map();
49024
+ for (const [name, cmd] of domain.commands) {
49025
+ children.set(name, fromCommand(cmd));
49026
+ }
49027
+ for (const [name, group] of domain.subcommands) {
49028
+ children.set(name, fromSubcommandGroup(group));
49029
+ }
49030
+ const node = {
49031
+ name: domain.name,
49032
+ description: domain.descriptionShort,
49033
+ source: "custom"
49034
+ };
49035
+ if (children.size > 0) {
49036
+ node.children = children;
49037
+ }
49038
+ return node;
49039
+ }
49040
+ function fromApiDomain(info) {
49041
+ const children = /* @__PURE__ */ new Map();
49042
+ for (const action of validActions) {
49043
+ children.set(action, {
49044
+ name: action,
49045
+ description: actionDescriptions[action] ?? action,
49046
+ source: "api"
49047
+ });
49048
+ }
49049
+ const node = {
49050
+ name: info.name,
49051
+ description: info.descriptionShort,
49052
+ children,
49053
+ source: "api"
49054
+ };
49055
+ if (info.aliases.length > 0) {
49056
+ node.aliases = info.aliases;
49057
+ }
49058
+ return node;
49059
+ }
49060
+ function getActionDescriptions() {
49061
+ return { ...actionDescriptions };
49062
+ }
49063
+
49064
+ // src/completion/generators/common.ts
49065
+ function escapeForZsh(str) {
49066
+ return str.replace(/'/g, "'\\''").replace(/:/g, "\\:");
49067
+ }
49068
+ function escapeForFish(str) {
49069
+ return str.replace(/'/g, "\\'");
49070
+ }
49071
+
49072
+ // src/domains/completion/generators.ts
49073
+ function generateBashCompletion() {
49074
+ const domains = completionRegistry.getDomains();
49075
+ const domainNames = domains.map((d) => d.name).join(" ");
49076
+ const allAliases = [];
49077
+ for (const domain of domains) {
49078
+ if (domain.aliases) {
49079
+ allAliases.push(...domain.aliases);
49755
49080
  }
49756
49081
  }
49757
- };
49758
- var quotaCommand = {
49759
- name: "quota",
49760
- description: "Display tenant-level quota limits and usage",
49761
- usage: "[--warnings] [--json]",
49762
- aliases: ["quotas", "limits"],
49763
- async execute(args, session) {
49764
- const jsonOutput = args.includes("--json");
49765
- const showWarnings = args.includes("--warnings");
49766
- const format = session.getOutputFormat();
49767
- const apiClient = session.getAPIClient();
49768
- if (!apiClient) {
49769
- return errorResult("Not authenticated. Use 'login' command first.");
49082
+ const actionDescriptions2 = getActionDescriptions();
49083
+ const actions = Object.keys(actionDescriptions2).join(" ");
49084
+ const customDomainCompletions = [];
49085
+ for (const domain of domains) {
49086
+ if (domain.source !== "custom" || !domain.children) continue;
49087
+ const childNames = Array.from(domain.children.keys());
49088
+ if (childNames.length > 0) {
49089
+ customDomainCompletions.push(
49090
+ ` ${domain.name})`,
49091
+ ` COMPREPLY=($(compgen -W "${childNames.join(" ")}" -- "\${cur}"))`,
49092
+ ` return 0`,
49093
+ ` ;;`
49094
+ );
49770
49095
  }
49771
- try {
49772
- const client = getClient2(apiClient);
49773
- const quotaInfo = await client.getQuotaInfo();
49774
- let objects = quotaInfo.objects;
49775
- if (showWarnings) {
49776
- objects = objects.filter(
49777
- (q) => q.status === QuotaStatus.Warning || q.status === QuotaStatus.Exceeded
49096
+ for (const [childName, child] of domain.children) {
49097
+ if (child.children && child.children.size > 0) {
49098
+ const nestedNames = Array.from(child.children.keys());
49099
+ customDomainCompletions.push(
49100
+ ` ${domain.name}/${childName})`,
49101
+ ` COMPREPLY=($(compgen -W "${nestedNames.join(" ")}" -- "\${cur}"))`,
49102
+ ` return 0`,
49103
+ ` ;;`
49778
49104
  );
49779
49105
  }
49780
- if (jsonOutput || format === "json") {
49781
- return successResult([
49782
- JSON.stringify({ ...quotaInfo, objects }, null, 2)
49783
- ]);
49784
- }
49785
- if (objects.length === 0) {
49786
- return successResult([
49787
- showWarnings ? "No quota warnings or exceeded limits" : "No quota information available"
49788
- ]);
49789
- }
49790
- const lines = [];
49791
- lines.push("=== Quota Usage (Tenant-Level) ===");
49792
- lines.push("");
49793
- const exceeded = objects.filter(
49794
- (q) => q.status === QuotaStatus.Exceeded
49795
- );
49796
- const warning = objects.filter(
49797
- (q) => q.status === QuotaStatus.Warning
49798
- );
49799
- const ok = objects.filter((q) => q.status === QuotaStatus.OK);
49800
- if (exceeded.length > 0) {
49801
- lines.push("--- Exceeded ---");
49802
- for (const q of exceeded) {
49803
- lines.push(` [!!] ${q.displayName}`);
49804
- lines.push(
49805
- ` Usage: ${q.usage} / ${q.limit} (${Math.round(q.percentage)}%)`
49806
- );
49807
- }
49808
- lines.push("");
49809
- }
49810
- if (warning.length > 0) {
49811
- lines.push("--- Warning (>80%) ---");
49812
- for (const q of warning) {
49813
- lines.push(` [!] ${q.displayName}`);
49814
- lines.push(
49815
- ` Usage: ${q.usage} / ${q.limit} (${Math.round(q.percentage)}%)`
49816
- );
49817
- }
49818
- lines.push("");
49819
- }
49820
- if (ok.length > 0 && !showWarnings) {
49821
- lines.push("--- OK ---");
49822
- for (const q of ok) {
49823
- lines.push(
49824
- ` [OK] ${q.displayName}: ${q.usage} / ${q.limit} (${Math.round(q.percentage)}%)`
49825
- );
49826
- }
49827
- }
49828
- return successResult(lines);
49829
- } catch (err) {
49830
- const message = err instanceof Error ? err.message : String(err);
49831
- return errorResult(`Failed to get quota info: ${message}`);
49832
- }
49833
- }
49834
- };
49835
- var validateCommand = {
49836
- name: "validate",
49837
- description: "Pre-deployment validation for quotas and features",
49838
- usage: "[--resource-type <type> --count <n>] [--feature <name>] [--json]",
49839
- async execute(args, session) {
49840
- const jsonOutput = args.includes("--json");
49841
- const format = session.getOutputFormat();
49842
- let resourceType;
49843
- const resourceIdx = args.indexOf("--resource-type");
49844
- if (resourceIdx !== -1 && args[resourceIdx + 1]) {
49845
- resourceType = args[resourceIdx + 1];
49846
- }
49847
- let count;
49848
- const countIdx = args.indexOf("--count");
49849
- if (countIdx !== -1) {
49850
- const countArg = args[countIdx + 1];
49851
- if (countArg) {
49852
- count = parseInt(countArg, 10);
49853
- }
49854
- }
49855
- let feature;
49856
- const featureIdx = args.indexOf("--feature");
49857
- if (featureIdx !== -1 && args[featureIdx + 1]) {
49858
- feature = args[featureIdx + 1];
49859
- }
49860
- if (!resourceType && !feature) {
49861
- return errorResult(
49862
- "Please specify --resource-type and --count, or --feature to validate"
49863
- );
49864
- }
49865
- const apiClient = session.getAPIClient();
49866
- if (!apiClient) {
49867
- return errorResult("Not authenticated. Use 'login' command first.");
49868
- }
49869
- try {
49870
- const client = getClient2(apiClient);
49871
- const result = await client.validateResource({
49872
- resourceType: resourceType ?? "",
49873
- count: count ?? 0,
49874
- feature: feature ?? ""
49875
- });
49876
- if (jsonOutput || format === "json") {
49877
- return successResult([JSON.stringify(result, null, 2)]);
49878
- }
49879
- const lines = [];
49880
- lines.push("=== Validation Result ===");
49881
- lines.push("");
49882
- lines.push(`Status: ${result.valid ? "[PASS]" : "[FAIL]"}`);
49883
- lines.push("");
49884
- if (result.checks.length > 0) {
49885
- lines.push("--- Checks ---");
49886
- for (const check of result.checks) {
49887
- const icon = check.result === "PASS" ? "[OK]" : check.result === "WARNING" ? "[!]" : "[X]";
49888
- lines.push(
49889
- ` ${icon} [${check.type}] ${check.message ?? ""}`
49890
- );
49891
- }
49892
- }
49893
- if (result.errors && result.errors.length > 0) {
49894
- lines.push("");
49895
- lines.push("--- Errors ---");
49896
- for (const error of result.errors) {
49897
- lines.push(` [X] ${error}`);
49898
- }
49899
- }
49900
- if (result.warnings && result.warnings.length > 0) {
49901
- lines.push("");
49902
- lines.push("--- Warnings ---");
49903
- for (const warning of result.warnings) {
49904
- lines.push(` [!] ${warning}`);
49905
- }
49906
- }
49907
- const commandResult = {
49908
- output: lines,
49909
- shouldExit: false,
49910
- shouldClear: false,
49911
- contextChanged: false
49912
- };
49913
- if (!result.valid) {
49914
- commandResult.error = "Validation failed";
49915
- }
49916
- return commandResult;
49917
- } catch (err) {
49918
- const message = err instanceof Error ? err.message : String(err);
49919
- return errorResult(`Validation failed: ${message}`);
49920
- }
49921
- }
49922
- };
49923
- var activationStatusCommand = {
49924
- name: "activation-status",
49925
- description: "Check pending addon activation requests",
49926
- usage: "[--json]",
49927
- async execute(args, session) {
49928
- const jsonOutput = args.includes("--json");
49929
- const format = session.getOutputFormat();
49930
- const apiClient = session.getAPIClient();
49931
- if (!apiClient) {
49932
- return errorResult("Not authenticated. Use 'login' command first.");
49933
- }
49934
- try {
49935
- const client = getClient2(apiClient);
49936
- const result = await client.getPendingActivations("system");
49937
- if (jsonOutput || format === "json") {
49938
- return successResult([JSON.stringify(result, null, 2)]);
49939
- }
49940
- const lines = [];
49941
- lines.push("=== Activation Status ===");
49942
- lines.push("");
49943
- if (result.pendingActivations.length === 0) {
49944
- lines.push("No pending activation requests.");
49945
- } else {
49946
- lines.push(`Pending Activations: ${result.totalPending}`);
49947
- lines.push("");
49948
- for (const pending of result.pendingActivations) {
49949
- lines.push(` [...] ${pending.addonService}`);
49950
- if (pending.message) {
49951
- lines.push(` Status: ${pending.message}`);
49952
- }
49953
- }
49954
- }
49955
- lines.push("");
49956
- lines.push(`Active Addons: ${result.activeAddons.length}`);
49957
- if (result.activeAddons.length > 0) {
49958
- for (const addon of result.activeAddons) {
49959
- lines.push(` [OK] ${addon}`);
49960
- }
49961
- }
49962
- return successResult(lines);
49963
- } catch (err) {
49964
- const message = err instanceof Error ? err.message : String(err);
49965
- return errorResult(`Failed to get activation status: ${message}`);
49966
- }
49967
- }
49968
- };
49969
- var subscriptionExtension = {
49970
- targetDomain: "subscription",
49971
- description: "xcsh-specific subscription management commands (overview, quota analysis, validation)",
49972
- standalone: true,
49973
- // Works even before upstream adds subscription domain
49974
- commands: /* @__PURE__ */ new Map([
49975
- ["overview", overviewCommand],
49976
- ["addons", addonsCommand],
49977
- ["quota", quotaCommand],
49978
- ["validate", validateCommand],
49979
- ["activation-status", activationStatusCommand]
49980
- ]),
49981
- subcommands: /* @__PURE__ */ new Map()
49982
- };
49983
-
49984
- // src/extensions/index.ts
49985
- function initializeExtensions() {
49986
- extensionRegistry.register(subscriptionExtension);
49987
- }
49988
- initializeExtensions();
49989
-
49990
- // src/domains/completion/generators.ts
49991
- function getAllDomains() {
49992
- const domains = [];
49993
- const seen = /* @__PURE__ */ new Set();
49994
- for (const domain of customDomains.all()) {
49995
- domains.push({
49996
- name: domain.name,
49997
- description: domain.descriptionShort,
49998
- aliases: []
49999
- });
50000
- seen.add(domain.name);
50001
- }
50002
- for (const extDomain of extensionRegistry.getExtendedDomains()) {
50003
- if (seen.has(extDomain)) continue;
50004
- if (domainRegistry.has(extDomain)) continue;
50005
- const merged = extensionRegistry.getMergedDomain(extDomain);
50006
- if (merged && merged.source === "extension") {
50007
- domains.push({
50008
- name: extDomain,
50009
- description: merged.description,
50010
- aliases: []
50011
- });
50012
- seen.add(extDomain);
50013
- }
50014
- }
50015
- for (const [name, info] of domainRegistry) {
50016
- if (seen.has(name)) continue;
50017
- domains.push({
50018
- name,
50019
- description: info.descriptionShort,
50020
- aliases: info.aliases
50021
- });
50022
- seen.add(name);
50023
- }
50024
- return domains.sort((a, b) => a.name.localeCompare(b.name));
50025
- }
50026
- function getCustomDomainCommands(domainName) {
50027
- const domain = customDomains.get(domainName);
50028
- if (!domain) {
50029
- return { commands: [], subcommands: /* @__PURE__ */ new Map() };
50030
- }
50031
- const commands = Array.from(domain.commands.keys());
50032
- const subcommands = /* @__PURE__ */ new Map();
50033
- for (const [groupName, group] of domain.subcommands) {
50034
- subcommands.set(groupName, Array.from(group.commands.keys()));
50035
- }
50036
- return { commands, subcommands };
50037
- }
50038
- function generateBashCompletion() {
50039
- const domains = getAllDomains();
50040
- const domainNames = domains.map((d) => d.name).join(" ");
50041
- const allAliases = domains.flatMap((d) => d.aliases).join(" ");
50042
- const actions = Array.from(validActions).join(" ");
50043
- const customDomainCompletions = [];
50044
- for (const domain of customDomains.all()) {
50045
- const { commands, subcommands } = getCustomDomainCommands(domain.name);
50046
- if (commands.length > 0 || subcommands.size > 0) {
50047
- const allCommands = [
50048
- ...commands,
50049
- ...Array.from(subcommands.keys())
50050
- ];
50051
- customDomainCompletions.push(
50052
- ` ${domain.name})`,
50053
- ` COMPREPLY=($(compgen -W "${allCommands.join(" ")}" -- "\${cur}"))`,
50054
- ` return 0`,
50055
- ` ;;`
50056
- );
50057
- }
50058
- for (const [groupName, groupCommands] of subcommands) {
50059
- customDomainCompletions.push(
50060
- ` ${domain.name}/${groupName})`,
50061
- ` COMPREPLY=($(compgen -W "${groupCommands.join(" ")}" -- "\${cur}"))`,
50062
- ` return 0`,
50063
- ` ;;`
50064
- );
50065
49106
  }
50066
49107
  }
50067
49108
  return `# bash completion for xcsh
@@ -50072,7 +49113,7 @@ _xcsh_completions() {
50072
49113
  local cur prev words cword
50073
49114
  _init_completion || return
50074
49115
 
50075
- local commands="${domainNames} ${allAliases} help quit exit clear history"
49116
+ local commands="${domainNames} ${allAliases.join(" ")} help quit exit clear history"
50076
49117
  local actions="${actions}"
50077
49118
  local builtins="help quit exit clear history context ctx"
50078
49119
  local global_flags="--help -h --version -v --interactive -i --no-color --output -o --namespace -ns"
@@ -50118,36 +49159,29 @@ complete -F _xcsh_completions xcsh
50118
49159
  `;
50119
49160
  }
50120
49161
  function generateZshCompletion() {
50121
- const domains = getAllDomains();
49162
+ const domains = completionRegistry.getDomains();
50122
49163
  const domainDescriptions = domains.map((d) => {
50123
- const escaped = d.description.replace(/'/g, "'\\''").replace(/:/g, "\\:");
49164
+ const escaped = escapeForZsh(d.description);
50124
49165
  return `'${d.name}:${escaped}'`;
50125
49166
  }).join("\n ");
50126
- const aliasDescriptions = domains.flatMap((d) => d.aliases.map((a) => `'${a}:Alias for ${d.name}'`)).join("\n ");
50127
- const actionDescriptions = [
50128
- "'list:List resources'",
50129
- "'get:Get a specific resource'",
50130
- "'create:Create a new resource'",
50131
- "'delete:Delete a resource'",
50132
- "'replace:Replace a resource'",
50133
- "'apply:Apply configuration from file'",
50134
- "'status:Get resource status'",
50135
- "'patch:Patch a resource'",
50136
- "'add-labels:Add labels to a resource'",
50137
- "'remove-labels:Remove labels from a resource'"
50138
- ].join("\n ");
49167
+ const aliasDescriptions = domains.filter((d) => d.aliases && d.aliases.length > 0).flatMap((d) => d.aliases.map((a) => `'${a}:Alias for ${d.name}'`)).join("\n ");
49168
+ const actionDescriptions2 = getActionDescriptions();
49169
+ const actionDescArray = Object.entries(actionDescriptions2).map(([action, desc]) => {
49170
+ const escaped = escapeForZsh(desc);
49171
+ return `'${action}:${escaped}'`;
49172
+ }).join("\n ");
50139
49173
  const customDomainCompletions = [];
50140
- for (const domain of customDomains.all()) {
50141
- const { commands, subcommands } = getCustomDomainCommands(domain.name);
50142
- if (commands.length > 0 || subcommands.size > 0) {
50143
- const cmdDescriptions = commands.map((c) => `'${c}:Command'`);
50144
- const subDescriptions = Array.from(subcommands.keys()).map(
50145
- (s) => `'${s}:Subcommand group'`
50146
- );
50147
- const allDescriptions = [...cmdDescriptions, ...subDescriptions].filter((d) => d.length > 0).join(" ");
49174
+ for (const domain of domains) {
49175
+ if (domain.source !== "custom" || !domain.children) continue;
49176
+ const childDescriptions = [];
49177
+ for (const child of domain.children.values()) {
49178
+ const escaped = escapeForZsh(child.description);
49179
+ childDescriptions.push(`'${child.name}:${escaped}'`);
49180
+ }
49181
+ if (childDescriptions.length > 0) {
50148
49182
  customDomainCompletions.push(
50149
49183
  ` (${domain.name})`,
50150
- ` _values 'command' ${allDescriptions}`,
49184
+ ` _values 'command' ${childDescriptions.join(" ")}`,
50151
49185
  ` ;;`
50152
49186
  );
50153
49187
  }
@@ -50203,7 +49237,7 @@ ${customDomainCompletions.join("\n")}
50203
49237
  (*)
50204
49238
  local -a actions
50205
49239
  actions=(
50206
- ${actionDescriptions}
49240
+ ${actionDescArray}
50207
49241
  )
50208
49242
  _describe -t actions 'action' actions
50209
49243
  ;;
@@ -50234,157 +49268,417 @@ _xcsh "$@"
50234
49268
  `;
50235
49269
  }
50236
49270
  function generateFishCompletion() {
50237
- const domains = getAllDomains();
50238
- const actions = Array.from(validActions);
49271
+ const domains = completionRegistry.getDomains();
49272
+ const actionDescriptions2 = getActionDescriptions();
50239
49273
  const domainCompletions = domains.map((d) => {
50240
- const escaped = d.description.replace(/'/g, "\\'");
49274
+ const escaped = escapeForFish(d.description);
50241
49275
  return `complete -c xcsh -n "__fish_use_subcommand" -a "${d.name}" -d '${escaped}'`;
50242
49276
  }).join("\n");
50243
- const aliasCompletions = domains.flatMap(
49277
+ const aliasCompletions = domains.filter((d) => d.aliases && d.aliases.length > 0).flatMap(
50244
49278
  (d) => d.aliases.map(
50245
49279
  (a) => `complete -c xcsh -n "__fish_use_subcommand" -a "${a}" -d 'Alias for ${d.name}'`
50246
49280
  )
50247
49281
  ).join("\n");
50248
- const actionCompletions = domains.map(
50249
- (d) => actions.map(
50250
- (a) => `complete -c xcsh -n "__fish_seen_subcommand_from ${d.name}" -a "${a}" -d '${a.charAt(0).toUpperCase() + a.slice(1)} resources'`
50251
- ).join("\n")
50252
- ).join("\n");
50253
49282
  const customDomainCompletions = [];
50254
- for (const domain of customDomains.all()) {
50255
- const { commands, subcommands } = getCustomDomainCommands(domain.name);
50256
- for (const cmd of commands) {
49283
+ for (const domain of domains) {
49284
+ if (domain.source !== "custom" || !domain.children) continue;
49285
+ for (const child of domain.children.values()) {
49286
+ const escaped = escapeForFish(child.description);
50257
49287
  customDomainCompletions.push(
50258
- `complete -c xcsh -n "__fish_seen_subcommand_from ${domain.name}" -a "${cmd}" -d 'Command'`
49288
+ `complete -c xcsh -n "__fish_seen_subcommand_from ${domain.name}" -a "${child.name}" -d '${escaped}'`
49289
+ );
49290
+ if (child.children) {
49291
+ for (const nested of child.children.values()) {
49292
+ const nestedEscaped = escapeForFish(nested.description);
49293
+ customDomainCompletions.push(
49294
+ `complete -c xcsh -n "__fish_seen_subcommand_from ${domain.name}; and __fish_seen_subcommand_from ${child.name}" -a "${nested.name}" -d '${nestedEscaped}'`
49295
+ );
49296
+ }
49297
+ }
49298
+ }
49299
+ }
49300
+ const apiDomains = domains.filter((d) => d.source === "api");
49301
+ const actionCompletions = apiDomains.map(
49302
+ (d) => Object.entries(actionDescriptions2).map(
49303
+ ([action, desc]) => `complete -c xcsh -n "__fish_seen_subcommand_from ${d.name}" -a "${action}" -d '${escapeForFish(desc)}'`
49304
+ ).join("\n")
49305
+ ).join("\n");
49306
+ return `# fish completion for xcsh
49307
+ # Generated by xcsh completion fish
49308
+
49309
+ # Disable file completions for xcsh
49310
+ complete -c xcsh -f
49311
+
49312
+ # Global options
49313
+ complete -c xcsh -s h -l help -d 'Show help information'
49314
+ complete -c xcsh -s v -l version -d 'Show version number'
49315
+ complete -c xcsh -s i -l interactive -d 'Force interactive mode'
49316
+ complete -c xcsh -l no-color -d 'Disable color output'
49317
+ complete -c xcsh -s o -l output -d 'Output format' -xa 'json yaml table'
49318
+ complete -c xcsh -l namespace -s ns -d 'Namespace' -xa 'default system shared'
49319
+
49320
+ # Builtin commands
49321
+ complete -c xcsh -n "__fish_use_subcommand" -a "help" -d 'Show help information'
49322
+ complete -c xcsh -n "__fish_use_subcommand" -a "quit" -d 'Exit the shell'
49323
+ complete -c xcsh -n "__fish_use_subcommand" -a "exit" -d 'Exit the shell'
49324
+ complete -c xcsh -n "__fish_use_subcommand" -a "clear" -d 'Clear the screen'
49325
+ complete -c xcsh -n "__fish_use_subcommand" -a "history" -d 'Show command history'
49326
+ complete -c xcsh -n "__fish_use_subcommand" -a "context" -d 'Show current navigation context'
49327
+ complete -c xcsh -n "__fish_use_subcommand" -a "ctx" -d 'Show current navigation context'
49328
+
49329
+ # Domain completions
49330
+ ${domainCompletions}
49331
+
49332
+ # Alias completions
49333
+ ${aliasCompletions}
49334
+
49335
+ # Custom domain subcommands
49336
+ ${customDomainCompletions.join("\n")}
49337
+
49338
+ # Action completions for API domains
49339
+ ${actionCompletions}
49340
+
49341
+ # Action-specific flags
49342
+ complete -c xcsh -l name -s n -d 'Resource name'
49343
+ complete -c xcsh -l limit -d 'Maximum results'
49344
+ complete -c xcsh -l label -d 'Filter by label'
49345
+ complete -c xcsh -s f -l file -d 'Configuration file' -r
49346
+ complete -c xcsh -l force -d 'Force deletion'
49347
+ complete -c xcsh -l cascade -d 'Cascade delete'
49348
+ `;
49349
+ }
49350
+
49351
+ // src/domains/completion/index.ts
49352
+ var bashCommand = {
49353
+ name: "bash",
49354
+ description: "Generate a bash shell completion script for xcsh. Output the script to stdout for manual installation or pipe to a file. Enables tab-completion for commands, domains, actions, and option flags.",
49355
+ descriptionShort: "Generate bash completion script",
49356
+ descriptionMedium: "Output bash completion script for tab-completion of commands, domains, and flags.",
49357
+ async execute() {
49358
+ try {
49359
+ const script = generateBashCompletion();
49360
+ return successResult([script]);
49361
+ } catch (error) {
49362
+ return errorResult(
49363
+ `Failed to generate bash completion: ${error instanceof Error ? error.message : "Unknown error"}`
50259
49364
  );
50260
49365
  }
50261
- for (const [groupName, groupCommands] of subcommands) {
50262
- customDomainCompletions.push(
50263
- `complete -c xcsh -n "__fish_seen_subcommand_from ${domain.name}" -a "${groupName}" -d 'Subcommand group'`
50264
- );
50265
- for (const cmd of groupCommands) {
50266
- customDomainCompletions.push(
50267
- `complete -c xcsh -n "__fish_seen_subcommand_from ${domain.name}; and __fish_seen_subcommand_from ${groupName}" -a "${cmd}" -d 'Command'`
50268
- );
49366
+ }
49367
+ };
49368
+ var zshCommand = {
49369
+ name: "zsh",
49370
+ description: "Generate a zsh shell completion script for xcsh. Output the script to stdout for manual installation or add to your fpath. Provides rich tab-completion with descriptions for commands, domains, and options.",
49371
+ descriptionShort: "Generate zsh completion script",
49372
+ descriptionMedium: "Output zsh completion script with rich descriptions for commands and options.",
49373
+ async execute() {
49374
+ try {
49375
+ const script = generateZshCompletion();
49376
+ return successResult([script]);
49377
+ } catch (error) {
49378
+ return errorResult(
49379
+ `Failed to generate zsh completion: ${error instanceof Error ? error.message : "Unknown error"}`
49380
+ );
49381
+ }
49382
+ }
49383
+ };
49384
+ var fishCommand = {
49385
+ name: "fish",
49386
+ description: "Generate a fish shell completion script for xcsh. Output the script to stdout for manual installation or save to your fish completions directory. Enables intelligent tab-completion with inline descriptions.",
49387
+ descriptionShort: "Generate fish completion script",
49388
+ descriptionMedium: "Output fish completion script with inline descriptions for commands and options.",
49389
+ async execute() {
49390
+ try {
49391
+ const script = generateFishCompletion();
49392
+ return successResult([script]);
49393
+ } catch (error) {
49394
+ return errorResult(
49395
+ `Failed to generate fish completion: ${error instanceof Error ? error.message : "Unknown error"}`
49396
+ );
49397
+ }
49398
+ }
49399
+ };
49400
+ var completionDomain = {
49401
+ name: "completion",
49402
+ description: "Generate shell completion scripts for bash, zsh, and fish shells. Enables tab-completion for xcsh commands, domains, actions, and flags in your preferred shell environment.",
49403
+ descriptionShort: "Shell completion script generation",
49404
+ descriptionMedium: "Generate tab-completion scripts for bash, zsh, and fish shells to enhance the xcsh command-line experience.",
49405
+ commands: /* @__PURE__ */ new Map([
49406
+ ["bash", bashCommand],
49407
+ ["zsh", zshCommand],
49408
+ ["fish", fishCommand]
49409
+ ]),
49410
+ subcommands: /* @__PURE__ */ new Map()
49411
+ };
49412
+
49413
+ // src/domains/index.ts
49414
+ customDomains.register(loginDomain);
49415
+ customDomains.register(cloudstatusDomain);
49416
+ customDomains.register(completionDomain);
49417
+ for (const domain of customDomains.all()) {
49418
+ completionRegistry.registerDomain(fromCustomDomain(domain));
49419
+ }
49420
+ for (const [, info] of domainRegistry) {
49421
+ if (!completionRegistry.has(info.name)) {
49422
+ completionRegistry.registerDomain(fromApiDomain(info));
49423
+ }
49424
+ }
49425
+ var domainAliases = /* @__PURE__ */ new Map();
49426
+ for (const alias of cloudstatusAliases) {
49427
+ domainAliases.set(alias, "cloudstatus");
49428
+ }
49429
+ function resolveDomainAlias(name) {
49430
+ return domainAliases.get(name) ?? name;
49431
+ }
49432
+ function isCustomDomain(name) {
49433
+ const canonical = resolveDomainAlias(name);
49434
+ return customDomains.has(canonical);
49435
+ }
49436
+
49437
+ // src/extensions/types.ts
49438
+ var RESERVED_API_ACTIONS = /* @__PURE__ */ new Set([
49439
+ "list",
49440
+ "get",
49441
+ "create",
49442
+ "delete",
49443
+ "replace",
49444
+ "apply",
49445
+ "status",
49446
+ "patch",
49447
+ "add-labels",
49448
+ "remove-labels"
49449
+ ]);
49450
+ function isReservedAction(name) {
49451
+ return RESERVED_API_ACTIONS.has(name.toLowerCase());
49452
+ }
49453
+ function validateExtension(extension) {
49454
+ const conflicts = [];
49455
+ for (const [name] of extension.commands) {
49456
+ if (isReservedAction(name)) {
49457
+ conflicts.push(name);
49458
+ }
49459
+ }
49460
+ if (conflicts.length > 0) {
49461
+ throw new Error(
49462
+ `Extension "${extension.targetDomain}" has commands that conflict with API actions: ${conflicts.join(", ")}. Use unique names or submit a feature request to upstream.`
49463
+ );
49464
+ }
49465
+ }
49466
+
49467
+ // src/extensions/registry.ts
49468
+ var ExtensionRegistry = class {
49469
+ extensions = /* @__PURE__ */ new Map();
49470
+ mergedCache = /* @__PURE__ */ new Map();
49471
+ /**
49472
+ * Register a domain extension
49473
+ *
49474
+ * @param extension - Extension definition to register
49475
+ * @throws Error if extension has command name conflicts with API actions
49476
+ */
49477
+ register(extension) {
49478
+ validateExtension(extension);
49479
+ this.extensions.set(extension.targetDomain, extension);
49480
+ this.mergedCache.delete(extension.targetDomain);
49481
+ }
49482
+ /**
49483
+ * Get extension for a domain
49484
+ *
49485
+ * @param domain - Canonical domain name
49486
+ * @returns Extension if registered, undefined otherwise
49487
+ */
49488
+ getExtension(domain) {
49489
+ return this.extensions.get(domain);
49490
+ }
49491
+ /**
49492
+ * Check if a domain has an extension
49493
+ */
49494
+ hasExtension(domain) {
49495
+ return this.extensions.has(domain);
49496
+ }
49497
+ /**
49498
+ * Get merged domain view combining API domain + extension
49499
+ *
49500
+ * Resolution priority:
49501
+ * 1. Check if canonical domain exists in generated domains
49502
+ * 2. Check if extension exists for this domain
49503
+ * 3. Merge if both exist, or return standalone if only one
49504
+ *
49505
+ * @param domain - Canonical domain name or alias
49506
+ * @returns Merged domain view or undefined if neither exists
49507
+ */
49508
+ getMergedDomain(domain) {
49509
+ const canonical = aliasRegistry.get(domain) ?? domain;
49510
+ const cached = this.mergedCache.get(canonical);
49511
+ if (cached) {
49512
+ return cached;
49513
+ }
49514
+ const domainInfo = domainRegistry.get(canonical);
49515
+ const extension = this.extensions.get(canonical);
49516
+ if (!domainInfo && !extension) {
49517
+ return void 0;
49518
+ }
49519
+ const merged = this.buildMergedDomain(canonical, domainInfo, extension);
49520
+ this.mergedCache.set(canonical, merged);
49521
+ return merged;
49522
+ }
49523
+ /**
49524
+ * Build a merged domain from API domain info and/or extension
49525
+ */
49526
+ buildMergedDomain(name, domainInfo, extension) {
49527
+ const hasGeneratedDomain = !!domainInfo;
49528
+ const hasExtension = !!extension;
49529
+ let source;
49530
+ if (hasGeneratedDomain && hasExtension) {
49531
+ source = "merged";
49532
+ } else if (hasGeneratedDomain) {
49533
+ source = "generated";
49534
+ } else {
49535
+ source = "extension";
49536
+ }
49537
+ const displayName = domainInfo?.displayName ?? this.toDisplayName(extension?.targetDomain ?? name);
49538
+ const description = domainInfo?.description ?? extension?.description ?? `Commands for ${displayName}`;
49539
+ const merged = {
49540
+ name,
49541
+ displayName,
49542
+ description,
49543
+ source,
49544
+ hasGeneratedDomain,
49545
+ hasExtension,
49546
+ extensionCommands: extension?.commands ?? /* @__PURE__ */ new Map(),
49547
+ extensionSubcommands: extension?.subcommands ?? /* @__PURE__ */ new Map()
49548
+ };
49549
+ if (domainInfo) {
49550
+ merged.metadata = domainInfo;
49551
+ }
49552
+ return merged;
49553
+ }
49554
+ /**
49555
+ * Convert snake_case domain name to display name
49556
+ */
49557
+ toDisplayName(name) {
49558
+ return name.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
49559
+ }
49560
+ /**
49561
+ * Get all domains with extensions (for iteration)
49562
+ */
49563
+ getExtendedDomains() {
49564
+ return Array.from(this.extensions.keys());
49565
+ }
49566
+ /**
49567
+ * Get all merged domains (generated + extended)
49568
+ *
49569
+ * Returns domains that either:
49570
+ * - Have generated API commands (from upstream)
49571
+ * - Have extension commands (xcsh-specific)
49572
+ * - Have both (merged)
49573
+ */
49574
+ getAllMergedDomains() {
49575
+ const domains = /* @__PURE__ */ new Set();
49576
+ for (const name of domainRegistry.keys()) {
49577
+ domains.add(name);
49578
+ }
49579
+ for (const name of this.extensions.keys()) {
49580
+ domains.add(name);
49581
+ }
49582
+ const merged = [];
49583
+ for (const name of domains) {
49584
+ const domain = this.getMergedDomain(name);
49585
+ if (domain) {
49586
+ merged.push(domain);
49587
+ }
49588
+ }
49589
+ return merged.sort((a, b) => a.name.localeCompare(b.name));
49590
+ }
49591
+ /**
49592
+ * Get extension command by name
49593
+ *
49594
+ * @param domain - Canonical domain name
49595
+ * @param command - Command name
49596
+ * @returns Command definition if found
49597
+ */
49598
+ getExtensionCommand(domain, command) {
49599
+ const extension = this.getExtension(domain);
49600
+ if (!extension) {
49601
+ return void 0;
49602
+ }
49603
+ const cmd = extension.commands.get(command);
49604
+ if (cmd) {
49605
+ return cmd;
49606
+ }
49607
+ for (const [, cmdDef] of extension.commands) {
49608
+ if (cmdDef.aliases?.includes(command)) {
49609
+ return cmdDef;
50269
49610
  }
50270
49611
  }
49612
+ return void 0;
50271
49613
  }
50272
- return `# fish completion for xcsh
50273
- # Generated by xcsh completion fish
50274
-
50275
- # Disable file completions for xcsh
50276
- complete -c xcsh -f
50277
-
50278
- # Global options
50279
- complete -c xcsh -s h -l help -d 'Show help information'
50280
- complete -c xcsh -s v -l version -d 'Show version number'
50281
- complete -c xcsh -s i -l interactive -d 'Force interactive mode'
50282
- complete -c xcsh -l no-color -d 'Disable color output'
50283
- complete -c xcsh -s o -l output -d 'Output format' -xa 'json yaml table'
50284
- complete -c xcsh -l namespace -s ns -d 'Namespace' -xa 'default system shared'
50285
-
50286
- # Builtin commands
50287
- complete -c xcsh -n "__fish_use_subcommand" -a "help" -d 'Show help information'
50288
- complete -c xcsh -n "__fish_use_subcommand" -a "quit" -d 'Exit the shell'
50289
- complete -c xcsh -n "__fish_use_subcommand" -a "exit" -d 'Exit the shell'
50290
- complete -c xcsh -n "__fish_use_subcommand" -a "clear" -d 'Clear the screen'
50291
- complete -c xcsh -n "__fish_use_subcommand" -a "history" -d 'Show command history'
50292
- complete -c xcsh -n "__fish_use_subcommand" -a "context" -d 'Show current navigation context'
50293
- complete -c xcsh -n "__fish_use_subcommand" -a "ctx" -d 'Show current navigation context'
50294
-
50295
- # Domain completions
50296
- ${domainCompletions}
50297
-
50298
- # Alias completions
50299
- ${aliasCompletions}
50300
-
50301
- # Custom domain subcommands
50302
- ${customDomainCompletions.join("\n")}
50303
-
50304
- # Action completions for API domains
50305
- ${actionCompletions}
50306
-
50307
- # Action-specific flags
50308
- complete -c xcsh -l name -s n -d 'Resource name'
50309
- complete -c xcsh -l limit -d 'Maximum results'
50310
- complete -c xcsh -l label -d 'Filter by label'
50311
- complete -c xcsh -s f -l file -d 'Configuration file' -r
50312
- complete -c xcsh -l force -d 'Force deletion'
50313
- complete -c xcsh -l cascade -d 'Cascade delete'
50314
- `;
50315
- }
50316
-
50317
- // src/domains/completion/index.ts
50318
- var bashCommand = {
50319
- name: "bash",
50320
- description: "Generate bash completion script",
50321
- async execute() {
50322
- try {
50323
- const script = generateBashCompletion();
50324
- return successResult([script]);
50325
- } catch (error) {
50326
- return errorResult(
50327
- `Failed to generate bash completion: ${error instanceof Error ? error.message : "Unknown error"}`
50328
- );
50329
- }
49614
+ /**
49615
+ * Get extension subcommand group
49616
+ *
49617
+ * @param domain - Canonical domain name
49618
+ * @param subcommand - Subcommand group name
49619
+ * @returns Subcommand group if found
49620
+ */
49621
+ getExtensionSubcommand(domain, subcommand) {
49622
+ const extension = this.getExtension(domain);
49623
+ return extension?.subcommands?.get(subcommand);
50330
49624
  }
50331
- };
50332
- var zshCommand = {
50333
- name: "zsh",
50334
- description: "Generate zsh completion script",
50335
- async execute() {
50336
- try {
50337
- const script = generateZshCompletion();
50338
- return successResult([script]);
50339
- } catch (error) {
50340
- return errorResult(
50341
- `Failed to generate zsh completion: ${error instanceof Error ? error.message : "Unknown error"}`
50342
- );
49625
+ /**
49626
+ * Check if a command exists in extension
49627
+ */
49628
+ hasExtensionCommand(domain, command) {
49629
+ return this.getExtensionCommand(domain, command) !== void 0;
49630
+ }
49631
+ /**
49632
+ * Get all extension command names for a domain
49633
+ * Used for tab completion
49634
+ */
49635
+ getExtensionCommandNames(domain) {
49636
+ const extension = this.getExtension(domain);
49637
+ if (!extension) {
49638
+ return [];
49639
+ }
49640
+ const names = [];
49641
+ for (const [name, cmd] of extension.commands) {
49642
+ names.push(name);
49643
+ if (cmd.aliases) {
49644
+ names.push(...cmd.aliases);
49645
+ }
50343
49646
  }
49647
+ return names;
50344
49648
  }
50345
- };
50346
- var fishCommand = {
50347
- name: "fish",
50348
- description: "Generate fish completion script",
50349
- async execute() {
50350
- try {
50351
- const script = generateFishCompletion();
50352
- return successResult([script]);
50353
- } catch (error) {
50354
- return errorResult(
50355
- `Failed to generate fish completion: ${error instanceof Error ? error.message : "Unknown error"}`
50356
- );
49649
+ /**
49650
+ * Clear the merged domain cache
49651
+ * Call this if generated domains change
49652
+ */
49653
+ clearCache() {
49654
+ this.mergedCache.clear();
49655
+ }
49656
+ /**
49657
+ * Get registry statistics
49658
+ */
49659
+ getStats() {
49660
+ let standaloneCount = 0;
49661
+ let mergedCount = 0;
49662
+ for (const [domain] of this.extensions) {
49663
+ if (domainRegistry.has(domain)) {
49664
+ mergedCount++;
49665
+ } else {
49666
+ standaloneCount++;
49667
+ }
50357
49668
  }
49669
+ return {
49670
+ extensionCount: this.extensions.size,
49671
+ standaloneCount,
49672
+ mergedCount
49673
+ };
50358
49674
  }
50359
49675
  };
50360
- var completionDomain = {
50361
- name: "completion",
50362
- description: "Generate shell completion scripts for bash, zsh, and fish shells. Enables tab-completion for xcsh commands, domains, actions, and flags in your preferred shell environment.",
50363
- descriptionShort: "Shell completion script generation",
50364
- descriptionMedium: "Generate tab-completion scripts for bash, zsh, and fish shells to enhance the xcsh command-line experience.",
50365
- commands: /* @__PURE__ */ new Map([
50366
- ["bash", bashCommand],
50367
- ["zsh", zshCommand],
50368
- ["fish", fishCommand]
50369
- ]),
50370
- subcommands: /* @__PURE__ */ new Map()
50371
- };
49676
+ var extensionRegistry = new ExtensionRegistry();
50372
49677
 
50373
- // src/domains/index.ts
50374
- customDomains.register(loginDomain);
50375
- customDomains.register(cloudstatusDomain);
50376
- customDomains.register(completionDomain);
50377
- var domainAliases = /* @__PURE__ */ new Map();
50378
- for (const alias of cloudstatusAliases) {
50379
- domainAliases.set(alias, "cloudstatus");
50380
- }
50381
- function resolveDomainAlias(name) {
50382
- return domainAliases.get(name) ?? name;
50383
- }
50384
- function isCustomDomain(name) {
50385
- const canonical = resolveDomainAlias(name);
50386
- return customDomains.has(canonical);
49678
+ // src/extensions/index.ts
49679
+ function initializeExtensions() {
50387
49680
  }
49681
+ initializeExtensions();
50388
49682
 
50389
49683
  // src/repl/completion/cache.ts
50390
49684
  var DEFAULT_TTL_MS = 5 * 60 * 1e3;
@@ -50604,7 +49898,25 @@ var Completer = class {
50604
49898
  }
50605
49899
  let suggestions;
50606
49900
  if (parsed.isEscapedToRoot) {
50607
- suggestions = this.getRootContextSuggestions();
49901
+ const firstArg2 = parsed.args[0];
49902
+ if (parsed.args.length > 0 && firstArg2) {
49903
+ const targetDomain = firstArg2.toLowerCase();
49904
+ if (completionRegistry.has(targetDomain)) {
49905
+ const domainNode = completionRegistry.get(targetDomain);
49906
+ if (domainNode?.source === "api") {
49907
+ suggestions = this.getActionSuggestions();
49908
+ } else {
49909
+ suggestions = completionRegistry.getChildSuggestions(
49910
+ targetDomain,
49911
+ parsed.currentWord
49912
+ );
49913
+ }
49914
+ } else {
49915
+ suggestions = this.getRootContextSuggestions();
49916
+ }
49917
+ } else {
49918
+ suggestions = this.getRootContextSuggestions();
49919
+ }
50608
49920
  } else {
50609
49921
  suggestions = await this.getContextualSuggestions();
50610
49922
  }
@@ -50615,53 +49927,36 @@ var Completer = class {
50615
49927
  }
50616
49928
  /**
50617
49929
  * Get completions for custom domain commands
49930
+ * Uses unified completion registry for structure navigation,
49931
+ * falls back to domain handlers for argument completions
50618
49932
  */
50619
49933
  async getCustomDomainCompletions(domainName, args, currentWord) {
50620
- const domain = customDomains.get(domainName);
50621
- if (!domain) {
49934
+ const domainNode = completionRegistry.get(domainName);
49935
+ if (!domainNode) {
50622
49936
  return [];
50623
49937
  }
50624
- const suggestions = [];
50625
49938
  if (args.length === 0 || args.length === 1 && currentWord === args[0]) {
50626
- for (const [name, group] of domain.subcommands) {
50627
- if (!currentWord || name.toLowerCase().startsWith(currentWord.toLowerCase())) {
50628
- suggestions.push({
50629
- text: name,
50630
- description: group.description,
50631
- category: "subcommand"
50632
- });
50633
- }
50634
- }
50635
- for (const [name, cmd] of domain.commands) {
50636
- if (!currentWord || name.toLowerCase().startsWith(currentWord.toLowerCase())) {
50637
- suggestions.push({
50638
- text: name,
50639
- description: cmd.description,
50640
- category: "command"
50641
- });
50642
- }
50643
- }
50644
- return suggestions;
49939
+ return completionRegistry.getChildSuggestions(
49940
+ domainName,
49941
+ currentWord
49942
+ );
50645
49943
  }
50646
49944
  const subgroupName = args[0]?.toLowerCase() ?? "";
50647
- const subgroup = domain.subcommands.get(subgroupName);
50648
- if (subgroup) {
49945
+ const subgroupNode = domainNode.children?.get(subgroupName);
49946
+ if (subgroupNode?.children) {
50649
49947
  if (args.length === 1 || args.length === 2 && currentWord === args[1]) {
50650
- const cmdPrefix = args.length === 2 ? currentWord : "";
50651
- for (const [name, cmd] of subgroup.commands) {
50652
- if (!cmdPrefix || name.toLowerCase().startsWith(cmdPrefix.toLowerCase())) {
50653
- suggestions.push({
50654
- text: name,
50655
- description: cmd.description,
50656
- category: "command"
50657
- });
50658
- }
50659
- }
50660
- return suggestions;
49948
+ const prefix = args.length === 2 ? currentWord : "";
49949
+ return completionRegistry.getNestedChildSuggestions(
49950
+ domainName,
49951
+ [subgroupName],
49952
+ prefix
49953
+ );
50661
49954
  }
50662
49955
  if (args.length >= 2 && this.session) {
50663
49956
  const cmdName = args[1]?.toLowerCase() ?? "";
50664
- const cmd = subgroup.commands.get(cmdName);
49957
+ const domain2 = customDomains.get(domainName);
49958
+ const subgroup = domain2?.subcommands.get(subgroupName);
49959
+ const cmd = subgroup?.commands.get(cmdName);
50665
49960
  if (cmd?.completion) {
50666
49961
  try {
50667
49962
  const completions = await cmd.completion(
@@ -50680,8 +49975,9 @@ var Completer = class {
50680
49975
  }
50681
49976
  }
50682
49977
  const directCmdName = args[0]?.toLowerCase() ?? "";
50683
- const directCmd = domain.commands.get(directCmdName);
50684
- if (directCmd?.completion) {
49978
+ const domain = customDomains.get(domainName);
49979
+ const directCmd = domain?.commands.get(directCmdName);
49980
+ if (directCmd?.completion && this.session) {
50685
49981
  try {
50686
49982
  const completions = await directCmd.completion(
50687
49983
  currentWord,
@@ -50696,7 +49992,7 @@ var Completer = class {
50696
49992
  } catch {
50697
49993
  }
50698
49994
  }
50699
- return suggestions;
49995
+ return [];
50700
49996
  }
50701
49997
  /**
50702
49998
  * Get suggestions based on current navigation context
@@ -50872,95 +50168,23 @@ var Completer = class {
50872
50168
  return suggestions;
50873
50169
  }
50874
50170
  /**
50875
- * Get domain suggestions from registry
50171
+ * Get domain suggestions from unified registry
50876
50172
  */
50877
50173
  getDomainSuggestions() {
50878
- const suggestions = [];
50879
- const addedDomains = /* @__PURE__ */ new Set();
50880
- for (const domain of customDomains.all()) {
50881
- suggestions.push({
50882
- text: domain.name,
50883
- description: domain.description,
50884
- category: "domain"
50885
- });
50886
- addedDomains.add(domain.name);
50887
- }
50888
- for (const extDomain of extensionRegistry.getExtendedDomains()) {
50889
- if (addedDomains.has(extDomain)) continue;
50890
- if (domainRegistry.has(extDomain)) continue;
50891
- const merged = extensionRegistry.getMergedDomain(extDomain);
50892
- if (merged && merged.source === "extension") {
50893
- suggestions.push({
50894
- text: extDomain,
50895
- description: merged.description,
50896
- category: "domain"
50897
- });
50898
- addedDomains.add(extDomain);
50899
- }
50900
- }
50901
- for (const [domain, meta] of domainRegistry) {
50902
- if (addedDomains.has(domain)) continue;
50903
- suggestions.push({
50904
- text: domain,
50905
- description: meta.descriptionShort,
50906
- category: "domain"
50907
- });
50908
- addedDomains.add(domain);
50909
- }
50910
- return suggestions;
50174
+ return completionRegistry.getDomainSuggestions();
50911
50175
  }
50912
50176
  /**
50913
- * Get action suggestions
50177
+ * Get action suggestions from unified registry
50914
50178
  */
50915
50179
  getActionSuggestions() {
50916
- return [
50917
- { text: "list", description: "List resources", category: "action" },
50918
- {
50919
- text: "get",
50920
- description: "Get a specific resource",
50921
- category: "action"
50922
- },
50923
- {
50924
- text: "create",
50925
- description: "Create a new resource",
50926
- category: "action"
50927
- },
50928
- {
50929
- text: "delete",
50930
- description: "Delete a resource",
50931
- category: "action"
50932
- },
50933
- {
50934
- text: "replace",
50935
- description: "Replace a resource",
50936
- category: "action"
50937
- },
50938
- {
50939
- text: "apply",
50940
- description: "Apply configuration from file",
50180
+ const actionDescriptions2 = getActionDescriptions();
50181
+ return Object.entries(actionDescriptions2).map(
50182
+ ([action, description]) => ({
50183
+ text: action,
50184
+ description,
50941
50185
  category: "action"
50942
- },
50943
- {
50944
- text: "status",
50945
- description: "Get resource status",
50946
- category: "action"
50947
- },
50948
- {
50949
- text: "patch",
50950
- description: "Patch a resource",
50951
- category: "action"
50952
- },
50953
- {
50954
- text: "add-labels",
50955
- description: "Add labels to a resource",
50956
- category: "action"
50957
- },
50958
- {
50959
- text: "remove-labels",
50960
- description: "Remove labels from a resource",
50961
- category: "action"
50962
- }
50963
- ];
50186
+ })
50187
+ );
50964
50188
  }
50965
50189
  /**
50966
50190
  * Get flag suggestions for current action
@@ -51574,7 +50798,7 @@ function formatDomainHelp(domain) {
51574
50798
  output.push(` ${CLI_NAME} ${domain.name} <action> [options]`);
51575
50799
  output.push("");
51576
50800
  output.push("ACTIONS");
51577
- const actionDescriptions = {
50801
+ const actionDescriptions2 = {
51578
50802
  list: "List resources",
51579
50803
  get: "Get a specific resource by name",
51580
50804
  create: "Create a new resource",
@@ -51587,7 +50811,7 @@ function formatDomainHelp(domain) {
51587
50811
  "remove-labels": "Remove labels from a resource"
51588
50812
  };
51589
50813
  for (const action of validActions) {
51590
- const desc = actionDescriptions[action] ?? action;
50814
+ const desc = actionDescriptions2[action] ?? action;
51591
50815
  output.push(` ${action.padEnd(16)} ${desc}`);
51592
50816
  }
51593
50817
  output.push("");
@@ -51623,7 +50847,7 @@ function formatDomainHelp(domain) {
51623
50847
  function formatActionHelp(domainName, action) {
51624
50848
  const domain = getDomainInfo(domainName);
51625
50849
  const displayDomain = domain?.displayName ?? domainName;
51626
- const actionDescriptions = {
50850
+ const actionDescriptions2 = {
51627
50851
  list: {
51628
50852
  desc: "List all resources in the namespace",
51629
50853
  usage: `${CLI_NAME} ${domainName} list [--limit N] [--label key=value]`
@@ -51665,7 +50889,7 @@ function formatActionHelp(domainName, action) {
51665
50889
  usage: `${CLI_NAME} ${domainName} remove-labels <name> key`
51666
50890
  }
51667
50891
  };
51668
- const actionInfo = actionDescriptions[action] ?? {
50892
+ const actionInfo = actionDescriptions2[action] ?? {
51669
50893
  desc: `Execute ${action} operation`,
51670
50894
  usage: `${CLI_NAME} ${domainName} ${action} [options]`
51671
50895
  };