switch-profile 2.3.0 → 2.4.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.
Files changed (3) hide show
  1. package/README.md +5 -4
  2. package/dist/cli.js +92 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -21,7 +21,7 @@ npx switch-profile
21
21
  │ ○ globex-dev ReadOnly 333333333333 us-east-1
22
22
  │ ○ initech-dev Admin 444444444444 eu-west-1
23
23
  │
24
- │ [Log in] [Add] [Remove] [Log out] [Settings]
24
+ │ [Log in] [Add] [Rename] [Remove] [Log out] [Settings]
25
25
  └ ↑↓ choose · enter switch · tab actions · esc quit
26
26
  ```
27
27
 
@@ -100,7 +100,7 @@ No profiles yet? `switch-profile` starts the **Add profiles** flow. To import ev
100
100
  Running `sp` (or `npx switch-profile`) with no arguments opens the home screen:
101
101
 
102
102
  - **Type and press Enter** to switch. That's the whole path for everyday use.
103
- - **Tab** moves to the action bar below the list, which is always visible however many profiles you have: **Log in**, **Add**, **Remove**, **Log out**, **Settings**. Use ←→ to choose and Enter to open.
103
+ - **Tab** moves to the action bar below the list, which is always visible however many profiles you have: **Log in**, **Add**, **Rename**, **Remove**, **Log out**, **Settings**. Use ←→ to choose and Enter to open.
104
104
  - **Every action opens as a page and comes back** to the home screen when it's done. **Esc** goes back from a page, and quits from the home screen.
105
105
  - A switch ends the session, which is what lets `sp` set `AWS_PROFILE` in your terminal.
106
106
 
@@ -115,6 +115,7 @@ Running `sp` (or `npx switch-profile`) with no arguments opens the home screen:
115
115
  | `logout [--yes]` | Ends every SSO session on this machine (`aws sso logout`, plus `aws logout --all` on AWS CLI 2.32+). |
116
116
  | `add` | Adds profiles: import accounts from an SSO portal (recommended), a single SSO profile, a console sign-in profile, or access keys. |
117
117
  | `add --from-sso [session]` | Imports or re-syncs every account and role of an `[sso-session]`. Options: `--region`, `--prefix`, `--prune`, `--yes`. |
118
+ | `rename [profile] [new-name]` | Renames a profile (alias `mv`), for example an imported `acme-prod-workloads-administratoraccess` to `acme-prod`. Also updates `source_profile` references, the default profile and the home screen order. SSO logins are kept. Scripts, terminals and tools that use the old name need the new one. |
118
119
  | `remove [profiles...] [--yes]` | Removes profiles (alias `rm`). The current default cannot be removed. |
119
120
  | `settings` | Per-terminal switching, SSO login mode, legacy SSO upgrade. |
120
121
 
@@ -155,7 +156,7 @@ sp add # then choose "Accounts from an SSO portal"
155
156
 
156
157
  1. Pick an existing `[sso-session]` or create one: start URL (e.g. `https://acme.awsapps.com/start`), SSO region (where Identity Center lives, not where you deploy), and a short name, usually the client.
157
158
  2. Log in if needed.
158
- 3. `switch-profile` lists every account and role you can access, then asks for a default region and a name prefix. Profiles are named `<prefix>-<account-name>-<role>`, for example `acme-prod-workloads-admin`.
159
+ 3. `switch-profile` lists every account and role you can access, then asks for a default region and a name prefix. Profiles are named `<prefix>-<account-name>-<role>`, for example `acme-prod-workloads-admin`. Rename any of them later with `sp rename` (re-imports still recognize them).
159
160
  4. A preview shows the new profiles, the ones already set up, and the ones that no longer exist. Then pick the new profiles to add: all are selected, so press Enter to add everything, or untick the ones you don't want (type to search by name, account or role).
160
161
 
