@robinmordasiewicz/f5xc-xcsh 1.0.91-2601040044 → 1.0.91-2601040346
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 +584 -117
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -47052,8 +47052,8 @@ function getLogoModeFromEnv(envPrefix) {
|
|
|
47052
47052
|
var CLI_NAME = "xcsh";
|
|
47053
47053
|
var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
|
|
47054
47054
|
function getVersion() {
|
|
47055
|
-
if ("v1.0.91-
|
|
47056
|
-
return "v1.0.91-
|
|
47055
|
+
if ("v1.0.91-2601040346") {
|
|
47056
|
+
return "v1.0.91-2601040346";
|
|
47057
47057
|
}
|
|
47058
47058
|
if (process.env.XCSH_VERSION) {
|
|
47059
47059
|
return process.env.XCSH_VERSION;
|
|
@@ -145585,6 +145585,387 @@ function buildConnectionInfo(profileName, apiUrl, hasToken, namespace, isConnect
|
|
|
145585
145585
|
return info;
|
|
145586
145586
|
}
|
|
145587
145587
|
|
|
145588
|
+
// src/validation/namespace.ts
|
|
145589
|
+
function validateNamespaceScope(domain, action, currentNamespace, resourceType) {
|
|
145590
|
+
const opInfo = getOperationDescription(domain, action, resourceType);
|
|
145591
|
+
if (!opInfo?.namespaceScope) {
|
|
145592
|
+
return { valid: true };
|
|
145593
|
+
}
|
|
145594
|
+
const scope = opInfo.namespaceScope;
|
|
145595
|
+
const normalizedNamespace = currentNamespace.toLowerCase();
|
|
145596
|
+
switch (scope) {
|
|
145597
|
+
case "system":
|
|
145598
|
+
if (normalizedNamespace !== "system") {
|
|
145599
|
+
return {
|
|
145600
|
+
valid: false,
|
|
145601
|
+
scope,
|
|
145602
|
+
message: `${action} on ${resourceType || domain} requires the 'system' namespace`,
|
|
145603
|
+
suggestion: "system"
|
|
145604
|
+
};
|
|
145605
|
+
}
|
|
145606
|
+
return { valid: true, scope };
|
|
145607
|
+
case "shared":
|
|
145608
|
+
if (normalizedNamespace !== "shared") {
|
|
145609
|
+
return {
|
|
145610
|
+
valid: false,
|
|
145611
|
+
scope,
|
|
145612
|
+
message: `${action} on ${resourceType || domain} requires the 'shared' namespace`,
|
|
145613
|
+
suggestion: "shared"
|
|
145614
|
+
};
|
|
145615
|
+
}
|
|
145616
|
+
return { valid: true, scope };
|
|
145617
|
+
case "any":
|
|
145618
|
+
default:
|
|
145619
|
+
return { valid: true, scope };
|
|
145620
|
+
}
|
|
145621
|
+
}
|
|
145622
|
+
|
|
145623
|
+
// src/validation/safety.ts
|
|
145624
|
+
function checkOperationSafety(domain, action, resourceType) {
|
|
145625
|
+
const opInfo = getOperationDescription(domain, action, resourceType);
|
|
145626
|
+
const dangerLevel = opInfo?.dangerLevel || "low";
|
|
145627
|
+
const requiresConfirmation2 = opInfo?.confirmationRequired ?? dangerLevel === "high";
|
|
145628
|
+
const sideEffects = opInfo?.sideEffects;
|
|
145629
|
+
const result = {
|
|
145630
|
+
proceed: dangerLevel !== "high",
|
|
145631
|
+
// High danger requires explicit confirmation
|
|
145632
|
+
dangerLevel,
|
|
145633
|
+
requiresConfirmation: requiresConfirmation2
|
|
145634
|
+
};
|
|
145635
|
+
if (dangerLevel === "high") {
|
|
145636
|
+
result.warning = formatHighDangerWarning(domain, action, sideEffects);
|
|
145637
|
+
} else if (dangerLevel === "medium") {
|
|
145638
|
+
result.warning = formatMediumDangerWarning(domain, action, sideEffects);
|
|
145639
|
+
}
|
|
145640
|
+
if (sideEffects) {
|
|
145641
|
+
result.sideEffects = sideEffects;
|
|
145642
|
+
}
|
|
145643
|
+
return result;
|
|
145644
|
+
}
|
|
145645
|
+
function formatHighDangerWarning(_domain, _action, sideEffects) {
|
|
145646
|
+
const lines = [
|
|
145647
|
+
colorRed("\u26A0\uFE0F WARNING: This is a HIGH DANGER operation"),
|
|
145648
|
+
""
|
|
145649
|
+
];
|
|
145650
|
+
if (sideEffects) {
|
|
145651
|
+
if (sideEffects.deletes && sideEffects.deletes.length > 0) {
|
|
145652
|
+
lines.push(
|
|
145653
|
+
colorRed(` Will DELETE: ${sideEffects.deletes.join(", ")}`)
|
|
145654
|
+
);
|
|
145655
|
+
}
|
|
145656
|
+
if (sideEffects.updates && sideEffects.updates.length > 0) {
|
|
145657
|
+
lines.push(` Will UPDATE: ${sideEffects.updates.join(", ")}`);
|
|
145658
|
+
}
|
|
145659
|
+
if (sideEffects.creates && sideEffects.creates.length > 0) {
|
|
145660
|
+
lines.push(
|
|
145661
|
+
colorDim(` Will CREATE: ${sideEffects.creates.join(", ")}`)
|
|
145662
|
+
);
|
|
145663
|
+
}
|
|
145664
|
+
lines.push("");
|
|
145665
|
+
}
|
|
145666
|
+
lines.push(
|
|
145667
|
+
colorRed("This action may be destructive and cannot be undone.")
|
|
145668
|
+
);
|
|
145669
|
+
return lines.join("\n");
|
|
145670
|
+
}
|
|
145671
|
+
function formatMediumDangerWarning(_domain, _action, sideEffects) {
|
|
145672
|
+
const lines = [
|
|
145673
|
+
colorYellow("\u26A0\uFE0F CAUTION: This operation may have significant effects"),
|
|
145674
|
+
""
|
|
145675
|
+
];
|
|
145676
|
+
if (sideEffects) {
|
|
145677
|
+
const effects = [];
|
|
145678
|
+
if (sideEffects.creates && sideEffects.creates.length > 0) {
|
|
145679
|
+
effects.push(`creates: ${sideEffects.creates.join(", ")}`);
|
|
145680
|
+
}
|
|
145681
|
+
if (sideEffects.updates && sideEffects.updates.length > 0) {
|
|
145682
|
+
effects.push(`updates: ${sideEffects.updates.join(", ")}`);
|
|
145683
|
+
}
|
|
145684
|
+
if (sideEffects.deletes && sideEffects.deletes.length > 0) {
|
|
145685
|
+
effects.push(`deletes: ${sideEffects.deletes.join(", ")}`);
|
|
145686
|
+
}
|
|
145687
|
+
if (effects.length > 0) {
|
|
145688
|
+
lines.push(` Side effects: ${effects.join("; ")}`);
|
|
145689
|
+
lines.push("");
|
|
145690
|
+
}
|
|
145691
|
+
}
|
|
145692
|
+
return lines.join("\n");
|
|
145693
|
+
}
|
|
145694
|
+
|
|
145695
|
+
// src/validation/reserved-words.ts
|
|
145696
|
+
var RESERVED_ACTIONS = /* @__PURE__ */ new Set([
|
|
145697
|
+
// CRUD operations
|
|
145698
|
+
"create",
|
|
145699
|
+
"delete",
|
|
145700
|
+
"list",
|
|
145701
|
+
"get",
|
|
145702
|
+
"update",
|
|
145703
|
+
"apply",
|
|
145704
|
+
"patch",
|
|
145705
|
+
// Info operations
|
|
145706
|
+
"describe",
|
|
145707
|
+
"show",
|
|
145708
|
+
"status",
|
|
145709
|
+
"logs",
|
|
145710
|
+
"events",
|
|
145711
|
+
// Modification
|
|
145712
|
+
"edit",
|
|
145713
|
+
"replace",
|
|
145714
|
+
"set",
|
|
145715
|
+
"unset",
|
|
145716
|
+
// Lifecycle
|
|
145717
|
+
"start",
|
|
145718
|
+
"stop",
|
|
145719
|
+
"restart",
|
|
145720
|
+
"rollout",
|
|
145721
|
+
"scale",
|
|
145722
|
+
// Connection
|
|
145723
|
+
"attach",
|
|
145724
|
+
"detach",
|
|
145725
|
+
"connect",
|
|
145726
|
+
"disconnect",
|
|
145727
|
+
// Registration
|
|
145728
|
+
"register",
|
|
145729
|
+
"deregister",
|
|
145730
|
+
"associate",
|
|
145731
|
+
"disassociate",
|
|
145732
|
+
// AWS-specific
|
|
145733
|
+
"put",
|
|
145734
|
+
"modify",
|
|
145735
|
+
// Built-in xcsh commands
|
|
145736
|
+
"help",
|
|
145737
|
+
"quit",
|
|
145738
|
+
"exit",
|
|
145739
|
+
"clear",
|
|
145740
|
+
"history",
|
|
145741
|
+
"refresh",
|
|
145742
|
+
"context",
|
|
145743
|
+
"banner",
|
|
145744
|
+
"profile",
|
|
145745
|
+
"completion",
|
|
145746
|
+
// Common CLI patterns
|
|
145747
|
+
"run",
|
|
145748
|
+
"exec",
|
|
145749
|
+
"wait",
|
|
145750
|
+
"open",
|
|
145751
|
+
"close",
|
|
145752
|
+
"inspect",
|
|
145753
|
+
"validate",
|
|
145754
|
+
"diff",
|
|
145755
|
+
"plan",
|
|
145756
|
+
"import",
|
|
145757
|
+
"export"
|
|
145758
|
+
]);
|
|
145759
|
+
var SHELL_METACHARACTERS = /[;&|`$()<>\\#!{}[\]*?~\n\r]/;
|
|
145760
|
+
var DANGEROUS_PATTERNS = [
|
|
145761
|
+
{
|
|
145762
|
+
pattern: /^-/,
|
|
145763
|
+
message: "Name cannot start with a hyphen (would be interpreted as a flag)"
|
|
145764
|
+
},
|
|
145765
|
+
{
|
|
145766
|
+
pattern: /^--/,
|
|
145767
|
+
message: "Name cannot start with double-hyphen (would be interpreted as a long flag)"
|
|
145768
|
+
},
|
|
145769
|
+
{
|
|
145770
|
+
pattern: /\.\./,
|
|
145771
|
+
message: "Name cannot contain '..' (path traversal risk)"
|
|
145772
|
+
},
|
|
145773
|
+
{
|
|
145774
|
+
pattern: /^\./,
|
|
145775
|
+
message: "Name cannot start with '.' (hidden file pattern)"
|
|
145776
|
+
},
|
|
145777
|
+
{
|
|
145778
|
+
pattern: /\//,
|
|
145779
|
+
message: "Name cannot contain '/' (path separator)"
|
|
145780
|
+
},
|
|
145781
|
+
{
|
|
145782
|
+
pattern: /\\$/,
|
|
145783
|
+
message: "Name cannot end with backslash (escape sequence risk)"
|
|
145784
|
+
},
|
|
145785
|
+
{
|
|
145786
|
+
pattern: /\s/,
|
|
145787
|
+
message: "Name cannot contain whitespace"
|
|
145788
|
+
},
|
|
145789
|
+
{
|
|
145790
|
+
pattern: /^_/,
|
|
145791
|
+
message: "Name cannot start with underscore (reserved for internal use)"
|
|
145792
|
+
}
|
|
145793
|
+
];
|
|
145794
|
+
var DANGEROUS_COMMANDS = /* @__PURE__ */ new Set([
|
|
145795
|
+
// File destruction
|
|
145796
|
+
"rm",
|
|
145797
|
+
"rm-rf",
|
|
145798
|
+
"rmdir",
|
|
145799
|
+
"del",
|
|
145800
|
+
"unlink",
|
|
145801
|
+
"shred",
|
|
145802
|
+
// Privilege escalation
|
|
145803
|
+
"sudo",
|
|
145804
|
+
"su",
|
|
145805
|
+
"chmod",
|
|
145806
|
+
"chown",
|
|
145807
|
+
"chattr",
|
|
145808
|
+
"setfacl",
|
|
145809
|
+
// Network tools (payload download)
|
|
145810
|
+
"wget",
|
|
145811
|
+
"curl",
|
|
145812
|
+
"nc",
|
|
145813
|
+
"netcat",
|
|
145814
|
+
"socat",
|
|
145815
|
+
"telnet",
|
|
145816
|
+
"ssh",
|
|
145817
|
+
"scp",
|
|
145818
|
+
"rsync",
|
|
145819
|
+
// Shell execution
|
|
145820
|
+
"bash",
|
|
145821
|
+
"sh",
|
|
145822
|
+
"zsh",
|
|
145823
|
+
"csh",
|
|
145824
|
+
"ksh",
|
|
145825
|
+
"fish",
|
|
145826
|
+
"pwsh",
|
|
145827
|
+
"powershell",
|
|
145828
|
+
// Process execution
|
|
145829
|
+
"exec",
|
|
145830
|
+
"eval",
|
|
145831
|
+
"source",
|
|
145832
|
+
"nohup",
|
|
145833
|
+
"xargs",
|
|
145834
|
+
// Process termination
|
|
145835
|
+
"kill",
|
|
145836
|
+
"pkill",
|
|
145837
|
+
"killall",
|
|
145838
|
+
"killall5",
|
|
145839
|
+
// Disk operations
|
|
145840
|
+
"dd",
|
|
145841
|
+
"mkfs",
|
|
145842
|
+
"fdisk",
|
|
145843
|
+
"parted",
|
|
145844
|
+
"format",
|
|
145845
|
+
// System control
|
|
145846
|
+
"reboot",
|
|
145847
|
+
"shutdown",
|
|
145848
|
+
"halt",
|
|
145849
|
+
"poweroff",
|
|
145850
|
+
"init",
|
|
145851
|
+
"systemctl",
|
|
145852
|
+
// Container escape
|
|
145853
|
+
"docker",
|
|
145854
|
+
"kubectl",
|
|
145855
|
+
"nsenter",
|
|
145856
|
+
"chroot"
|
|
145857
|
+
]);
|
|
145858
|
+
var CONTROL_CHARS = /[\x00-\x1f\x7f]/;
|
|
145859
|
+
var RFC1035_PATTERN = /^[a-z]([a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
145860
|
+
|
|
145861
|
+
// src/validation/resource-name.ts
|
|
145862
|
+
var DEFAULT_OPTIONS = {
|
|
145863
|
+
maxLength: 63,
|
|
145864
|
+
allowUppercase: false,
|
|
145865
|
+
skipFormatValidation: false
|
|
145866
|
+
};
|
|
145867
|
+
function validateResourceName(name, options = {}) {
|
|
145868
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
145869
|
+
const nameLower = name.toLowerCase();
|
|
145870
|
+
if (!name || name.trim().length === 0) {
|
|
145871
|
+
return {
|
|
145872
|
+
valid: false,
|
|
145873
|
+
category: "invalid",
|
|
145874
|
+
message: "Resource name cannot be empty"
|
|
145875
|
+
};
|
|
145876
|
+
}
|
|
145877
|
+
if (name.length > opts.maxLength) {
|
|
145878
|
+
return {
|
|
145879
|
+
valid: false,
|
|
145880
|
+
category: "invalid",
|
|
145881
|
+
message: `Name exceeds maximum length of ${opts.maxLength} characters (got ${name.length})`,
|
|
145882
|
+
suggestion: sanitizeName(name.slice(0, opts.maxLength))
|
|
145883
|
+
};
|
|
145884
|
+
}
|
|
145885
|
+
if (CONTROL_CHARS.test(name)) {
|
|
145886
|
+
return {
|
|
145887
|
+
valid: false,
|
|
145888
|
+
category: "security",
|
|
145889
|
+
message: "Name contains control characters which are not allowed"
|
|
145890
|
+
};
|
|
145891
|
+
}
|
|
145892
|
+
if (SHELL_METACHARACTERS.test(name)) {
|
|
145893
|
+
const match = name.match(SHELL_METACHARACTERS);
|
|
145894
|
+
const char = match?.[0] ?? "unknown";
|
|
145895
|
+
const charDesc = getCharacterDescription(char);
|
|
145896
|
+
return {
|
|
145897
|
+
valid: false,
|
|
145898
|
+
category: "security",
|
|
145899
|
+
message: `Name contains shell metacharacter '${charDesc}' which could enable command injection`
|
|
145900
|
+
};
|
|
145901
|
+
}
|
|
145902
|
+
if (RESERVED_ACTIONS.has(nameLower)) {
|
|
145903
|
+
return {
|
|
145904
|
+
valid: false,
|
|
145905
|
+
category: "reserved",
|
|
145906
|
+
message: `'${name}' is a reserved CLI action word and cannot be used as a resource name`,
|
|
145907
|
+
suggestion: `my-${name}`
|
|
145908
|
+
};
|
|
145909
|
+
}
|
|
145910
|
+
if (DANGEROUS_COMMANDS.has(nameLower)) {
|
|
145911
|
+
return {
|
|
145912
|
+
valid: false,
|
|
145913
|
+
category: "dangerous",
|
|
145914
|
+
message: `'${name}' matches a dangerous system command and cannot be used as a resource name`
|
|
145915
|
+
};
|
|
145916
|
+
}
|
|
145917
|
+
for (const { pattern, message } of DANGEROUS_PATTERNS) {
|
|
145918
|
+
if (pattern.test(name)) {
|
|
145919
|
+
return {
|
|
145920
|
+
valid: false,
|
|
145921
|
+
category: "dangerous",
|
|
145922
|
+
message
|
|
145923
|
+
};
|
|
145924
|
+
}
|
|
145925
|
+
}
|
|
145926
|
+
if (!opts.skipFormatValidation) {
|
|
145927
|
+
const nameToCheck = opts.allowUppercase ? nameLower : name;
|
|
145928
|
+
if (!RFC1035_PATTERN.test(nameToCheck.toLowerCase())) {
|
|
145929
|
+
return {
|
|
145930
|
+
valid: false,
|
|
145931
|
+
category: "invalid",
|
|
145932
|
+
message: "Name must start with a letter, end with alphanumeric, and contain only lowercase letters, numbers, and hyphens",
|
|
145933
|
+
suggestion: sanitizeName(name)
|
|
145934
|
+
};
|
|
145935
|
+
}
|
|
145936
|
+
}
|
|
145937
|
+
return { valid: true };
|
|
145938
|
+
}
|
|
145939
|
+
function getCharacterDescription(char) {
|
|
145940
|
+
const descriptions = {
|
|
145941
|
+
";": "; (command separator)",
|
|
145942
|
+
"&": "& (background execution)",
|
|
145943
|
+
"|": "| (pipe)",
|
|
145944
|
+
"`": "` (command substitution)",
|
|
145945
|
+
$: "$ (variable/command expansion)",
|
|
145946
|
+
"(": "( (subshell)",
|
|
145947
|
+
")": ") (subshell)",
|
|
145948
|
+
"<": "< (input redirection)",
|
|
145949
|
+
">": "> (output redirection)",
|
|
145950
|
+
"\\": "\\ (escape)",
|
|
145951
|
+
"#": "# (comment)",
|
|
145952
|
+
"!": "! (history expansion)",
|
|
145953
|
+
"{": "{ (brace expansion)",
|
|
145954
|
+
"}": "} (brace expansion)",
|
|
145955
|
+
"[": "[ (bracket expansion)",
|
|
145956
|
+
"]": "] (bracket expansion)",
|
|
145957
|
+
"*": "* (glob pattern)",
|
|
145958
|
+
"?": "? (glob pattern)",
|
|
145959
|
+
"~": "~ (home directory)",
|
|
145960
|
+
"\n": "newline",
|
|
145961
|
+
"\r": "carriage return"
|
|
145962
|
+
};
|
|
145963
|
+
return descriptions[char] ?? char;
|
|
145964
|
+
}
|
|
145965
|
+
function sanitizeName(name) {
|
|
145966
|
+
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^[^a-z]+/, "").replace(/-+$/, "").replace(/-{2,}/g, "-").slice(0, 63) || "resource";
|
|
145967
|
+
}
|
|
145968
|
+
|
|
145588
145969
|
// src/domains/login/profile/create.ts
|
|
145589
145970
|
var createCommand2 = {
|
|
145590
145971
|
name: "create",
|
|
@@ -145611,6 +145992,18 @@ var createCommand2 = {
|
|
|
145611
145992
|
].join("\n")
|
|
145612
145993
|
);
|
|
145613
145994
|
}
|
|
145995
|
+
const nameValidation = validateResourceName(name, {
|
|
145996
|
+
maxLength: 128,
|
|
145997
|
+
// Profiles can have longer names than API resources
|
|
145998
|
+
resourceType: "profile"
|
|
145999
|
+
});
|
|
146000
|
+
if (!nameValidation.valid) {
|
|
146001
|
+
const lines = [`Invalid profile name: ${nameValidation.message}`];
|
|
146002
|
+
if (nameValidation.suggestion) {
|
|
146003
|
+
lines.push("", `Suggested: ${nameValidation.suggestion}`);
|
|
146004
|
+
}
|
|
146005
|
+
return errorResult(lines.join("\n"));
|
|
146006
|
+
}
|
|
145614
146007
|
const existing = await manager.get(name);
|
|
145615
146008
|
if (existing) {
|
|
145616
146009
|
return errorResult(
|
|
@@ -148271,7 +148664,7 @@ var queryCommand = {
|
|
|
148271
148664
|
// src/domains/ai_services/chat.ts
|
|
148272
148665
|
import * as readline from "readline";
|
|
148273
148666
|
function parseChatArgs(args, session) {
|
|
148274
|
-
const { remainingArgs } = parseDomainOutputFlags(
|
|
148667
|
+
const { options, remainingArgs } = parseDomainOutputFlags(
|
|
148275
148668
|
args,
|
|
148276
148669
|
session.getOutputFormat()
|
|
148277
148670
|
);
|
|
@@ -148290,7 +148683,11 @@ function parseChatArgs(args, session) {
|
|
|
148290
148683
|
}
|
|
148291
148684
|
i++;
|
|
148292
148685
|
}
|
|
148293
|
-
return {
|
|
148686
|
+
return {
|
|
148687
|
+
spec,
|
|
148688
|
+
namespace,
|
|
148689
|
+
suppressOutput: options.format === "none"
|
|
148690
|
+
};
|
|
148294
148691
|
}
|
|
148295
148692
|
function showChatHelp() {
|
|
148296
148693
|
return [
|
|
@@ -148505,13 +148902,19 @@ var chatCommand = {
|
|
|
148505
148902
|
usage: "[--namespace <ns>]",
|
|
148506
148903
|
aliases: ["interactive", "i"],
|
|
148507
148904
|
async execute(args, session) {
|
|
148508
|
-
const { spec, namespace } = parseChatArgs(
|
|
148905
|
+
const { spec, namespace, suppressOutput } = parseChatArgs(
|
|
148906
|
+
args,
|
|
148907
|
+
session
|
|
148908
|
+
);
|
|
148509
148909
|
if (spec) {
|
|
148510
148910
|
const cmdSpec = getCommandSpec("generative_ai chat");
|
|
148511
148911
|
if (cmdSpec) {
|
|
148512
148912
|
return successResult([formatSpec(cmdSpec)]);
|
|
148513
148913
|
}
|
|
148514
148914
|
}
|
|
148915
|
+
if (suppressOutput) {
|
|
148916
|
+
return successResult([]);
|
|
148917
|
+
}
|
|
148515
148918
|
if (!process.stdin.isTTY) {
|
|
148516
148919
|
return errorResult(
|
|
148517
148920
|
"Chat mode requires an interactive terminal. Use 'ai query' for non-interactive queries."
|
|
@@ -148529,7 +148932,7 @@ var chatCommand = {
|
|
|
148529
148932
|
|
|
148530
148933
|
// src/domains/ai_services/feedback.ts
|
|
148531
148934
|
function parseFeedbackArgs(args, session) {
|
|
148532
|
-
const { remainingArgs } = parseDomainOutputFlags(
|
|
148935
|
+
const { options, remainingArgs } = parseDomainOutputFlags(
|
|
148533
148936
|
args,
|
|
148534
148937
|
session.getOutputFormat()
|
|
148535
148938
|
);
|
|
@@ -148577,6 +148980,8 @@ function parseFeedbackArgs(args, session) {
|
|
|
148577
148980
|
i++;
|
|
148578
148981
|
}
|
|
148579
148982
|
return {
|
|
148983
|
+
format: options.format,
|
|
148984
|
+
noColor: options.noColor,
|
|
148580
148985
|
spec,
|
|
148581
148986
|
namespace,
|
|
148582
148987
|
positive,
|
|
@@ -148593,13 +148998,25 @@ var feedbackCommand = {
|
|
|
148593
148998
|
usage: "--positive | --negative <type> [--comment <text>] [--query-id <id>]",
|
|
148594
148999
|
aliases: ["fb", "rate"],
|
|
148595
149000
|
async execute(args, session) {
|
|
148596
|
-
const {
|
|
149001
|
+
const {
|
|
149002
|
+
format,
|
|
149003
|
+
noColor,
|
|
149004
|
+
spec,
|
|
149005
|
+
namespace,
|
|
149006
|
+
positive,
|
|
149007
|
+
negativeType,
|
|
149008
|
+
comment,
|
|
149009
|
+
queryId
|
|
149010
|
+
} = parseFeedbackArgs(args, session);
|
|
148597
149011
|
if (spec) {
|
|
148598
149012
|
const cmdSpec = getCommandSpec("generative_ai feedback");
|
|
148599
149013
|
if (cmdSpec) {
|
|
148600
149014
|
return successResult([formatSpec(cmdSpec)]);
|
|
148601
149015
|
}
|
|
148602
149016
|
}
|
|
149017
|
+
if (format === "none") {
|
|
149018
|
+
return successResult([]);
|
|
149019
|
+
}
|
|
148603
149020
|
if (!positive && !negativeType) {
|
|
148604
149021
|
const validTypes = getValidFeedbackTypes().join(", ");
|
|
148605
149022
|
return errorResult(
|
|
@@ -148644,6 +149061,17 @@ Negative types: ${validTypes}`
|
|
|
148644
149061
|
positive_feedback: {},
|
|
148645
149062
|
comment: comment ?? void 0
|
|
148646
149063
|
});
|
|
149064
|
+
const result2 = {
|
|
149065
|
+
status: "success",
|
|
149066
|
+
type: "positive",
|
|
149067
|
+
query_id: targetQueryId,
|
|
149068
|
+
message: "Positive feedback submitted successfully."
|
|
149069
|
+
};
|
|
149070
|
+
if (format === "json" || format === "yaml" || format === "tsv") {
|
|
149071
|
+
return successResult(
|
|
149072
|
+
formatDomainOutput(result2, { format, noColor })
|
|
149073
|
+
);
|
|
149074
|
+
}
|
|
148647
149075
|
return successResult([
|
|
148648
149076
|
"Positive feedback submitted successfully.",
|
|
148649
149077
|
`Query ID: ${targetQueryId}`
|
|
@@ -148658,6 +149086,19 @@ Negative types: ${validTypes}`
|
|
|
148658
149086
|
},
|
|
148659
149087
|
comment: comment ?? void 0
|
|
148660
149088
|
});
|
|
149089
|
+
const result = {
|
|
149090
|
+
status: "success",
|
|
149091
|
+
type: "negative",
|
|
149092
|
+
query_id: targetQueryId,
|
|
149093
|
+
reason: negativeType ?? "OTHER",
|
|
149094
|
+
...comment ? { comment } : {},
|
|
149095
|
+
message: "Negative feedback submitted successfully."
|
|
149096
|
+
};
|
|
149097
|
+
if (format === "json" || format === "yaml" || format === "tsv") {
|
|
149098
|
+
return successResult(
|
|
149099
|
+
formatDomainOutput(result, { format, noColor })
|
|
149100
|
+
);
|
|
149101
|
+
}
|
|
148661
149102
|
return successResult([
|
|
148662
149103
|
"Negative feedback submitted successfully.",
|
|
148663
149104
|
`Query ID: ${targetQueryId}`,
|
|
@@ -148909,13 +149350,94 @@ var evalSubcommands = {
|
|
|
148909
149350
|
defaultCommand: evalQueryCommand
|
|
148910
149351
|
};
|
|
148911
149352
|
|
|
149353
|
+
// src/domains/domain-overview.ts
|
|
149354
|
+
function formatDomainOverview(config) {
|
|
149355
|
+
const lines = [];
|
|
149356
|
+
lines.push("");
|
|
149357
|
+
lines.push(`${config.name} - ${config.description}`);
|
|
149358
|
+
lines.push("");
|
|
149359
|
+
if (config.commands.length > 0) {
|
|
149360
|
+
lines.push("Commands:");
|
|
149361
|
+
const maxNameLen = Math.max(
|
|
149362
|
+
...config.commands.map((cmd) => cmd.name.length)
|
|
149363
|
+
);
|
|
149364
|
+
const padding = Math.min(maxNameLen + 2, 20);
|
|
149365
|
+
for (const cmd of config.commands) {
|
|
149366
|
+
lines.push(` ${cmd.name.padEnd(padding)} ${cmd.description}`);
|
|
149367
|
+
}
|
|
149368
|
+
lines.push("");
|
|
149369
|
+
}
|
|
149370
|
+
if (config.examples.length > 0) {
|
|
149371
|
+
lines.push("Examples:");
|
|
149372
|
+
for (const example of config.examples) {
|
|
149373
|
+
lines.push(` ${example}`);
|
|
149374
|
+
}
|
|
149375
|
+
lines.push("");
|
|
149376
|
+
}
|
|
149377
|
+
if (config.supportsOutputFormats) {
|
|
149378
|
+
lines.push("Output formats: --output json|yaml|table|tsv|none");
|
|
149379
|
+
lines.push("");
|
|
149380
|
+
}
|
|
149381
|
+
if (config.notes && config.notes.length > 0) {
|
|
149382
|
+
for (const note of config.notes) {
|
|
149383
|
+
lines.push(note);
|
|
149384
|
+
}
|
|
149385
|
+
lines.push("");
|
|
149386
|
+
}
|
|
149387
|
+
return lines;
|
|
149388
|
+
}
|
|
149389
|
+
|
|
148912
149390
|
// src/domains/ai_services/index.ts
|
|
149391
|
+
var entryCommand = {
|
|
149392
|
+
name: "ai_services",
|
|
149393
|
+
description: "AI-powered query and chat services for F5 Distributed Cloud",
|
|
149394
|
+
descriptionShort: "AI assistant queries and feedback",
|
|
149395
|
+
descriptionMedium: "Query the AI assistant for help with F5 XC platform operations, configurations, and troubleshooting.",
|
|
149396
|
+
async execute(args, session) {
|
|
149397
|
+
const hasQuestion = args.length > 0 && !args[0]?.startsWith("--");
|
|
149398
|
+
if (hasQuestion) {
|
|
149399
|
+
return queryCommand.execute(args, session);
|
|
149400
|
+
}
|
|
149401
|
+
const overview = formatDomainOverview({
|
|
149402
|
+
name: "AI Services",
|
|
149403
|
+
description: "Query and chat with the F5 XC AI assistant",
|
|
149404
|
+
commands: [
|
|
149405
|
+
{
|
|
149406
|
+
name: "query <question>",
|
|
149407
|
+
description: "Ask a single question"
|
|
149408
|
+
},
|
|
149409
|
+
{
|
|
149410
|
+
name: "chat",
|
|
149411
|
+
description: "Start interactive chat session"
|
|
149412
|
+
},
|
|
149413
|
+
{
|
|
149414
|
+
name: "feedback",
|
|
149415
|
+
description: "Provide feedback on AI responses"
|
|
149416
|
+
}
|
|
149417
|
+
],
|
|
149418
|
+
examples: [
|
|
149419
|
+
"query 'How do I create an HTTP load balancer?'",
|
|
149420
|
+
"query 'What is my WAF policy configuration?' --namespace prod",
|
|
149421
|
+
"chat",
|
|
149422
|
+
"feedback positive"
|
|
149423
|
+
],
|
|
149424
|
+
supportsOutputFormats: true,
|
|
149425
|
+
notes: ["Use 'eval' subcommand for AI evaluation testing."]
|
|
149426
|
+
});
|
|
149427
|
+
return {
|
|
149428
|
+
output: overview,
|
|
149429
|
+
contextChanged: true,
|
|
149430
|
+
shouldExit: false,
|
|
149431
|
+
shouldClear: false
|
|
149432
|
+
};
|
|
149433
|
+
}
|
|
149434
|
+
};
|
|
148913
149435
|
var aiServicesDomain = {
|
|
148914
149436
|
name: "ai_services",
|
|
148915
149437
|
description: "Interact with the F5 Distributed Cloud AI assistant for natural language queries about platform operations. Ask questions about load balancers, WAF configurations, site status, security events, or any platform topic. Supports single queries with follow-up suggestions, interactive multi-turn chat sessions, and feedback submission to improve AI responses.",
|
|
148916
149438
|
descriptionShort: "AI assistant queries and feedback",
|
|
148917
149439
|
descriptionMedium: "Query the AI assistant for help with F5 XC platform operations, configurations, security analysis, and troubleshooting.",
|
|
148918
|
-
defaultCommand:
|
|
149440
|
+
defaultCommand: entryCommand,
|
|
148919
149441
|
commands: /* @__PURE__ */ new Map([
|
|
148920
149442
|
["query", queryCommand],
|
|
148921
149443
|
["chat", chatCommand],
|
|
@@ -150510,13 +151032,13 @@ var RESERVED_API_ACTIONS = /* @__PURE__ */ new Set([
|
|
|
150510
151032
|
"add-labels",
|
|
150511
151033
|
"remove-labels"
|
|
150512
151034
|
]);
|
|
150513
|
-
function
|
|
151035
|
+
function isReservedAction2(name) {
|
|
150514
151036
|
return RESERVED_API_ACTIONS.has(name.toLowerCase());
|
|
150515
151037
|
}
|
|
150516
151038
|
function validateExtension(extension) {
|
|
150517
151039
|
const conflicts = [];
|
|
150518
151040
|
for (const [name] of extension.commands) {
|
|
150519
|
-
if (
|
|
151041
|
+
if (isReservedAction2(name)) {
|
|
150520
151042
|
conflicts.push(name);
|
|
150521
151043
|
}
|
|
150522
151044
|
}
|
|
@@ -151861,114 +152383,15 @@ function useGitStatus(options = {}) {
|
|
|
151861
152383
|
return { gitInfo, refresh, lastRefresh };
|
|
151862
152384
|
}
|
|
151863
152385
|
|
|
151864
|
-
// src/validation/namespace.ts
|
|
151865
|
-
function validateNamespaceScope(domain, action, currentNamespace, resourceType) {
|
|
151866
|
-
const opInfo = getOperationDescription(domain, action, resourceType);
|
|
151867
|
-
if (!opInfo?.namespaceScope) {
|
|
151868
|
-
return { valid: true };
|
|
151869
|
-
}
|
|
151870
|
-
const scope = opInfo.namespaceScope;
|
|
151871
|
-
const normalizedNamespace = currentNamespace.toLowerCase();
|
|
151872
|
-
switch (scope) {
|
|
151873
|
-
case "system":
|
|
151874
|
-
if (normalizedNamespace !== "system") {
|
|
151875
|
-
return {
|
|
151876
|
-
valid: false,
|
|
151877
|
-
scope,
|
|
151878
|
-
message: `${action} on ${resourceType || domain} requires the 'system' namespace`,
|
|
151879
|
-
suggestion: "system"
|
|
151880
|
-
};
|
|
151881
|
-
}
|
|
151882
|
-
return { valid: true, scope };
|
|
151883
|
-
case "shared":
|
|
151884
|
-
if (normalizedNamespace !== "shared") {
|
|
151885
|
-
return {
|
|
151886
|
-
valid: false,
|
|
151887
|
-
scope,
|
|
151888
|
-
message: `${action} on ${resourceType || domain} requires the 'shared' namespace`,
|
|
151889
|
-
suggestion: "shared"
|
|
151890
|
-
};
|
|
151891
|
-
}
|
|
151892
|
-
return { valid: true, scope };
|
|
151893
|
-
case "any":
|
|
151894
|
-
default:
|
|
151895
|
-
return { valid: true, scope };
|
|
151896
|
-
}
|
|
151897
|
-
}
|
|
151898
|
-
|
|
151899
|
-
// src/validation/safety.ts
|
|
151900
|
-
function checkOperationSafety(domain, action, resourceType) {
|
|
151901
|
-
const opInfo = getOperationDescription(domain, action, resourceType);
|
|
151902
|
-
const dangerLevel = opInfo?.dangerLevel || "low";
|
|
151903
|
-
const requiresConfirmation2 = opInfo?.confirmationRequired ?? dangerLevel === "high";
|
|
151904
|
-
const sideEffects = opInfo?.sideEffects;
|
|
151905
|
-
const result = {
|
|
151906
|
-
proceed: dangerLevel !== "high",
|
|
151907
|
-
// High danger requires explicit confirmation
|
|
151908
|
-
dangerLevel,
|
|
151909
|
-
requiresConfirmation: requiresConfirmation2
|
|
151910
|
-
};
|
|
151911
|
-
if (dangerLevel === "high") {
|
|
151912
|
-
result.warning = formatHighDangerWarning(domain, action, sideEffects);
|
|
151913
|
-
} else if (dangerLevel === "medium") {
|
|
151914
|
-
result.warning = formatMediumDangerWarning(domain, action, sideEffects);
|
|
151915
|
-
}
|
|
151916
|
-
if (sideEffects) {
|
|
151917
|
-
result.sideEffects = sideEffects;
|
|
151918
|
-
}
|
|
151919
|
-
return result;
|
|
151920
|
-
}
|
|
151921
|
-
function formatHighDangerWarning(_domain, _action, sideEffects) {
|
|
151922
|
-
const lines = [
|
|
151923
|
-
colorRed("\u26A0\uFE0F WARNING: This is a HIGH DANGER operation"),
|
|
151924
|
-
""
|
|
151925
|
-
];
|
|
151926
|
-
if (sideEffects) {
|
|
151927
|
-
if (sideEffects.deletes && sideEffects.deletes.length > 0) {
|
|
151928
|
-
lines.push(
|
|
151929
|
-
colorRed(` Will DELETE: ${sideEffects.deletes.join(", ")}`)
|
|
151930
|
-
);
|
|
151931
|
-
}
|
|
151932
|
-
if (sideEffects.updates && sideEffects.updates.length > 0) {
|
|
151933
|
-
lines.push(` Will UPDATE: ${sideEffects.updates.join(", ")}`);
|
|
151934
|
-
}
|
|
151935
|
-
if (sideEffects.creates && sideEffects.creates.length > 0) {
|
|
151936
|
-
lines.push(
|
|
151937
|
-
colorDim(` Will CREATE: ${sideEffects.creates.join(", ")}`)
|
|
151938
|
-
);
|
|
151939
|
-
}
|
|
151940
|
-
lines.push("");
|
|
151941
|
-
}
|
|
151942
|
-
lines.push(
|
|
151943
|
-
colorRed("This action may be destructive and cannot be undone.")
|
|
151944
|
-
);
|
|
151945
|
-
return lines.join("\n");
|
|
151946
|
-
}
|
|
151947
|
-
function formatMediumDangerWarning(_domain, _action, sideEffects) {
|
|
151948
|
-
const lines = [
|
|
151949
|
-
colorYellow("\u26A0\uFE0F CAUTION: This operation may have significant effects"),
|
|
151950
|
-
""
|
|
151951
|
-
];
|
|
151952
|
-
if (sideEffects) {
|
|
151953
|
-
const effects = [];
|
|
151954
|
-
if (sideEffects.creates && sideEffects.creates.length > 0) {
|
|
151955
|
-
effects.push(`creates: ${sideEffects.creates.join(", ")}`);
|
|
151956
|
-
}
|
|
151957
|
-
if (sideEffects.updates && sideEffects.updates.length > 0) {
|
|
151958
|
-
effects.push(`updates: ${sideEffects.updates.join(", ")}`);
|
|
151959
|
-
}
|
|
151960
|
-
if (sideEffects.deletes && sideEffects.deletes.length > 0) {
|
|
151961
|
-
effects.push(`deletes: ${sideEffects.deletes.join(", ")}`);
|
|
151962
|
-
}
|
|
151963
|
-
if (effects.length > 0) {
|
|
151964
|
-
lines.push(` Side effects: ${effects.join("; ")}`);
|
|
151965
|
-
lines.push("");
|
|
151966
|
-
}
|
|
151967
|
-
}
|
|
151968
|
-
return lines.join("\n");
|
|
151969
|
-
}
|
|
151970
|
-
|
|
151971
152386
|
// src/repl/executor.ts
|
|
152387
|
+
var WRITE_OPERATIONS = /* @__PURE__ */ new Set([
|
|
152388
|
+
"create",
|
|
152389
|
+
"replace",
|
|
152390
|
+
"apply",
|
|
152391
|
+
"patch",
|
|
152392
|
+
"add-labels",
|
|
152393
|
+
"remove-labels"
|
|
152394
|
+
]);
|
|
151972
152395
|
var BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
|
|
151973
152396
|
"help",
|
|
151974
152397
|
"--help",
|
|
@@ -152653,6 +153076,50 @@ async function executeAPICommand(session, ctx, cmd) {
|
|
|
152653
153076
|
);
|
|
152654
153077
|
const { resourceType, name, namespace, outputFormat, spec, noColor } = parseCommandArgs(args, domainResourceTypes);
|
|
152655
153078
|
const effectiveNamespace = namespace ?? session.getNamespace();
|
|
153079
|
+
if (effectiveNamespace) {
|
|
153080
|
+
const nsNameValidation = validateResourceName(effectiveNamespace, {
|
|
153081
|
+
resourceType: "namespace"
|
|
153082
|
+
});
|
|
153083
|
+
if (!nsNameValidation.valid) {
|
|
153084
|
+
const lines = [
|
|
153085
|
+
`Error: Invalid namespace name '${effectiveNamespace}'`,
|
|
153086
|
+
"",
|
|
153087
|
+
nsNameValidation.message ?? "Invalid namespace name"
|
|
153088
|
+
];
|
|
153089
|
+
if (nsNameValidation.suggestion) {
|
|
153090
|
+
lines.push("", `Suggested: ${nsNameValidation.suggestion}`);
|
|
153091
|
+
}
|
|
153092
|
+
return {
|
|
153093
|
+
output: lines,
|
|
153094
|
+
shouldExit: false,
|
|
153095
|
+
shouldClear: false,
|
|
153096
|
+
contextChanged: false,
|
|
153097
|
+
error: nsNameValidation.message ?? "Invalid namespace name"
|
|
153098
|
+
};
|
|
153099
|
+
}
|
|
153100
|
+
}
|
|
153101
|
+
if (WRITE_OPERATIONS.has(action) && name) {
|
|
153102
|
+
const nameValidation = validateResourceName(name, {
|
|
153103
|
+
resourceType: resourceType ?? canonicalDomain
|
|
153104
|
+
});
|
|
153105
|
+
if (!nameValidation.valid) {
|
|
153106
|
+
const lines = [
|
|
153107
|
+
`Error: Invalid resource name '${name}'`,
|
|
153108
|
+
"",
|
|
153109
|
+
nameValidation.message ?? "Invalid resource name"
|
|
153110
|
+
];
|
|
153111
|
+
if (nameValidation.suggestion) {
|
|
153112
|
+
lines.push("", `Suggested: ${nameValidation.suggestion}`);
|
|
153113
|
+
}
|
|
153114
|
+
return {
|
|
153115
|
+
output: lines,
|
|
153116
|
+
shouldExit: false,
|
|
153117
|
+
shouldClear: false,
|
|
153118
|
+
contextChanged: false,
|
|
153119
|
+
error: nameValidation.message ?? "Invalid resource name"
|
|
153120
|
+
};
|
|
153121
|
+
}
|
|
153122
|
+
}
|
|
152656
153123
|
const effectiveResource = resourceType ?? canonicalDomain;
|
|
152657
153124
|
const nsValidation = validateNamespaceScope(
|
|
152658
153125
|
canonicalDomain,
|