@robinmordasiewicz/f5xc-xcsh 2.0.21-2601090318 → 2.0.21-2601090340
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/completions/xcsh.bash +1 -1
- package/completions/xcsh.fish +1 -0
- package/dist/index.js +220 -14
- package/package.json +1 -1
package/completions/xcsh.bash
CHANGED
package/completions/xcsh.fish
CHANGED
|
@@ -90,6 +90,7 @@ complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcomma
|
|
|
90
90
|
complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from profile" -a "show" -d 'Show profile details (masked credentials)'
|
|
91
91
|
complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from profile" -a "create" -d 'Create a new connection profile'
|
|
92
92
|
complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from profile" -a "use" -d 'Switch to a different profile'
|
|
93
|
+
complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from profile" -a "edit" -d 'Edit profile in $EDITOR'
|
|
93
94
|
complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from profile" -a "delete" -d 'Delete a saved profile'
|
|
94
95
|
complete -c xcsh -n "__fish_seen_subcommand_from login" -a "context" -d 'Manage default namespace context'
|
|
95
96
|
complete -c xcsh -n "__fish_seen_subcommand_from login; and __fish_seen_subcommand_from context" -a "show" -d 'Show current default namespace'
|
package/dist/index.js
CHANGED
|
@@ -28134,7 +28134,7 @@ var require_command = __commonJS({
|
|
|
28134
28134
|
var EventEmitter3 = __require("events").EventEmitter;
|
|
28135
28135
|
var childProcess = __require("child_process");
|
|
28136
28136
|
var path = __require("path");
|
|
28137
|
-
var
|
|
28137
|
+
var fs4 = __require("fs");
|
|
28138
28138
|
var process13 = __require("process");
|
|
28139
28139
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
28140
28140
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -29067,10 +29067,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29067
29067
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
29068
29068
|
function findFile(baseDir, baseName) {
|
|
29069
29069
|
const localBin = path.resolve(baseDir, baseName);
|
|
29070
|
-
if (
|
|
29070
|
+
if (fs4.existsSync(localBin)) return localBin;
|
|
29071
29071
|
if (sourceExt.includes(path.extname(baseName))) return void 0;
|
|
29072
29072
|
const foundExt = sourceExt.find(
|
|
29073
|
-
(ext) =>
|
|
29073
|
+
(ext) => fs4.existsSync(`${localBin}${ext}`)
|
|
29074
29074
|
);
|
|
29075
29075
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
29076
29076
|
return void 0;
|
|
@@ -29082,7 +29082,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
29082
29082
|
if (this._scriptPath) {
|
|
29083
29083
|
let resolvedScriptPath;
|
|
29084
29084
|
try {
|
|
29085
|
-
resolvedScriptPath =
|
|
29085
|
+
resolvedScriptPath = fs4.realpathSync(this._scriptPath);
|
|
29086
29086
|
} catch (err) {
|
|
29087
29087
|
resolvedScriptPath = this._scriptPath;
|
|
29088
29088
|
}
|
|
@@ -37034,14 +37034,14 @@ var require_parser = __commonJS({
|
|
|
37034
37034
|
case "scalar":
|
|
37035
37035
|
case "single-quoted-scalar":
|
|
37036
37036
|
case "double-quoted-scalar": {
|
|
37037
|
-
const
|
|
37037
|
+
const fs4 = this.flowScalar(this.type);
|
|
37038
37038
|
if (atNextItem || it.value) {
|
|
37039
|
-
map.items.push({ start, key:
|
|
37039
|
+
map.items.push({ start, key: fs4, sep: [] });
|
|
37040
37040
|
this.onKeyLine = true;
|
|
37041
37041
|
} else if (it.sep) {
|
|
37042
|
-
this.stack.push(
|
|
37042
|
+
this.stack.push(fs4);
|
|
37043
37043
|
} else {
|
|
37044
|
-
Object.assign(it, { key:
|
|
37044
|
+
Object.assign(it, { key: fs4, sep: [] });
|
|
37045
37045
|
this.onKeyLine = true;
|
|
37046
37046
|
}
|
|
37047
37047
|
return;
|
|
@@ -37169,13 +37169,13 @@ var require_parser = __commonJS({
|
|
|
37169
37169
|
case "scalar":
|
|
37170
37170
|
case "single-quoted-scalar":
|
|
37171
37171
|
case "double-quoted-scalar": {
|
|
37172
|
-
const
|
|
37172
|
+
const fs4 = this.flowScalar(this.type);
|
|
37173
37173
|
if (!it || it.value)
|
|
37174
|
-
fc.items.push({ start: [], key:
|
|
37174
|
+
fc.items.push({ start: [], key: fs4, sep: [] });
|
|
37175
37175
|
else if (it.sep)
|
|
37176
|
-
this.stack.push(
|
|
37176
|
+
this.stack.push(fs4);
|
|
37177
37177
|
else
|
|
37178
|
-
Object.assign(it, { key:
|
|
37178
|
+
Object.assign(it, { key: fs4, sep: [] });
|
|
37179
37179
|
return;
|
|
37180
37180
|
}
|
|
37181
37181
|
case "flow-map-end":
|
|
@@ -46994,8 +46994,8 @@ function getLogoModeFromEnv(envPrefix) {
|
|
|
46994
46994
|
var CLI_NAME = "xcsh";
|
|
46995
46995
|
var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
|
|
46996
46996
|
function getVersion() {
|
|
46997
|
-
if ("v2.0.21-
|
|
46998
|
-
return "v2.0.21-
|
|
46997
|
+
if ("v2.0.21-2601090340") {
|
|
46998
|
+
return "v2.0.21-2601090340";
|
|
46999
46999
|
}
|
|
47000
47000
|
if (process.env.XCSH_VERSION) {
|
|
47001
47001
|
return process.env.XCSH_VERSION;
|
|
@@ -75423,6 +75423,211 @@ var deleteCommand = {
|
|
|
75423
75423
|
}
|
|
75424
75424
|
};
|
|
75425
75425
|
|
|
75426
|
+
// src/domains/login/profile/edit.ts
|
|
75427
|
+
import { spawn } from "child_process";
|
|
75428
|
+
import { promises as fs3 } from "fs";
|
|
75429
|
+
import { tmpdir } from "os";
|
|
75430
|
+
import { join as join4 } from "path";
|
|
75431
|
+
function getEditor() {
|
|
75432
|
+
return process.env.EDITOR || process.env.VISUAL || "vi";
|
|
75433
|
+
}
|
|
75434
|
+
async function openInEditor(filePath) {
|
|
75435
|
+
const editor = getEditor();
|
|
75436
|
+
return new Promise((resolve, reject) => {
|
|
75437
|
+
const child = spawn(editor, [filePath], {
|
|
75438
|
+
stdio: "inherit",
|
|
75439
|
+
shell: true
|
|
75440
|
+
});
|
|
75441
|
+
child.on("error", (error) => {
|
|
75442
|
+
reject(
|
|
75443
|
+
new Error(
|
|
75444
|
+
`Failed to launch editor '${editor}': ${error.message}`
|
|
75445
|
+
)
|
|
75446
|
+
);
|
|
75447
|
+
});
|
|
75448
|
+
child.on("exit", (code) => {
|
|
75449
|
+
if (code === 0) {
|
|
75450
|
+
resolve();
|
|
75451
|
+
} else {
|
|
75452
|
+
reject(new Error(`Editor exited with code ${code}`));
|
|
75453
|
+
}
|
|
75454
|
+
});
|
|
75455
|
+
});
|
|
75456
|
+
}
|
|
75457
|
+
async function createTempFile(profile) {
|
|
75458
|
+
const tempDir = tmpdir();
|
|
75459
|
+
const tempFile = join4(
|
|
75460
|
+
tempDir,
|
|
75461
|
+
`xcsh-profile-${profile.name}-${Date.now()}.json`
|
|
75462
|
+
);
|
|
75463
|
+
const content = JSON.stringify(
|
|
75464
|
+
{
|
|
75465
|
+
name: profile.name,
|
|
75466
|
+
apiUrl: profile.apiUrl,
|
|
75467
|
+
apiToken: profile.apiToken || "",
|
|
75468
|
+
defaultNamespace: profile.defaultNamespace || "",
|
|
75469
|
+
// Include optional fields only if they exist
|
|
75470
|
+
...profile.p12Bundle ? { p12Bundle: profile.p12Bundle } : {},
|
|
75471
|
+
...profile.cert ? { cert: profile.cert } : {},
|
|
75472
|
+
...profile.key ? { key: profile.key } : {}
|
|
75473
|
+
},
|
|
75474
|
+
null,
|
|
75475
|
+
2
|
|
75476
|
+
);
|
|
75477
|
+
await fs3.writeFile(tempFile, content, { mode: 384 });
|
|
75478
|
+
return tempFile;
|
|
75479
|
+
}
|
|
75480
|
+
async function parseEditedProfile(filePath, originalName) {
|
|
75481
|
+
try {
|
|
75482
|
+
const content = await fs3.readFile(filePath, "utf-8");
|
|
75483
|
+
const parsed = JSON.parse(content);
|
|
75484
|
+
if (!parsed.name || typeof parsed.name !== "string") {
|
|
75485
|
+
return { profile: null, error: "Profile name is required" };
|
|
75486
|
+
}
|
|
75487
|
+
if (!parsed.apiUrl || typeof parsed.apiUrl !== "string") {
|
|
75488
|
+
return { profile: null, error: "API URL is required" };
|
|
75489
|
+
}
|
|
75490
|
+
if (parsed.name !== originalName) {
|
|
75491
|
+
return {
|
|
75492
|
+
profile: null,
|
|
75493
|
+
error: `Cannot change profile name from '${originalName}' to '${parsed.name}'. Use 'login profile create' to create a new profile instead.`
|
|
75494
|
+
};
|
|
75495
|
+
}
|
|
75496
|
+
const profile = {
|
|
75497
|
+
name: parsed.name,
|
|
75498
|
+
apiUrl: parsed.apiUrl
|
|
75499
|
+
};
|
|
75500
|
+
if (parsed.apiToken && typeof parsed.apiToken === "string" && parsed.apiToken.trim()) {
|
|
75501
|
+
profile.apiToken = parsed.apiToken.trim();
|
|
75502
|
+
}
|
|
75503
|
+
if (parsed.defaultNamespace && typeof parsed.defaultNamespace === "string" && parsed.defaultNamespace.trim()) {
|
|
75504
|
+
profile.defaultNamespace = parsed.defaultNamespace.trim();
|
|
75505
|
+
}
|
|
75506
|
+
if (parsed.p12Bundle && typeof parsed.p12Bundle === "string" && parsed.p12Bundle.trim()) {
|
|
75507
|
+
profile.p12Bundle = parsed.p12Bundle.trim();
|
|
75508
|
+
}
|
|
75509
|
+
if (parsed.cert && typeof parsed.cert === "string" && parsed.cert.trim()) {
|
|
75510
|
+
profile.cert = parsed.cert.trim();
|
|
75511
|
+
}
|
|
75512
|
+
if (parsed.key && typeof parsed.key === "string" && parsed.key.trim()) {
|
|
75513
|
+
profile.key = parsed.key.trim();
|
|
75514
|
+
}
|
|
75515
|
+
return { profile, error: null };
|
|
75516
|
+
} catch (error) {
|
|
75517
|
+
if (error instanceof SyntaxError) {
|
|
75518
|
+
return { profile: null, error: `Invalid JSON: ${error.message}` };
|
|
75519
|
+
}
|
|
75520
|
+
return {
|
|
75521
|
+
profile: null,
|
|
75522
|
+
error: `Failed to read edited file: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
75523
|
+
};
|
|
75524
|
+
}
|
|
75525
|
+
}
|
|
75526
|
+
async function cleanupTempFile(filePath) {
|
|
75527
|
+
try {
|
|
75528
|
+
await fs3.unlink(filePath);
|
|
75529
|
+
} catch {
|
|
75530
|
+
}
|
|
75531
|
+
}
|
|
75532
|
+
var editCommand = {
|
|
75533
|
+
name: "edit",
|
|
75534
|
+
description: "Edit a profile configuration using your preferred text editor ($EDITOR). Opens the profile in JSON format for modification. After saving, the profile is validated and updated. If editing the active profile, the session is automatically refreshed with the new settings.",
|
|
75535
|
+
descriptionShort: "Edit profile in $EDITOR",
|
|
75536
|
+
descriptionMedium: "Open a profile in your text editor for modification, then validate and save changes.",
|
|
75537
|
+
usage: "[name]",
|
|
75538
|
+
aliases: ["modify", "vi"],
|
|
75539
|
+
async execute(args, session) {
|
|
75540
|
+
const manager = getProfileManager();
|
|
75541
|
+
let profileName = args[0];
|
|
75542
|
+
if (!profileName) {
|
|
75543
|
+
const active = await manager.getActive();
|
|
75544
|
+
if (!active) {
|
|
75545
|
+
return errorResult(
|
|
75546
|
+
"No profile specified and no active profile set.\nUsage: login profile edit <name>"
|
|
75547
|
+
);
|
|
75548
|
+
}
|
|
75549
|
+
profileName = active;
|
|
75550
|
+
}
|
|
75551
|
+
const existingProfile = await manager.get(profileName);
|
|
75552
|
+
if (!existingProfile) {
|
|
75553
|
+
return errorResult(
|
|
75554
|
+
`Profile '${profileName}' not found.
|
|
75555
|
+
Use 'login profile list' to see available profiles.`
|
|
75556
|
+
);
|
|
75557
|
+
}
|
|
75558
|
+
if (!process.stdin.isTTY) {
|
|
75559
|
+
return errorResult(
|
|
75560
|
+
"Edit command requires an interactive terminal.\nUse 'login profile show <name>' to view profile details."
|
|
75561
|
+
);
|
|
75562
|
+
}
|
|
75563
|
+
let tempFile = null;
|
|
75564
|
+
try {
|
|
75565
|
+
tempFile = await createTempFile(existingProfile);
|
|
75566
|
+
const statsBefore = await fs3.stat(tempFile);
|
|
75567
|
+
const editor = getEditor();
|
|
75568
|
+
const output = [
|
|
75569
|
+
`Opening profile '${profileName}' in ${editor}...`
|
|
75570
|
+
];
|
|
75571
|
+
await openInEditor(tempFile);
|
|
75572
|
+
const statsAfter = await fs3.stat(tempFile);
|
|
75573
|
+
if (statsBefore.mtimeMs === statsAfter.mtimeMs) {
|
|
75574
|
+
output.push("", "No changes made.");
|
|
75575
|
+
return successResult(output);
|
|
75576
|
+
}
|
|
75577
|
+
const { profile: editedProfile, error } = await parseEditedProfile(
|
|
75578
|
+
tempFile,
|
|
75579
|
+
profileName
|
|
75580
|
+
);
|
|
75581
|
+
if (error || !editedProfile) {
|
|
75582
|
+
return errorResult(`Validation failed: ${error}`);
|
|
75583
|
+
}
|
|
75584
|
+
const saveResult = await manager.save(editedProfile);
|
|
75585
|
+
if (!saveResult.success) {
|
|
75586
|
+
return errorResult(
|
|
75587
|
+
`Failed to save profile: ${saveResult.message}`
|
|
75588
|
+
);
|
|
75589
|
+
}
|
|
75590
|
+
output.push("", `Profile '${profileName}' updated successfully.`);
|
|
75591
|
+
const activeProfileName = await manager.getActive();
|
|
75592
|
+
const isActive = profileName === activeProfileName;
|
|
75593
|
+
if (isActive) {
|
|
75594
|
+
const success = await session.switchProfile(profileName);
|
|
75595
|
+
if (success) {
|
|
75596
|
+
output.push("", "Session refreshed with updated settings.");
|
|
75597
|
+
const profile = session.getActiveProfile();
|
|
75598
|
+
const connectionInfo = buildConnectionInfo(
|
|
75599
|
+
profileName,
|
|
75600
|
+
profile?.apiUrl || "",
|
|
75601
|
+
!!profile?.apiToken,
|
|
75602
|
+
profile?.defaultNamespace || session.getNamespace(),
|
|
75603
|
+
session.isAuthenticated(),
|
|
75604
|
+
session.isTokenValidated(),
|
|
75605
|
+
session.getValidationError() ?? void 0
|
|
75606
|
+
);
|
|
75607
|
+
const tableLines = formatConnectionTable(connectionInfo);
|
|
75608
|
+
output.push("", ...tableLines);
|
|
75609
|
+
return successResult(output, true);
|
|
75610
|
+
}
|
|
75611
|
+
}
|
|
75612
|
+
return successResult(output);
|
|
75613
|
+
} catch (error) {
|
|
75614
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75615
|
+
return errorResult(`Edit failed: ${message}`);
|
|
75616
|
+
} finally {
|
|
75617
|
+
if (tempFile) {
|
|
75618
|
+
await cleanupTempFile(tempFile);
|
|
75619
|
+
}
|
|
75620
|
+
}
|
|
75621
|
+
},
|
|
75622
|
+
async completion(partial, _args, _session) {
|
|
75623
|
+
const manager = getProfileManager();
|
|
75624
|
+
const profiles = await manager.list();
|
|
75625
|
+
return profiles.map((p) => p.name).filter(
|
|
75626
|
+
(name) => name.toLowerCase().startsWith(partial.toLowerCase())
|
|
75627
|
+
);
|
|
75628
|
+
}
|
|
75629
|
+
};
|
|
75630
|
+
|
|
75426
75631
|
// src/domains/login/profile/active.ts
|
|
75427
75632
|
var activeCommand = {
|
|
75428
75633
|
name: "active",
|
|
@@ -76235,6 +76440,7 @@ var profileSubcommands = {
|
|
|
76235
76440
|
["show", showCommand],
|
|
76236
76441
|
["create", createCommand2],
|
|
76237
76442
|
["use", useCommand],
|
|
76443
|
+
["edit", editCommand],
|
|
76238
76444
|
["delete", deleteCommand]
|
|
76239
76445
|
]),
|
|
76240
76446
|
defaultCommand: activeCommand
|