clever-tools 4.5.2 → 4.6.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 (69) hide show
  1. package/README.md +10 -0
  2. package/bin/clever.js +25 -22
  3. package/package.json +2 -2
  4. package/src/clever-client/auth-bridge.js +0 -25
  5. package/src/commands/README.md +1 -0
  6. package/src/commands/accesslogs/accesslogs.command.js +4 -1
  7. package/src/commands/accesslogs/accesslogs.docs.md +1 -1
  8. package/src/commands/addon/addon.create.command.js +23 -20
  9. package/src/commands/config/config.set.command.js +3 -3
  10. package/src/commands/config-provider/config-provider.args.js +8 -0
  11. package/src/commands/config-provider/config-provider.command.js +10 -0
  12. package/src/commands/config-provider/config-provider.docs.md +109 -0
  13. package/src/commands/config-provider/config-provider.get.command.js +36 -0
  14. package/src/commands/config-provider/config-provider.import.command.js +40 -0
  15. package/src/commands/config-provider/config-provider.list.command.js +45 -0
  16. package/src/commands/config-provider/config-provider.open.command.js +17 -0
  17. package/src/commands/config-provider/config-provider.rm.command.js +25 -0
  18. package/src/commands/config-provider/config-provider.set.command.js +37 -0
  19. package/src/commands/create/create.command.js +7 -6
  20. package/src/commands/curl/curl.command.js +18 -19
  21. package/src/commands/deploy/deploy.command.js +14 -8
  22. package/src/commands/deploy/deploy.docs.md +20 -0
  23. package/src/commands/diag/diag.command.js +52 -39
  24. package/src/commands/features/features.disable.command.js +1 -2
  25. package/src/commands/features/features.enable.command.js +1 -2
  26. package/src/commands/features/features.info.command.js +1 -1
  27. package/src/commands/features/features.list.command.js +1 -2
  28. package/src/commands/global.commands.js +22 -0
  29. package/src/commands/global.options.js +1 -1
  30. package/src/commands/login/login.command.js +119 -20
  31. package/src/commands/login/login.docs.md +9 -2
  32. package/src/commands/logout/logout.command.js +39 -7
  33. package/src/commands/logout/logout.docs.md +7 -1
  34. package/src/commands/logs/logs.command.js +7 -8
  35. package/src/commands/logs/logs.docs.md +1 -1
  36. package/src/commands/ng/ng.get-config.command.js +3 -3
  37. package/src/commands/profile/profile.command.js +13 -37
  38. package/src/commands/profile/profile.docs.md +28 -0
  39. package/src/commands/profile/profile.list.command.js +44 -0
  40. package/src/commands/profile/profile.switch.command.js +80 -0
  41. package/src/commands/restart/restart.command.js +3 -2
  42. package/src/commands/ssh/ssh.command.js +2 -2
  43. package/src/commands/tokens/tokens.command.js +3 -3
  44. package/src/commands/tokens/tokens.create.command.js +4 -4
  45. package/src/config/cache.js +60 -0
  46. package/src/config/config.js +233 -0
  47. package/src/config/features.js +167 -0
  48. package/src/config/paths.js +23 -0
  49. package/src/lib/date-utils.js +48 -0
  50. package/src/lib/fs.js +49 -0
  51. package/src/lib/operator-commands.js +4 -4
  52. package/src/lib/profile.js +116 -0
  53. package/src/logger.js +123 -69
  54. package/src/logger.types.d.ts +5 -0
  55. package/src/models/app_configuration.js +42 -39
  56. package/src/models/application_configuration.js +30 -30
  57. package/src/models/config-provider.js +34 -0
  58. package/src/models/git-isomorphic.js +153 -0
  59. package/src/models/git-system.js +182 -0
  60. package/src/models/git.js +150 -128
  61. package/src/models/ids-resolver.js +1 -1
  62. package/src/models/log.js +141 -90
  63. package/src/models/send-to-api.js +58 -33
  64. package/src/models/user.js +0 -11
  65. package/src/models/utils.js +2 -2
  66. package/src/experimental-features.js +0 -91
  67. package/src/lib/format-date.js +0 -3
  68. package/src/models/configuration.js +0 -140
  69. package/src/models/log-v4.js +0 -189