161
162
  Run it again later to pick up new accounts. Account/role pairs that already have a profile are never duplicated, whatever its name. Generated profiles that no longer exist can be pruned (after a backup); profiles you wrote by hand are never pruned.
@@ -251,7 +252,7 @@ The SSO login is missing or expired. Run `sp login` (or just switch to the profi
251
252
 
252
253
  ### SSO login hangs on a remote machine
253
254
 
254
- The AWS CLI is waiting for a browser on the remote machine. Run `sp login --device`, or set **Settings > SSO login** to always use a device code.
255
+ The AWS CLI is waiting for a browser on the remote machine. Run `sp login --device`, or set **Settings > SSO login** to always use a device code. Since 2.3.1, `sp add` > A single SSO profile also uses a device code automatically over SSH; with an older version, press Ctrl+C and update (`sp` always runs the latest).
255
256
 
256
257
  ### The code is not in my clipboard over SSH
257
258
 
package/dist/cli.js CHANGED
@@ -5419,7 +5419,7 @@ var require_package = __commonJS({
5419
5419
  "package.json"(exports2, module2) {
5420
5420
  module2.exports = {
5421
5421
  name: "switch-profile",
5422
- version: "2.3.0",
5422
+ version: "2.4.0",
5423
5423
  main: "index.js",
5424
5424
  bin: {
5425
5425
  "switch-profile": "index.js"
@@ -5602,6 +5602,9 @@ var require_ini = __commonJS({
5602
5602
  return str;
5603
5603
  let newline = detectNewline(str);
5604
5604
  return tidy(stringify(blocks.filter((b3) => b3.name !== name), newline), newline);
5605
+ }, renameSection = (str, name, newName) => {
5606
+ let blocks = parse(str), block2 = findBlock(blocks, name);
5607
+ return block2 ? (block2.lines[0] = `[${newName}]`, stringify(blocks, detectNewline(str))) : str;
5605
5608
  }, setKeys = (str, name, changes) => {
5606
5609
  let blocks = parse(str), block2 = findBlock(blocks, name);
5607
5610
  if (!block2)
@@ -5636,6 +5639,7 @@ var require_ini = __commonJS({
5636
5639
  getSection,
5637
5640
  setSection,
5638
5641
  removeSection,
5642
+ renameSection,
5639
5643
  setKeys
5640
5644
  };
5641
5645
  }
@@ -5755,6 +5759,19 @@ var require_transforms = __commonJS({
5755
5759
  for (let name of stale)
5756
5760
  config = ini.removeSection(config, configSectionName(config, name)), removed.push(name);
5757
5761
  return { config, added, addedEntries, existing, stale, removed };
5762
+ }, escapeRegex = (text2) => text2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), renameProfile = (configStr, credsStr, from, to) => {
5763
+ let section = from == "default" ? null : configSectionName(configStr, from);
5764
+ if (!section)
5765
+ throw new Error(`Profile ${from} not found in ~/.aws/config.`);
5766
+ if (to == "default" || configSectionName(configStr, to) || ini.getSection(credsStr, to))
5767
+ throw new Error(`Profile ${to} already exists.`);
5768
+ let config = ini.renameSection(configStr, section, `profile ${to}`), creds = ini.renameSection(credsStr, from, to), sources = [], processes = [], mentions = new RegExp(`--profile[\\s=]+["']?${escapeRegex(from)}(?=["'\\s]|$)`);
5769
+ for (let s of ini.listSections(config).filter((s2) => s2 != "default" && !s2.startsWith("sso-session "))) {
5770
+ let params = ini.getSection(config, s), name = s.replace(/^profile\s+/, "");
5771
+ params.source_profile == from && (config = ini.setKeys(config, s, { source_profile: to }), sources.push(name)), params.credential_process && mentions.test(params.credential_process) && processes.push(name);
5772
+ }
5773
+ let defaults = ini.getSection(config, "default") || {}, wasDefault = defaults[NAME_KEY] == from;
5774
+ return wasDefault && (config = ini.setKeys(config, "default", { [NAME_KEY]: to, ...defaults.source_profile == from ? { source_profile: to } : {} })), { config, creds, sources, wasDefault, processes };
5758
5775
  }, listSsoSessions = (configStr) => ini.listSections(configStr).filter((s) => s.startsWith("sso-session ")).map((s) => ({ name: s.replace(/^sso-session\s+/, ""), ...ini.getSection(configStr, s) })), addSsoSession = (configStr, { name, startUrl, region, version }) => ini.getSection(configStr, `sso-session ${name}`) ? configStr : ini.setSection(configStr, `sso-session ${name}`, [
5759
5776
  ["sso_start_url", startUrl],
5760
5777
  ["sso_region", region],
@@ -5781,7 +5798,8 @@ var require_transforms = __commonJS({
5781
5798
  sessionNameFromUrl,
5782
5799
  upgradeLegacySsoProfiles,
5783
5800
  stampProfile,
5784
- listProfiles
5801
+ listProfiles,
5802
+ renameProfile
5785
5803
  };
5786
5804
  }
5787
5805
  });
@@ -6078,6 +6096,16 @@ var require_aws = __commonJS({
6078
6096
  configStr = deleteProfileFromConfig(profile, configStr), credsStr = deleteProfileFromCreds(profile, credsStr);
6079
6097
  }
6080
6098
  updateConfig && await writeAwsFile(AWS_CONFIG_FILE, configStr), updateCreds && await writeAwsFile(AWS_CREDS_FILE, credsStr);
6099
+ })()), renameProfile = (from, to) => catchErrors((async () => {
6100
+ let errMsg = `Fail to rename profile ${from} to ${to}`, [configStrErrors, configStr] = await getConfigFile(), [credsStrErrors, credsStr] = await getCredsFile();
6101
+ if (configStrErrors || credsStrErrors)
6102
+ throw wrapErrors(errMsg, configStrErrors || credsStrErrors);
6103
+ try {
6104
+ let { config, creds, sources, wasDefault, processes } = transforms.renameProfile(configStr, credsStr, from, to);
6105
+ return await writeAwsFiles({ config, creds }), { sources, wasDefault, processes };
6106
+ } catch (err) {
6107
+ throw wrapErrors(errMsg, [err]);
6108
+ }
6081
6109
  })()), createProfile = ({ name, aws_access_key_id, aws_secret_access_key, region }) => catchErrors((async () => {
6082
6110
  await awsCliV2Exists();
6083
6111
  let errMsg = "Fail to create AWS profile";
@@ -6104,10 +6132,11 @@ var require_aws = __commonJS({
6104
6132
  `${transforms.VERSION_KEY} = ${CLI_VERSION2}`
6105
6133
  ].join(NL) + NL, append = (str, section) => (str || "").trim() ? str.replace(/\s+$/, "") + NL + NL + section : section;
6106
6134
  await writeAwsFile(AWS_CONFIG_FILE, append(configStr, newConfig)), await writeAwsFile(AWS_CREDS_FILE, append(credsStr, newCreds));
6107
- })()), createSsoProfile = (name) => catchErrors((async () => {
6135
+ })()), createSsoProfile = (name, { loginMode } = {}) => catchErrors((async () => {
6108
6136
  await awsCliV2Exists();
6137
+ let flags = loginFlags(loginMode || "auto", { env: process.env, platform: process.platform, cliVersion: await getAwsCliVersion() });
6109
6138
  try {
6110
- await run2("aws", ["configure", "sso", "--profile", name], { tee: !0 });
6139
+ await run2("aws", ["configure", "sso", "--profile", name, ...flags], { tee: !0 });
6111
6140
  } catch (err) {
6112
6141
  throw Object.assign(new Error(`'aws configure sso' failed: ${err.message}`, { cause: err }), { output: err.output || "" });
6113
6142
  }
@@ -6134,6 +6163,7 @@ var require_aws = __commonJS({
6134
6163
  getDefaultProfile,
6135
6164
  setDefaultProfile,
6136
6165
  deleteProfiles,
6166
+ renameProfile,
6137
6167
  createProfile,
6138
6168
  createSsoProfile,
6139
6169
  backupAwsFiles,
@@ -6150,7 +6180,7 @@ var require_aws = __commonJS({
6150
6180
  // src/shell.js
6151
6181
  var require_shell = __commonJS({
6152
6182
  "src/shell.js"(exports2, module2) {
6153
- var fs = require("fs"), { homedir } = require("os"), { join: join2, dirname: dirname2, basename } = require("path"), { run: run2 } = require_core(), log3 = require_log(), IS_WINDOWS = process.platform === "win32", IS_MAC = process.platform === "darwin", FUNCTION_NAME = "sp", BLOCK_START_PREFIX = "# >>> switch-profile", BLOCK_END = "# <<< switch-profile <<<", BLOCK_REGEX = /(^|\r?\n)# >>> switch-profile[^\n]*\r?\n[\s\S]*?# <<< switch-profile <<<[^\n]*(\r?\n)?/, blockStart = (version) => `${BLOCK_START_PREFIX} v${version} (managed by switch-profile, do not edit) >>>`, CLEARED_VARS = ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_DEFAULT_PROFILE"], SUBCOMMANDS = ["status", "login", "logout", "add", "remove", "settings", "use"], PROFILES_SED = "sed -n 's/^\\[profile \\(.*\\)\\]$/\\1/p'", POSIX_FUNCTION = (shell) => `${FUNCTION_NAME}() {
6183
+ var fs = require("fs"), { homedir } = require("os"), { join: join2, dirname: dirname2, basename } = require("path"), { run: run2 } = require_core(), log3 = require_log(), IS_WINDOWS = process.platform === "win32", IS_MAC = process.platform === "darwin", FUNCTION_NAME = "sp", BLOCK_START_PREFIX = "# >>> switch-profile", BLOCK_END = "# <<< switch-profile <<<", BLOCK_REGEX = /(^|\r?\n)# >>> switch-profile[^\n]*\r?\n[\s\S]*?# <<< switch-profile <<<[^\n]*(\r?\n)?/, blockStart = (version) => `${BLOCK_START_PREFIX} v${version} (managed by switch-profile, do not edit) >>>`, CLEARED_VARS = ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SESSION_TOKEN", "AWS_DEFAULT_PROFILE"], SUBCOMMANDS = ["status", "login", "logout", "add", "remove", "settings", "use", "rename"], PROFILES_SED = "sed -n 's/^\\[profile \\(.*\\)\\]$/\\1/p'", POSIX_FUNCTION = (shell) => `${FUNCTION_NAME}() {
6154
6184
  local __sp_file __sp_status
6155
6185
  __sp_file="$(mktemp "\${TMPDIR:-/tmp}/switch-profile.XXXXXX")" || return 1
6156
6186
  if [ -n "\${SWITCH_PROFILE_DEV_BIN:-}" ]; then
@@ -6170,7 +6200,7 @@ var require_shell = __commonJS({
6170
6200
  items=(\${(f)"$(${PROFILES_SED} "\${AWS_CONFIG_FILE:-$HOME/.aws/config}" 2>/dev/null)"})
6171
6201
  if (( CURRENT == 2 )); then
6172
6202
  compadd -- $items ${SUBCOMMANDS.join(" ")}
6173
- elif [[ $words[2] == (remove|rm) ]] || { (( CURRENT == 3 )) && [[ $words[2] == (use|login) ]] }; then
6203
+ elif [[ $words[2] == (remove|rm) ]] || { (( CURRENT == 3 )) && [[ $words[2] == (use|login|rename|mv) ]] }; then
6174
6204
  compadd -- $items
6175
6205
  fi
6176
6206
  }
@@ -6181,7 +6211,7 @@ fi`, BASH_COMPLETION = `_switch_profile_complete() {
6181
6211
  items="$(${PROFILES_SED} "\${AWS_CONFIG_FILE:-$HOME/.aws/config}" 2>/dev/null)"
6182
6212
  if [ "$COMP_CWORD" -eq 1 ]; then
6183
6213
  items="$items ${SUBCOMMANDS.join(" ")}"
6184
- elif [ "$COMP_CWORD" -lt 2 ] || ! case "\${COMP_WORDS[1]}" in use|login|remove|rm) true ;; *) false ;; esac; then
6214
+ elif [ "$COMP_CWORD" -lt 2 ] || ! case "\${COMP_WORDS[1]}" in use|login|rename|mv|remove|rm) true ;; *) false ;; esac; then
6185
6215
  return 0
6186
6216
  elif [ "$COMP_CWORD" -gt 2 ] && [ "\${COMP_WORDS[1]}" != remove ] && [ "\${COMP_WORDS[1]}" != rm ]; then
6187
6217
  return 0
@@ -6210,7 +6240,7 @@ function __switch_profile_profiles
6210
6240
  end
6211
6241
  for __sp_cmd in ${FUNCTION_NAME} switch-profile
6212
6242
  complete -c $__sp_cmd -f -n 'test (count (commandline -opc)) -eq 1' -a '(__switch_profile_profiles) ${SUBCOMMANDS.join(" ")}'
6213
- complete -c $__sp_cmd -f -n 'test (count (commandline -opc)) -eq 2; and __fish_seen_subcommand_from use login' -a '(__switch_profile_profiles)'
6243
+ complete -c $__sp_cmd -f -n 'test (count (commandline -opc)) -eq 2; and __fish_seen_subcommand_from use login rename mv' -a '(__switch_profile_profiles)'
6214
6244
  complete -c $__sp_cmd -f -n '__fish_seen_subcommand_from remove rm' -a '(__switch_profile_profiles)'
6215
6245
  end`, POWERSHELL_FUNCTION = `function ${FUNCTION_NAME} {
6216
6246
  param([Parameter(ValueFromRemainingArguments = $true)] [string[]] $Rest)
@@ -7660,6 +7690,7 @@ ${ui2.dim(viaShortcut ? "Switching clears them from this terminal." : `Unset ${s
7660
7690
  }, ACTIONS = [
7661
7691
  { key: "login", label: "Log in" },
7662
7692
  { key: "add", label: "Add" },
7693
+ { key: "rename", label: "Rename" },
7663
7694
  { key: "remove", label: "Remove" },
7664
7695
  { key: "logout", label: "Log out" },
7665
7696
  { key: "settings", label: "Settings" }
@@ -7756,7 +7787,7 @@ ${ui2.dim("Tip: enable per-terminal switching in Settings.")}` : ""}`);
7756
7787
  ${ui2.dim(`Open a new terminal or run: ${installed.reload}`)}`), installed.name == "powershell" && p4.log.message(ui2.dim("If PowerShell refuses to load your profile: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned"));
7757
7788
  }, runAction = async (key, state, opts) => {
7758
7789
  let commands2 = require_commands();
7759
- return key == "login" ? commands2.login(state.defaultName, { ...opts, fromPicker: !0 }) : commands2[key](opts.args || [], { ...opts, fromPicker: !0 });
7790
+ return key == "login" ? commands2.login(state.defaultName, { ...opts, fromPicker: !0 }) : key == "rename" ? commands2.rename(null, null, { ...opts, fromPicker: !0 }) : commands2[key](opts.args || [], { ...opts, fromPicker: !0 });
7760
7791
  }, routeChoice = (choice) => {
7761
7792
  if (p4.isCancel(choice))
7762
7793
  return { type: "quit" };
@@ -7823,7 +7854,7 @@ ${ui2.dim(`Open a new terminal or run: ${installed.reload}`)}`), installed.name
7823
7854
  // src/commands/index.js
7824
7855
  var require_commands = __commonJS({
7825
7856
  "src/commands/index.js"(exports2, module2) {
7826
- var p4 = (init_dist4(), __toCommonJS(dist_exports2)), log3 = require_log(), aws = require_aws(), transforms = require_transforms(), settings2 = require_settings(), shell = require_shell(), migrate = require_migrate(), rank = require_rank(), { resolveLoginMode, isRemoteSession, configureSsoFailure } = require_login(), ui2 = require_ui(), { ask, preflight, loadState, loginKey, describe, loginState, upgradeLegacySso } = require_common(), { ssoLogin, rememberLogin } = require_login_flow(), { switchCommand, switchTo, connect, enableShortcut } = require_switch(), intro2 = (opts) => {
7857
+ var p4 = (init_dist4(), __toCommonJS(dist_exports2)), log3 = require_log(), aws = require_aws(), transforms = require_transforms(), settings2 = require_settings(), shell = require_shell(), migrate = require_migrate(), rank = require_rank(), { resolveLoginMode, isRemoteSession, configureSsoFailure } = require_login(), ui2 = require_ui(), { ask, preflight, loadState, loginKey, describe, loginState, upgradeLegacySso } = require_common(), { ssoLogin, rememberLogin } = require_login_flow(), { switchCommand, switchTo, connect, enableShortcut, exportHint } = require_switch(), intro2 = (opts) => {
7827
7858
  !opts.fromPicker && !opts.json && p4.intro(`${ui2.badge("switch-profile")} ${ui2.dim(settings2.CLI_VERSION)}`);
7828
7859
  }, begin = async (opts, { needsInput } = {}) => {
7829
7860
  let interactive = ui2.isInteractive(opts);
@@ -7919,7 +7950,7 @@ var require_commands = __commonJS({
7919
7950
  ...sessions.length ? [ui2.dim(`Portals already set up: ${sessions.map((x2) => `${x2.name} (${x2.sso_region || "?"})`).join(", ")}. Type one of these names to reuse it.`)] : []
7920
7951
  ].join(`
7921
7952
  `));
7922
- let [errors, upgraded] = await aws.createSsoProfile(name);
7953
+ let [errors, upgraded] = await aws.createSsoProfile(name, { loginMode: settings2.getLoginMode(state.settings) });
7923
7954
  if (errors) {
7924
7955
  let failed = errors.find((e) => e.output != null);
7925
7956
  if (!failed)
@@ -8059,6 +8090,53 @@ AWS recommends SSO or console sign-in instead.`), !await ask(p4.confirm({ messag
8059
8090
  if (errors)
8060
8091
  throw ui2.cliErrorFrom(errors);
8061
8092
  p4.outro(`${ui2.ok(ui2.sym.ok)} Removed ${names.join(", ")}`);
8093
+ }, moveKey = (obj, from, to) => {
8094
+ if (!obj || !(from in obj))
8095
+ return obj;
8096
+ let { [from]: value, ...rest } = obj;
8097
+ return { ...rest, [to]: value };
8098
+ }, rename = async (from, to, opts) => {
8099
+ let interactive = await begin(opts), state = await loadState();
8100
+ if (!from) {
8101
+ if (!interactive)
8102
+ throw new ui2.CliError("Which profile?", { code: 3, hint: "Run: switch-profile rename <profile> <new-name>" });
8103
+ from = await ask(p4.autocomplete({
8104
+ message: "Rename which profile?",
8105
+ maxItems: 12,
8106
+ options: state.profiles.map((x2) => ({ value: x2.name, label: x2.name, hint: describe(x2) }))
8107
+ }));
8108
+ }
8109
+ let profile = findProfile(state, from), taken = [...state.profiles.map((x2) => x2.name).filter((n3) => n3 != from), "default"], validate = (v) => v == from ? "That is already its name." : validateProfileName(taken)(v);
8110
+ if (!to) {
8111
+ if (!interactive)
8112
+ throw new ui2.CliError("What is the new name?", { code: 3, hint: `Run: switch-profile rename ${from} <new-name>` });
8113
+ to = await ask(p4.text({ message: `New name for ${from}`, initialValue: from, validate }));
8114
+ }
8115
+ let invalid = validate(to);
8116
+ if (invalid)
8117
+ throw new ui2.CliError(invalid, { code: 3 });
8118
+ let [errors, result] = await aws.renameProfile(from, to);
8119
+ if (errors)
8120
+ throw ui2.cliErrorFrom(errors);
8121
+ let current = await settings2.read();
8122
+ await settings2.update({
8123
+ usage: moveKey(current.usage, from, to),
8124
+ ...loginKey(profile) == from ? { logins: moveKey(current.logins, from, to) } : {}
8125
+ });
8126
+ let inTerminal = process.env.AWS_PROFILE == from, terminal = inTerminal ? await shell.exportProfile(to).catch(log3.tolerated("handing the profile to sp", !1)) : !1;
8127
+ if (opts.json) {
8128
+ process.stdout.write(JSON.stringify({ from, to, default: result.wasDefault, sources: result.sources, processes: result.processes, terminal }) + `
8129
+ `);
8130
+ return;
8131
+ }
8132
+ let lines = [
8133
+ result.wasDefault ? ui2.dim("still the default profile") : null,
8134
+ result.sources.length ? ui2.dim(`source_profile updated in ${result.sources.join(", ")}`) : null,
8135
+ terminal ? ui2.dim("this terminal now uses the new name") : null
8136
+ ].filter(Boolean);
8137
+ p4.log.success([`Renamed ${ui2.accent(from)} to ${ui2.accent(to)}`, ...lines].join(`
8138
+ `)), result.processes.length && p4.log.warn(`The credential_process of ${result.processes.join(", ")} still uses --profile ${from}. Update ${result.processes.length == 1 ? "it" : "them"} in ~/.aws/config.`), inTerminal && !terminal && p4.log.warn(`This terminal still uses ${from}. Run:
8139
+ ${ui2.accent(exportHint(to))}`), p4.outro(ui2.dim(`Other terminals, scripts and tools that use ${from} (AWS_PROFILE or --profile) need the new name.`));
8062
8140
  }, LOGIN_MODE_LABELS = {
8063
8141
  auto: "Auto: device code over SSH, browser otherwise",
8064
8142
  device: "Always device code (approve from any device)",
@@ -8110,6 +8188,7 @@ AWS recommends SSO or console sign-in instead.`), !await ask(p4.confirm({ messag
8110
8188
  logout,
8111
8189
  add,
8112
8190
  remove,
8191
+ rename,
8113
8192
  settings: settingsCommand
8114
8193
  };
8115
8194
  }
@@ -8125,6 +8204,7 @@ Examples:
8125
8204
  $ sp acme prod fuzzy match: switches if only one profile matches
8126
8205
  $ sp login log in again now (device code over SSH)
8127
8206
  $ sp add import every account of an SSO portal
8207
+ $ sp rename <profile> <new> give a profile a friendlier name
8128
8208
  $ switch-profile status --json
8129
8209
 
8130
8210
  'sp' is the shortcut switch-profile installs on first use (or from Settings). It also
@@ -8154,6 +8234,6 @@ Exit codes: 0 ok \xB7 1 error \xB7 2 login required \xB7 3 bad input \xB7 130 ca
8154
8234
  }, main = (argv) => {
8155
8235
  log2.start({ version: CLI_VERSION, argv }), process.on("uncaughtException", crashed), process.on("unhandledRejection", crashed), process.on("exit", (code) => log2.info(`exit ${code}`));
8156
8236
  let program = new Command();
8157
- return program.name("switch-profile").description("Switch between AWS profiles, log in with SSO, and keep every terminal on the right account.").version(CLI_VERSION, "-v, --version").argument("[profile...]", "profile name or search text").option("--json", "machine-readable output").option("--no-input", "never prompt (fails with a hint instead)").option("--debug", "show error details").addHelpText("after", EXAMPLES).showSuggestionAfterError().action(run((words, opts) => commands.switch((words || []).join(" "), opts))), program.command("use").argument("<profile>").description("switch to a profile by its exact name").action(run(commands.use)), program.command("status").description("show the current profile and login state").action(run((opts) => commands.status([], opts))), program.command("login").argument("[profile]", "defaults to this terminal's profile, then the default profile").description("log in again now, even if the session is still valid").option("--device", "use a device code (approve from any device)").option("--browser", "use the browser on this machine").action(run(commands.login)), program.command("logout").description("end every SSO session on this machine").option("-y, --yes", "do not ask for confirmation").action(run((opts) => commands.logout([], opts))), program.command("add").description("add profiles: import an SSO portal, or create one").option("--from-sso [session]", "import (or re-sync) every account and role of an [sso-session]").option("--region <region>", "default region of imported profiles").option("--prefix <prefix>", "name prefix of imported profiles").option("--prune", "remove imported profiles that no longer exist").option("-y, --yes", "do not ask for confirmation").action(run((opts) => commands.add([], opts))), program.command("remove").alias("rm").argument("[profiles...]").description("remove profiles").option("-y, --yes", "do not ask for confirmation").action(run(commands.remove)), program.command("settings").description("per-terminal switching, login mode and more").action(run((opts) => commands.settings([], opts))), program.command("switch", { hidden: !0 }).action(run((opts) => commands.switch("", opts))), program.parseAsync(argv);
8237
+ return program.name("switch-profile").description("Switch between AWS profiles, log in with SSO, and keep every terminal on the right account.").version(CLI_VERSION, "-v, --version").argument("[profile...]", "profile name or search text").option("--json", "machine-readable output").option("--no-input", "never prompt (fails with a hint instead)").option("--debug", "show error details").addHelpText("after", EXAMPLES).showSuggestionAfterError().action(run((words, opts) => commands.switch((words || []).join(" "), opts))), program.command("use").argument("<profile>").description("switch to a profile by its exact name").action(run(commands.use)), program.command("status").description("show the current profile and login state").action(run((opts) => commands.status([], opts))), program.command("login").argument("[profile]", "defaults to this terminal's profile, then the default profile").description("log in again now, even if the session is still valid").option("--device", "use a device code (approve from any device)").option("--browser", "use the browser on this machine").action(run(commands.login)), program.command("logout").description("end every SSO session on this machine").option("-y, --yes", "do not ask for confirmation").action(run((opts) => commands.logout([], opts))), program.command("add").description("add profiles: import an SSO portal, or create one").option("--from-sso [session]", "import (or re-sync) every account and role of an [sso-session]").option("--region <region>", "default region of imported profiles").option("--prefix <prefix>", "name prefix of imported profiles").option("--prune", "remove imported profiles that no longer exist").option("-y, --yes", "do not ask for confirmation").action(run((opts) => commands.add([], opts))), program.command("remove").alias("rm").argument("[profiles...]").description("remove profiles").option("-y, --yes", "do not ask for confirmation").action(run(commands.remove)), program.command("rename").alias("mv").argument("[profile]").argument("[new-name]").description("rename a profile").action(run(commands.rename)), program.command("settings").description("per-terminal switching, login mode and more").action(run((opts) => commands.settings([], opts))), program.command("switch", { hidden: !0 }).action(run((opts) => commands.switch("", opts))), program.parseAsync(argv);
8158
8238
  };
8159
8239
  module.exports = { main };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "switch-profile",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "main": "index.js",
5
5
  "bin": {
6
6
  "switch-profile": "index.js"