@@ -0,0 +1,37 @@
1
+ import { getConfigProviderEnv, updateConfigProviderEnv } from '@clevercloud/client/esm/api/v4/addon.js';
2
+ import { validateName } from '@clevercloud/client/esm/utils/env-vars.js';
3
+ import { defineCommand } from '../../lib/define-command.js';
4
+ import { Logger } from '../../logger.js';
5
+ import { resolveConfigProviderId } from '../../models/config-provider.js';
6
+ import { sendToApi } from '../../models/send-to-api.js';
7
+ import { envVariableNameArg, envVariableValueArg } from '../global.args.js';
8
+ import { configProviderIdOrNameArg } from './config-provider.args.js';
9
+
10
+ export const configProviderSetCommand = defineCommand({
11
+ description: 'Add or update an environment variable named <variable-name> with the value <variable-value>',
12
+ since: '4.6.0',
13
+ options: {},
14
+ args: [configProviderIdOrNameArg, envVariableNameArg, envVariableValueArg],
15
+ async handler(_options, addonIdOrRealIdOrName, varName, varValue) {
16
+ const nameIsValid = validateName(varName);
17
+ if (!nameIsValid) {
18
+ throw new Error(`Variable name '${varName}' is invalid`);
19
+ }
20
+
21
+ const { realId } = await resolveConfigProviderId(addonIdOrRealIdOrName);
22
+
23
+ // API returns an array of { name, value } objects
24
+ const envVars = await getConfigProviderEnv({ configurationProviderId: realId }).then(sendToApi);
25
+ const existingIndex = envVars.findIndex((v) => v.name === varName);
26
+
27
+ if (existingIndex >= 0) {
28
+ envVars[existingIndex].value = varValue;
29
+ } else {
30
+ envVars.push({ name: varName, value: varValue });
31
+ }
32
+
33
+ await updateConfigProviderEnv({ configurationProviderId: realId }, envVars).then(sendToApi);
34
+
35
+ Logger.println('Environment variable has been set');
36
+ },
37
+ });
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { z } from 'zod';
3
+ import { config } from '../../config/config.js';
3
4
  import { defineArgument } from '../../lib/define-argument.js';
4
5
  import { defineCommand } from '../../lib/define-command.js';
5
6
  import { defineOption } from '../../lib/define-option.js';
@@ -8,8 +9,7 @@ import { Logger } from '../../logger.js';
8
9
  import * as AppConfig from '../../models/app_configuration.js';
9
10
  import * as Application from '../../models/application.js';
10
11
  import { AVAILABLE_ZONES, listAvailableTypes, listAvailableZones } from '../../models/application.js';
11
- import { conf } from '../../models/configuration.js';
12
- import { isGitWorkingDirectoryClean, isInsideGitRepo } from '../../models/git.js';
12
+ import { Git } from '../../models/git.js';
13
13
  import { aliasCreationOption, humanJsonOutputFormatOption, orgaIdOrNameOption } from '../global.options.js';
14
14
 
15
15
  function getGithubDetails(githubOwnerRepo) {
@@ -45,15 +45,16 @@ async function displayAppCreation(app, alias, github, taskCommand) {
45
45
  Logger.println(' ' + styleText('bold', 'Next steps:'));
46
46
 
47
47
  if (!github) {
48
- const isInsideGit = await isInsideGitRepo();
49
- if (!isInsideGit) {
48
+ const git = await Git.get();
49
+ const isInsideGitRepo = await git.isInsideGitRepo();
50
+ if (!isInsideGitRepo) {
50
51
  Logger.println(` ${styleText('yellow', '!')} Initialize a git repository first, for example:`);
51
52
  Logger.println(` ${shellCommand('git init')}`);
52
53
  Logger.println(` ${shellCommand('git add .')}`);
53
54
  Logger.println(` ${shellCommand('git commit -m "Initial commit"')}`);
54
55
  Logger.println();
55
56
  } else {
56
- const isClean = await isGitWorkingDirectoryClean();
57
+ const isClean = await git.isGitWorkingDirectoryClean();
57
58
  if (!isClean) {
58
59
  Logger.println(` ${styleText('yellow', '!')} Commit your changes first:`);
59
60
  Logger.println(` ${shellCommand('git add .')}`);
@@ -74,7 +75,7 @@ async function displayAppCreation(app, alias, github, taskCommand) {
74
75
  }
75
76
 
76
77
  Logger.println(
77
- ` ${styleText('blue', '→')} Manage your application at: ${styleText('underline', `${conf.GOTO_URL}/${app.id}`)}`,
78
+ ` ${styleText('blue', '→')} Manage your application at: ${styleText('underline', `${config.GOTO_URL}/${app.id}`)}`,
78
79
  );
79
80
  Logger.println('');
80
81
  }
@@ -1,18 +1,17 @@
1
1
  import { addOauthHeader } from '@clevercloud/client/esm/oauth.js';
2
2
  import dedent from 'dedent';
3
3
  import { spawn } from 'node:child_process';
4
+ import { config } from '../../config/config.js';
4
5
  import { defineCommand } from '../../lib/define-command.js';
5
6
  import { styleText } from '../../lib/style-text.js';
6
7
  import { Logger } from '../../logger.js';
7
- import { conf, loadOAuthConf } from '../../models/configuration.js';
8
8
 
9
- async function loadTokens() {
10
- const tokens = await loadOAuthConf();
9
+ function getTokens() {
11
10
  return {
12
- OAUTH_CONSUMER_KEY: conf.OAUTH_CONSUMER_KEY,
13
- OAUTH_CONSUMER_SECRET: conf.OAUTH_CONSUMER_SECRET,
14
- API_OAUTH_TOKEN: tokens.token,
15
- API_OAUTH_TOKEN_SECRET: tokens.secret,
11
+ OAUTH_CONSUMER_KEY: config.OAUTH_CONSUMER_KEY,
12
+ OAUTH_CONSUMER_SECRET: config.OAUTH_CONSUMER_SECRET,
13
+ API_OAUTH_TOKEN: config.token,
14
+ API_OAUTH_TOKEN_SECRET: config.secret,
16
15
  };
17
16
  }
18
17
 
@@ -21,16 +20,16 @@ function printCleverCurlHelp() {
21
20
  Usage: clever curl
22
21
  Query Clever Cloud's API using Clever Tools credentials. For example:
23
22
 
24
- clever curl ${conf.API_HOST}/v2/self
25
- clever curl ${conf.API_HOST}/v2/summary
26
- clever curl ${conf.API_HOST}/v4/products/zones
27
- clever curl ${conf.API_HOST}/v2/organisations/<ORGANISATION_ID>/applications | jq '.[].id'
28
- clever curl ${conf.API_HOST}/v4/billing/organisations/<ORGANISATION_ID>/<INVOICE_NUMBER>.pdf > invoice.pdf
23
+ clever curl ${config.API_HOST}/v2/self
24
+ clever curl ${config.API_HOST}/v2/summary
25
+ clever curl ${config.API_HOST}/v4/products/zones
26
+ clever curl ${config.API_HOST}/v2/organisations/<ORGANISATION_ID>/applications | jq '.[].id'
27
+ clever curl ${config.API_HOST}/v4/billing/organisations/<ORGANISATION_ID>/<INVOICE_NUMBER>.pdf > invoice.pdf
29
28
 
30
29
  Our API documentation is available here :
31
30
 
32
- ${conf.API_DOC_URL}/v2/
33
- ${conf.API_DOC_URL}/v4/
31
+ ${config.API_DOC_URL}/v2/
32
+ ${config.API_DOC_URL}/v4/
34
33
  `);
35
34
  }
36
35
 
@@ -46,21 +45,21 @@ export async function curl() {
46
45
  return;
47
46
  }
48
47
 
49
- const curlUrl = curlArgs.find((part) => part.startsWith(conf.API_HOST));
48
+ const curlUrl = curlArgs.find((part) => part.startsWith(config.API_HOST));
50
49
 
51
50
  // We only allow request to the respective API_HOST
52
51
  if (curlUrl == null) {
53
- Logger.error('"clever curl" command must be used with ' + styleText('blue', conf.API_HOST));
52
+ Logger.error('"clever curl" command must be used with ' + styleText('blue', config.API_HOST));
54
53
  process.exit(1);
55
54
  }
56
55
 
57
56
  const lastCurlArg = curlArgs.at(-1);
58
- const lastCurlArgIsHelp = lastCurlArg !== '--help' && lastCurlArg !== '-h';
57
+ const lastCurlArgIsNotHelp = lastCurlArg !== '--help' && lastCurlArg !== '-h';
59
58
 
60
59
  // Add OAuth header, only if last cURL arg is not help
61
60
  // We do this because cURL's help arg expect a category
62
- if (lastCurlArgIsHelp) {
63
- const tokens = await loadTokens();
61
+ if (lastCurlArgIsNotHelp) {
62
+ const tokens = getTokens();
64
63
  const oauthHeader = await Promise.resolve({})
65
64
  .then(addOauthHeader(tokens))
66
65
  .then((request) => request.headers.authorization);
@@ -3,14 +3,14 @@ import dedent from 'dedent';
3
3
  import { z } from 'zod';
4
4
  import { defineCommand } from '../../lib/define-command.js';
5
5
  import { defineOption } from '../../lib/define-option.js';
6
+ import { slugify } from '../../lib/slugify.js';
6
7
  import { styleText } from '../../lib/style-text.js';
7
8
  import { Logger } from '../../logger.js';
8
9
  import * as AppConfig from '../../models/app_configuration.js';
9
10
  import * as Application from '../../models/application.js';
10
11
  import * as ExitStrategy from '../../models/exit-strategy-option.js';
11
- import * as git from '../../models/git.js';
12
- import { completeBranches } from '../../models/git.js';
13
- import * as Log from '../../models/log-v4.js';
12
+ import { Git } from '../../models/git.js';
13
+ import * as Log from '../../models/log.js';
14
14
  import { sendToApi } from '../../models/send-to-api.js';
15
15
  import { aliasOption, exitOnDeployOption, followDeployLogsOption, quietOption } from '../global.options.js';
16
16
 
@@ -22,7 +22,7 @@ async function restartOnSameCommit(ownerId, appId, commitIdToPush, quiet, withou
22
22
  return Log.watchDeploymentAndDisplayLogs({ ownerId, appId, deploymentId: restart.deploymentId, quiet, exitStrategy });
23
23
  }
24
24
 
25
- async function getBranchToDeploy(branchName, tagName) {
25
+ async function getBranchToDeploy(git, branchName, tagName) {
26
26
  if (tagName) {
27
27
  const useTag = await git.isExistingTag(tagName);
28
28
  if (useTag) {
@@ -46,7 +46,10 @@ export const deployCommand = defineCommand({
46
46
  description: 'Branch to push (current branch by default)',
47
47
  aliases: ['b'],
48
48
  placeholder: 'branch',
49
- complete: completeBranches,
49
+ complete: async () => {
50
+ const git = await Git.get();
51
+ return git.completeBranches();
52
+ },
50
53
  }),
51
54
  tag: defineOption({
52
55
  name: 'tag',
@@ -78,11 +81,12 @@ export const deployCommand = defineCommand({
78
81
  const { alias, branch: branchName, tag: tagName, quiet, force, follow, sameCommitPolicy, exitOnDeploy } = options;
79
82
 
80
83
  const exitStrategy = ExitStrategy.get(follow, exitOnDeploy);
84
+ const git = await Git.get();
81
85
 
82
86
  const appData = await AppConfig.getAppDetails({ alias });
83
87
  const { ownerId, appId } = appData;
84
88
 
85
- const branchRefspec = await getBranchToDeploy(branchName, tagName);
89
+ const branchRefspec = await getBranchToDeploy(git, branchName, tagName);
86
90
  const commitIdToPush = await git.getBranchCommit(branchRefspec);
87
91
  const remoteHeadCommitId = await git.getRemoteCommit(appData.deployUrl);
88
92
  const deployedCommitId = await Application.get(ownerId, appId).then(({ commitId }) => commitId);
@@ -141,7 +145,8 @@ export const deployCommand = defineCommand({
141
145
  ${styleText('blue', '→ Pushing source code to Clever Cloud…')}
142
146
  `);
143
147
 
144
- await git.push(appData.deployUrl, commitIdToPush, force).catch(async (e) => {
148
+ const pushStart = Date.now();
149
+ await git.push(appData.deployUrl, commitIdToPush, force, slugify(appData.alias)).catch(async (e) => {
145
150
  const isShallow = await git.isShallow();
146
151
  if (isShallow) {
147
152
  throw new Error(
@@ -151,8 +156,9 @@ export const deployCommand = defineCommand({
151
156
  throw e;
152
157
  }
153
158
  });
159
+ const pushDuration = ((Date.now() - pushStart) / 1000).toFixed(1);
154
160
 
155
- await Logger.println(` ${styleText('green', '✓ Code pushed to Clever Cloud')}`);
161
+ await Logger.println(` ${styleText('green', `✓ Code pushed to Clever Cloud (${pushDuration}s)`)}`);
156
162
 
157
163
  return Log.watchDeploymentAndDisplayLogs({
158
164
  ownerId,
@@ -20,3 +20,23 @@ clever deploy [options]
20
20
  |`-q`, `--quiet`|Don't show logs during deployment|
21
21
  |`-p`, `--same-commit-policy` `<policy>`|What to do when local and remote commit are identical (error, ignore, restart, rebuild) (default: error)|
22
22
  |`-t`, `--tag` `<tag>`|Tag to push (none by default)|
23
+
24
+ ### 🧪 Experimental: System git backend
25
+
26
+ Clever Tools uses a current JS implementation for git operations. This works without requiring git to be installed on your system, but has some limitations:
27
+
28
+ * **HTTP-only**: cannot use SSH-based git protocols
29
+ * **Slow performance** on repositories with rewritten history (rebases, squashes)
30
+ * **Connection timeouts** on large repositories or when pushing big files, due to HTTP-based transfers
31
+
32
+ If you experience any of these issues, you can enable the **system git backend** which uses the `git` command installed on your system (it must be in your `PATH` environment variable).
33
+
34
+ ```bash
35
+ clever features enable system-git
36
+ ```
37
+
38
+ To disable and return to the current JS implementation:
39
+
40
+ ```bash
41
+ clever features disable system-git
42
+ ```
@@ -1,11 +1,12 @@
1
+ import { get as getUser } from '@clevercloud/client/esm/api/v2/organisation.js';
1
2
  import { releaseInfo as getLinuxInfos } from 'linux-release-info';
2
3
  import os from 'node:os';
3
4
  import pkg from '../../../package.json' with { type: 'json' };
5
+ import { config } from '../../config/config.js';
4
6
  import { defineCommand } from '../../lib/define-command.js';
5
7
  import { styleText } from '../../lib/style-text.js';
6
8
  import { Logger } from '../../logger.js';
7
- import { conf, loadOAuthConf } from '../../models/configuration.js';
8
- import * as User from '../../models/user.js';
9
+ import { sendToApi } from '../../models/send-to-api.js';
9
10
  import { humanJsonOutputFormatOption } from '../global.options.js';
10
11
 
11
12
  function getShell() {
@@ -37,29 +38,27 @@ function getTerminal() {
37
38
  return process.env.TERM_PROGRAM || process.env.TERMINAL_EMULATOR || process.env.TERM;
38
39
  }
39
40
 
41
+ function getAuthState({ hasToken, apiUser }) {
42
+ if (!hasToken) {
43
+ return 'not connected';
44
+ }
45
+ if (apiUser == null) {
46
+ return 'authentication failed';
47
+ }
48
+ return 'authenticated';
49
+ }
50
+
40
51
  export const diagCommand = defineCommand({
41
52
  description: 'Diagnose the current installation (prints various informations for support)',
42
53
  since: '1.6.0',
43
54
  options: {
44
55
  format: humanJsonOutputFormatOption,
45
56
  },
46
- args: [],
47
57
  async handler(options) {
48
- const { format } = options;
49
-
50
- /** @type {string} */
51
- const userId = await User.getCurrentId().catch(() => null);
52
- const authDetails = await loadOAuthConf();
53
-
54
- function getAuthState() {
55
- if (authDetails.token == null) {
56
- return 'not connected';
57
- }
58
- if (userId == null) {
59
- return 'authentication failed';
60
- }
61
- return 'authenticated';
62
- }
58
+ const activeProfile = config.profiles[0];
59
+ const user = await getUser({})
60
+ .then(sendToApi)
61
+ .catch(() => null);
63
62
 
64
63
  const formattedDiag = {
65
64
  version: pkg.version,
@@ -72,11 +71,15 @@ export const diagCommand = defineCommand({
72
71
  terminal: getTerminal(),
73
72
  isPackaged: process.pkg != null,
74
73
  execPath: process.execPath,
75
- configFile: conf.CONFIGURATION_FILE,
76
- authSource: authDetails.source,
77
- oAuthToken: authDetails.token,
78
- authState: getAuthState(),
79
- userId,
74
+ configFile: config.CONFIGURATION_FILE,
75
+ profile: activeProfile?.alias ?? null,
76
+ userId: activeProfile?.userId ?? user?.id ?? null,
77
+ authSource: activeProfile?.alias === '$env' ? 'environment variables' : 'configuration file',
78
+ oAuthToken: config.token,
79
+ loggedIn: user != null,
80
+ profileOverrides: activeProfile?.overrides ?? null,
81
+ // No longer useful but kept for compatibility reasons
82
+ authState: getAuthState({ hasToken: config.token != null, apiUser: user }),
80
83
  };
81
84
 
82
85
  const linuxInfos = await getLinuxInfos()
@@ -86,7 +89,7 @@ export const diagCommand = defineCommand({
86
89
  formattedDiag.linuxInfos = linuxInfos;
87
90
  }
88
91
 
89
- switch (format) {
92
+ switch (options.format) {
90
93
  case 'json': {
91
94
  Logger.printJson(formattedDiag);
92
95
  break;
@@ -111,23 +114,33 @@ export const diagCommand = defineCommand({
111
114
  Logger.println('Exec path ' + styleText('green', formattedDiag.execPath));
112
115
  Logger.println('Config file ' + styleText('green', formattedDiag.configFile));
113
116
 
114
- Logger.println('Auth source ' + styleText('green', formattedDiag.authSource));
115
-
116
- const token =
117
- formattedDiag.oAuthToken == null ? styleText('red', '(none)') : styleText('green', formattedDiag.oAuthToken);
118
- Logger.println('oAuth token ' + token);
119
-
120
- switch (formattedDiag.authState) {
121
- case 'authenticated': {
117
+ if (formattedDiag.profile != null) {
118
+ Logger.println('Profile ' + styleText('green', formattedDiag.profile));
119
+ if (formattedDiag.userId != null) {
122
120
  Logger.println('User ID ' + styleText('green', formattedDiag.userId));
123
- break;
124
- }
125
- case 'authentication failed': {
126
- Logger.println('User ID ' + styleText('red', 'Authentication failed'));
127
- break;
128
121
  }
129
- case 'not connected': {
130
- Logger.println('User ID ' + styleText('red', 'Not connected'));
122
+ Logger.println('Auth source ' + styleText('green', formattedDiag.authSource));
123
+ Logger.println('Auth token ' + styleText('green', formattedDiag.oAuthToken));
124
+ }
125
+
126
+ if (formattedDiag.profile == null) {
127
+ Logger.println('Auth state ' + styleText('red', 'not connected'));
128
+ } else if (formattedDiag.loggedIn) {
129
+ Logger.println('Auth state ' + styleText('green', 'valid token'));
130
+ } else {
131
+ Logger.println('Auth state ' + styleText('red', 'expired or revoked token'));
132
+ }
133
+
134
+ if (formattedDiag.profileOverrides != null) {
135
+ const overrideEntries = Object.entries(formattedDiag.profileOverrides).filter(([k, v]) => v != null);
136
+ if (overrideEntries.length > 0) {
137
+ const maxKeyLength = Math.max(...overrideEntries.map(([key]) => key.length));
138
+ const pad = maxKeyLength + 2;
139
+ Logger.println('');
140
+ Logger.println('Profile overrides:');
141
+ for (const [key, value] of overrideEntries) {
142
+ Logger.println(' ' + key.padEnd(pad) + styleText('green', value));
143
+ }
131
144
  }
132
145
  }
133
146
  }
@@ -1,7 +1,6 @@
1
- import { EXPERIMENTAL_FEATURES } from '../../experimental-features.js';
1
+ import { EXPERIMENTAL_FEATURES, setFeature } from '../../config/features.js';
2
2
  import { defineCommand } from '../../lib/define-command.js';
3
3
  import { Logger } from '../../logger.js';
4
- import { setFeature } from '../../models/configuration.js';
5
4
  import { featuresArg } from './features.args.js';
6
5
 
7
6
  export const featuresDisableCommand = defineCommand({
@@ -1,7 +1,6 @@
1
- import { EXPERIMENTAL_FEATURES } from '../../experimental-features.js';
1
+ import { EXPERIMENTAL_FEATURES, setFeature } from '../../config/features.js';
2
2
  import { defineCommand } from '../../lib/define-command.js';
3
3
  import { Logger } from '../../logger.js';
4
- import { setFeature } from '../../models/configuration.js';
5
4
  import { featuresArg } from './features.args.js';
6
5
 
7
6
  export const featuresEnableCommand = defineCommand({
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { EXPERIMENTAL_FEATURES } from '../../experimental-features.js';
2
+ import { EXPERIMENTAL_FEATURES } from '../../config/features.js';
3
3
  import { defineArgument } from '../../lib/define-argument.js';
4
4
  import { defineCommand } from '../../lib/define-command.js';
5
5
  import { Logger } from '../../logger.js';
@@ -1,8 +1,7 @@
1
- import { EXPERIMENTAL_FEATURES } from '../../experimental-features.js';
1
+ import { EXPERIMENTAL_FEATURES, getFeatures } from '../../config/features.js';
2
2
  import { formatTable } from '../../format-table.js';
3
3
  import { defineCommand } from '../../lib/define-command.js';
4
4
  import { Logger } from '../../logger.js';
5
- import { getFeatures } from '../../models/configuration.js';
6
5
  import { humanJsonOutputFormatOption } from '../global.options.js';
7
6
 
8
7
  export const featuresListCommand = defineCommand({
@@ -11,6 +11,13 @@ import { addonRenameCommand } from './addon/addon.rename.command.js';
11
11
  import { applicationsCommand } from './applications/applications.command.js';
12
12
  import { applicationsListCommand } from './applications/applications.list.command.js';
13
13
  import { cancelDeployCommand } from './cancel-deploy/cancel-deploy.command.js';
14
+ import { configProviderCommand } from './config-provider/config-provider.command.js';
15
+ import { configProviderGetCommand } from './config-provider/config-provider.get.command.js';
16
+ import { configProviderImportCommand } from './config-provider/config-provider.import.command.js';
17
+ import { configProviderListCommand } from './config-provider/config-provider.list.command.js';
18
+ import { configProviderOpenCommand } from './config-provider/config-provider.open.command.js';
19
+ import { configProviderRmCommand } from './config-provider/config-provider.rm.command.js';
20
+ import { configProviderSetCommand } from './config-provider/config-provider.set.command.js';
14
21
  import { configCommand } from './config/config.command.js';
15
22
  import { configGetCommand } from './config/config.get.command.js';
16
23
  import { configSetCommand } from './config/config.set.command.js';
@@ -125,7 +132,9 @@ import { otoroshiVersionCheckCommand } from './otoroshi/otoroshi.version.check.c
125
132
  import { otoroshiVersionCommand } from './otoroshi/otoroshi.version.command.js';
126
133
  import { otoroshiVersionUpdateCommand } from './otoroshi/otoroshi.version.update.command.js';
127
134
  import { profileCommand } from './profile/profile.command.js';
135
+ import { profileListCommand } from './profile/profile.list.command.js';
128
136
  import { profileOpenCommand } from './profile/profile.open.command.js';
137
+ import { profileSwitchCommand } from './profile/profile.switch.command.js';
129
138
  import { publishedConfigCommand } from './published-config/published-config.command.js';
130
139
  import { publishedConfigImportCommand } from './published-config/published-config.import.command.js';
131
140
  import { publishedConfigRmCommand } from './published-config/published-config.rm.command.js';
@@ -192,6 +201,17 @@ export const globalCommands = {
192
201
  update: configUpdateCommand,
193
202
  },
194
203
  ],
204
+ 'config-provider': [
205
+ configProviderCommand,
206
+ {
207
+ get: configProviderGetCommand,
208
+ import: configProviderImportCommand,
209
+ list: configProviderListCommand,
210
+ open: configProviderOpenCommand,
211
+ rm: configProviderRmCommand,
212
+ set: configProviderSetCommand,
213
+ },
214
+ ],
195
215
  console: consoleCommand,
196
216
  create: createCommand,
197
217
  curl: curlCommand,
@@ -400,7 +420,9 @@ export const globalCommands = {
400
420
  profile: [
401
421
  profileCommand,
402
422
  {
423
+ list: profileListCommand,
403
424
  open: profileOpenCommand,
425
+ switch: profileSwitchCommand,
404
426
  },
405
427
  ],
406
428
  'published-config': [
@@ -47,7 +47,7 @@ export const afterOption = defineOption({
47
47
  export const addonIdOption = defineOption({
48
48
  name: 'addon',
49
49
  schema: z.string().optional(),
50
- description: 'Add-on ID',
50
+ description: 'Add-on ID or real ID',
51
51
  placeholder: 'addon-id',
52
52
  });
53
53