@hubspot/cli 8.5.0-beta.1 → 8.6.0-beta.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 (64) hide show
  1. package/commands/account/clean.js +2 -0
  2. package/commands/account/createOverride.js +3 -0
  3. package/commands/account/info.js +34 -16
  4. package/commands/account/link.d.ts +4 -0
  5. package/commands/account/link.js +89 -0
  6. package/commands/account/list.js +29 -71
  7. package/commands/account/remove.js +2 -0
  8. package/commands/account/removeOverride.js +3 -0
  9. package/commands/account/unlink.d.ts +4 -0
  10. package/commands/account/unlink.js +70 -0
  11. package/commands/account/use.js +71 -1
  12. package/commands/account.js +4 -0
  13. package/commands/project/appInstallStatus.d.ts +4 -0
  14. package/commands/project/appInstallStatus.js +132 -0
  15. package/commands/project/create.js +8 -0
  16. package/commands/project/dev/deprecatedFlow.js +20 -2
  17. package/commands/project/dev/index.js +6 -0
  18. package/commands/project/dev/unifiedFlow.js +20 -3
  19. package/commands/project/lint.js +20 -2
  20. package/commands/project.js +2 -0
  21. package/lang/en.d.ts +102 -0
  22. package/lang/en.js +116 -8
  23. package/lib/app/migrate.js +2 -1
  24. package/lib/constants.d.ts +1 -0
  25. package/lib/constants.js +3 -0
  26. package/lib/doctor/Doctor.js +5 -5
  27. package/lib/link/accountTableUtils.d.ts +10 -0
  28. package/lib/link/accountTableUtils.js +39 -0
  29. package/lib/link/index.d.ts +18 -0
  30. package/lib/link/index.js +185 -0
  31. package/lib/link/linkUtils.d.ts +5 -0
  32. package/lib/link/linkUtils.js +49 -0
  33. package/lib/link/prompts.d.ts +7 -0
  34. package/lib/link/prompts.js +126 -0
  35. package/lib/link/renderLinkedAccountsTable.d.ts +2 -0
  36. package/lib/link/renderLinkedAccountsTable.js +14 -0
  37. package/lib/link/warnIfLinkedDirectory.d.ts +1 -0
  38. package/lib/link/warnIfLinkedDirectory.js +9 -0
  39. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +2 -1
  40. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
  41. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +2 -0
  42. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -0
  43. package/lib/projects/uieLinting.d.ts +17 -3
  44. package/lib/projects/uieLinting.js +93 -28
  45. package/lib/prompts/promptUtils.js +1 -0
  46. package/lib/ui/accountTable.d.ts +8 -0
  47. package/lib/ui/accountTable.js +67 -0
  48. package/mcp-server/server.js +39 -1
  49. package/mcp-server/tools/index.js +2 -0
  50. package/mcp-server/tools/project/AddFeatureToProjectTool.js +1 -1
  51. package/mcp-server/tools/project/CreateTestAccountTool.js +1 -1
  52. package/mcp-server/tools/project/DeployProjectTool.js +1 -1
  53. package/mcp-server/tools/project/FindProjectsTool.d.ts +15 -0
  54. package/mcp-server/tools/project/FindProjectsTool.js +60 -0
  55. package/mcp-server/tools/project/GetBuildLogsTool.js +1 -1
  56. package/mcp-server/tools/project/GetBuildStatusTool.js +1 -1
  57. package/mcp-server/tools/project/UploadProjectTools.js +1 -1
  58. package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
  59. package/package.json +2 -2
  60. package/types/Link.d.ts +32 -0
  61. package/types/Link.js +5 -0
  62. package/types/PackageJson.d.ts +1 -0
  63. package/types/Prompts.d.ts +1 -0
  64. package/types/Yargs.d.ts +1 -0
@@ -14,6 +14,7 @@ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
14
14
  import { commands } from '../../lang/en.js';
15
15
  import { uiLogger } from '../../lib/ui/logger.js';
16
16
  import { renderList } from '../../ui/render.js';
17
+ import { warnIfLinkedDirectory } from '../../lib/link/warnIfLinkedDirectory.js';
17
18
  const command = 'clean';
18
19
  const describe = commands.account.subcommands.clean.describe;
19
20
  async function handler(args) {
@@ -24,6 +25,7 @@ async function handler(args) {
24
25
  uiLogger.log(commands.account.subcommands.clean.noResults);
25
26
  return exit(EXIT_CODES.SUCCESS);
26
27
  }
28
+ warnIfLinkedDirectory(args._);
27
29
  const accountsToRemove = [];
28
30
  SpinniesManager.init({
29
31
  succeedColor: 'white',
@@ -12,11 +12,14 @@ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHand
12
12
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
13
13
  import { commands } from '../../lang/en.js';
14
14
  import { uiLogger } from '../../lib/ui/logger.js';
15
+ import { warnIfLinkedDirectory } from '../../lib/link/warnIfLinkedDirectory.js';
15
16
  const command = 'create-override [account]';
16
17
  const describe = commands.account.subcommands.createOverride.describe(DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME);
17
18
  async function handler(args) {
18
19
  const { exit } = args;
19
20
  let overrideDefaultAccount = args.account;
21
+ // TODO: Block this command when linked directory exists (next breaking change)
22
+ warnIfLinkedDirectory(args._);
20
23
  const globalConfigExists = globalConfigFileExists();
21
24
  if (!globalConfigExists) {
22
25
  uiLogger.error(commands.account.subcommands.createOverride.errors.globalConfigNotFound);
@@ -1,6 +1,9 @@
1
1
  import { getConfigAccountById, getConfigDefaultAccount, getConfigFilePath, } from '@hubspot/local-dev-lib/config';
2
2
  import { getDefaultAccountOverrideFilePath } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
3
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
4
+ import { isDirectoryLinked } from '../../lib/link/linkUtils.js';
3
5
  import { getAccessToken } from '@hubspot/local-dev-lib/personalAccessKey';
6
+ import { uiAccountDescription } from '../../lib/ui/index.js';
4
7
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
5
8
  import { indent } from '../../lib/ui/index.js';
6
9
  import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
@@ -9,31 +12,46 @@ import { uiLogger } from '../../lib/ui/logger.js';
9
12
  import { renderList } from '../../ui/render.js';
10
13
  const describe = commands.account.subcommands.info.describe;
11
14
  const command = 'info [account]';
15
+ function logLinkedAccountInfo(hsSettingsPath, localDefaultAccount) {
16
+ uiLogger.log(commands.account.subcommands.info.linkedDefaultTitle);
17
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.info.settingsPath(hsSettingsPath)}`);
18
+ if (localDefaultAccount) {
19
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.info.linkedDefault(uiAccountDescription(localDefaultAccount))}`);
20
+ }
21
+ }
22
+ function logGlobalAccountInfo() {
23
+ const configPath = getConfigFilePath();
24
+ if (configPath) {
25
+ uiLogger.log(commands.account.subcommands.info.defaultAccountTitle);
26
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.info.configPath(configPath)}`);
27
+ const defaultAccount = getConfigDefaultAccount();
28
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.info.defaultAccount(defaultAccount.name)}`);
29
+ }
30
+ const overrideFilePath = getDefaultAccountOverrideFilePath();
31
+ if (overrideFilePath) {
32
+ uiLogger.log('');
33
+ uiLogger.log(commands.account.subcommands.info.overrideFilePathTitle);
34
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.info.overrideFilePath(overrideFilePath)}`);
35
+ const defaultAccount = getConfigDefaultAccount();
36
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.info.overrideAccount(defaultAccount.name)}`);
37
+ }
38
+ }
12
39
  async function handler(args) {
13
40
  const { derivedAccountId } = args;
14
41
  const config = getConfigAccountById(derivedAccountId);
15
- // check if the provided account is using a personal access key, if not, show an error
16
42
  if (config && config.authType === 'personalaccesskey') {
17
43
  const { name, personalAccessKey, env } = config;
18
44
  let scopeGroups = [];
19
45
  const response = await getAccessToken(personalAccessKey, env, derivedAccountId);
20
46
  scopeGroups = response.scopeGroups.map(s => [s]);
21
- // If a default account is present in the config, display it
22
- const configPath = getConfigFilePath();
23
- if (configPath) {
24
- uiLogger.log(commands.account.subcommands.info.defaultAccountTitle);
25
- uiLogger.log(`${indent(1)}${commands.account.subcommands.info.configPath(configPath)}`);
26
- const defaultAccount = getConfigDefaultAccount();
27
- uiLogger.log(`${indent(1)}${commands.account.subcommands.info.defaultAccount(defaultAccount.name)}`);
47
+ const hsSettings = getHsSettingsFileIfExists();
48
+ const hsSettingsPath = getHsSettingsFilePath();
49
+ const isLinked = isDirectoryLinked(hsSettings) && hsSettingsPath !== null;
50
+ if (isLinked) {
51
+ logLinkedAccountInfo(hsSettingsPath, hsSettings.localDefaultAccount);
28
52
  }
29
- // If a default account override is present, display it
30
- const overrideFilePath = getDefaultAccountOverrideFilePath();
31
- if (overrideFilePath) {
32
- uiLogger.log('');
33
- uiLogger.log(commands.account.subcommands.info.overrideFilePathTitle);
34
- uiLogger.log(`${indent(1)}${commands.account.subcommands.info.overrideFilePath(overrideFilePath)}`);
35
- const defaultAccount = getConfigDefaultAccount();
36
- uiLogger.log(`${indent(1)}${commands.account.subcommands.info.overrideAccount(defaultAccount.name)}`);
53
+ else {
54
+ logGlobalAccountInfo();
37
55
  }
38
56
  uiLogger.log('');
39
57
  uiLogger.log(commands.account.subcommands.info.name(name));
@@ -0,0 +1,4 @@
1
+ import { YargsCommandModule } from '../../types/Yargs.js';
2
+ import { LinkArgs } from '../../types/Link.js';
3
+ declare const linkCommand: YargsCommandModule<unknown, LinkArgs>;
4
+ export default linkCommand;
@@ -0,0 +1,89 @@
1
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
2
+ import { uiLogger } from '../../lib/ui/logger.js';
3
+ import { getAllConfigAccounts } from '@hubspot/local-dev-lib/config';
4
+ import { getCwd } from '@hubspot/local-dev-lib/path';
5
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
7
+ import { getDefaultAccountOverrideAccountId } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
8
+ import { checkAndAddHsFolderToGitignore } from '@hubspot/local-dev-lib/gitignore';
9
+ import { DEFAULT_HS_SETTINGS_PATH, EMPTY_HS_SETTINGS_FILE, } from '@hubspot/local-dev-lib/constants/config';
10
+ import { ACTION_RESULT_STATUS } from '../../types/Link.js';
11
+ import { handleLinkFlow } from '../../lib/link/index.js';
12
+ import { hasDeprecatedConfigConflict, writeLinkedSettings, } from '../../lib/link/linkUtils.js';
13
+ import { renderLinkedAccountsTable } from '../../lib/link/renderLinkedAccountsTable.js';
14
+ import { commands } from '../../lang/en.js';
15
+ import { debugError } from '../../lib/errorHandlers/index.js';
16
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
17
+ const command = 'link';
18
+ // Hide the command until we're done testing and ready to make linking GA
19
+ // const describe = commands.account.subcommands.link.describe;
20
+ const describe = undefined;
21
+ async function handler(args) {
22
+ const { exit } = args;
23
+ if (hasDeprecatedConfigConflict(args._)) {
24
+ return exit(EXIT_CODES.ERROR);
25
+ }
26
+ const existingSettings = getHsSettingsFileIfExists();
27
+ const isNewFile = existingSettings === null;
28
+ if (isNewFile) {
29
+ uiLogger.log(commands.account.subcommands.link.linkingDirectory(getCwd()));
30
+ }
31
+ else {
32
+ uiLogger.log(commands.account.subcommands.link.managingLinkedAccounts(getCwd()));
33
+ }
34
+ uiLogger.log('');
35
+ const settingsFilePath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
36
+ uiLogger.log(commands.account.subcommands.link.settingsInfo(settingsFilePath));
37
+ uiLogger.log('');
38
+ const settings = isNewFile ? EMPTY_HS_SETTINGS_FILE : existingSettings;
39
+ const accounts = getAllConfigAccounts();
40
+ const accountOverrideId = getDefaultAccountOverrideAccountId(accounts);
41
+ if (settings.accounts.length !== 0) {
42
+ await renderLinkedAccountsTable(settings);
43
+ uiLogger.log('');
44
+ }
45
+ const result = await handleLinkFlow({
46
+ settings,
47
+ accountOverrideId,
48
+ args,
49
+ });
50
+ if (result.status === ACTION_RESULT_STATUS.ERROR) {
51
+ uiLogger.error(result.reason);
52
+ return exit(EXIT_CODES.ERROR);
53
+ }
54
+ if (result.status === ACTION_RESULT_STATUS.NOOP) {
55
+ return exit(EXIT_CODES.SUCCESS);
56
+ }
57
+ const settingsPath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
58
+ if (!writeLinkedSettings(result.settings, settingsPath)) {
59
+ return exit(EXIT_CODES.ERROR);
60
+ }
61
+ try {
62
+ checkAndAddHsFolderToGitignore(settingsPath);
63
+ }
64
+ catch (e) {
65
+ debugError(e);
66
+ }
67
+ if (isNewFile) {
68
+ uiLogger.success(commands.account.subcommands.link.success.created(settingsPath));
69
+ }
70
+ else {
71
+ uiLogger.success(commands.account.subcommands.link.shared.savedToSettings(settingsPath));
72
+ }
73
+ return exit(EXIT_CODES.SUCCESS);
74
+ }
75
+ function linkBuilder(yargs) {
76
+ yargs.example([['$0 link']]);
77
+ return yargs;
78
+ }
79
+ const builder = makeYargsBuilder(linkBuilder, command, commands.account.subcommands.link.verboseDescribe, {
80
+ useGlobalOptions: true,
81
+ useConfigOptions: true,
82
+ });
83
+ const linkCommand = {
84
+ command,
85
+ describe,
86
+ handler: makeYargsHandlerWithUsageTracking('account-link', handler),
87
+ builder,
88
+ };
89
+ export default linkCommand;
@@ -1,92 +1,50 @@
1
- import { getConfigFilePath, getAllConfigAccounts, getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
1
+ import { getConfigFilePath, getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
2
2
  import { getDefaultAccountOverrideFilePath } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
3
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
4
+ import { getCwd } from '@hubspot/local-dev-lib/path';
3
5
  import { indent } from '../../lib/ui/index.js';
4
- import { isSandbox, isDeveloperTestAccount } from '../../lib/accountTypes.js';
5
- import { HUBSPOT_ACCOUNT_TYPES, HUBSPOT_ACCOUNT_TYPE_STRINGS, } from '@hubspot/local-dev-lib/constants/config';
6
6
  import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
7
7
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
8
8
  import { uiLogger } from '../../lib/ui/logger.js';
9
9
  import { commands } from '../../lang/en.js';
10
- import { renderTable } from '../../ui/render.js';
10
+ import { renderAccountTable } from '../../lib/ui/accountTable.js';
11
+ import { renderLinkedAccountsTable } from '../../lib/link/renderLinkedAccountsTable.js';
12
+ import { isDirectoryLinked } from '../../lib/link/linkUtils.js';
11
13
  const command = ['list', 'ls'];
12
14
  const describe = commands.account.subcommands.list.describe;
13
- function sortAndMapAccounts(accounts) {
14
- const mappedAccountData = {};
15
- // Standard and app developer accounts
16
- accounts
17
- .filter(p => p.accountType &&
18
- (p.accountType === HUBSPOT_ACCOUNT_TYPES.STANDARD ||
19
- p.accountType === HUBSPOT_ACCOUNT_TYPES.APP_DEVELOPER))
20
- .forEach(account => {
21
- mappedAccountData[account.accountId] = [account];
22
- });
23
- // Non-standard accounts (sandbox, developer test account)
24
- accounts
25
- .filter(p => p.accountType && (isSandbox(p) || isDeveloperTestAccount(p)))
26
- .forEach(p => {
27
- if (p.parentAccountId) {
28
- mappedAccountData[p.parentAccountId] = [
29
- ...(mappedAccountData[p.parentAccountId] || []),
30
- p,
31
- ];
32
- }
33
- else {
34
- mappedAccountData[p.accountId] = [p];
35
- }
36
- });
37
- return mappedAccountData;
38
- }
39
- function getAccountData(mappedAccountData) {
40
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
- const accountData = [];
42
- Object.entries(mappedAccountData).forEach(([key, set]) => {
43
- const hasParentAccount = set.filter(p => p.accountId === parseInt(key, 10))[0];
44
- set.forEach(account => {
45
- let name = `${account.name} [${HUBSPOT_ACCOUNT_TYPE_STRINGS[account.accountType]}]`;
46
- if (isSandbox(account)) {
47
- if (hasParentAccount && set.length > 1) {
48
- name = `↳ ${name}`;
49
- }
50
- }
51
- else if (isDeveloperTestAccount(account)) {
52
- if (hasParentAccount && set.length > 1) {
53
- name = `↳ ${name}`;
54
- }
55
- }
56
- accountData.push([name, account.accountId, account.authType]);
57
- });
58
- });
59
- return accountData;
60
- }
61
15
  async function handler() {
62
16
  const configPath = getConfigFilePath();
63
- const accountsList = getAllConfigAccounts();
64
- const mappedAccountData = sortAndMapAccounts(accountsList);
65
- const accountData = getAccountData(mappedAccountData);
66
- const tableHeader = [
67
- commands.account.subcommands.list.labels.name,
68
- commands.account.subcommands.list.labels.accountId,
69
- commands.account.subcommands.list.labels.authType,
70
- ];
71
17
  const defaultAccount = getConfigDefaultAccountIfExists();
72
18
  const accountId = defaultAccount?.accountId;
73
19
  const overrideFilePath = getDefaultAccountOverrideFilePath();
74
- // If a default account is present in the config, display it
75
- if (configPath && accountId) {
76
- uiLogger.log(commands.account.subcommands.list.defaultAccountTitle);
77
- uiLogger.log(`${indent(1)}${commands.account.subcommands.list.configPath(configPath)}`);
78
- uiLogger.log(`${indent(1)}${commands.account.subcommands.list.currentResolvedDefaultAccount(accountId)}`);
20
+ const hsSettings = getHsSettingsFileIfExists();
21
+ const hsSettingsPath = getHsSettingsFilePath();
22
+ const isLinked = isDirectoryLinked(hsSettings);
23
+ if (isLinked && hsSettingsPath) {
24
+ uiLogger.log(commands.account.subcommands.list.linkedDefaultTitle);
25
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.list.directory(getCwd())}`);
26
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.list.configPath(hsSettingsPath)}`);
27
+ if (hsSettings.localDefaultAccount) {
28
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.list.currentResolvedDefaultAccount(hsSettings.localDefaultAccount)}`);
29
+ }
30
+ uiLogger.log('');
31
+ uiLogger.log(commands.account.subcommands.list.linkedAccounts);
32
+ await renderLinkedAccountsTable(hsSettings);
79
33
  uiLogger.log('');
80
34
  }
81
- // If a default account override is present, display it
82
- if (overrideFilePath && accountId) {
83
- uiLogger.log(commands.account.subcommands.list.overrideFilePathTitle);
84
- uiLogger.log(`${indent(1)}${commands.account.subcommands.list.overrideFilePath(overrideFilePath)}`);
35
+ if (!isLinked && configPath && accountId) {
36
+ uiLogger.log(commands.account.subcommands.list.defaultAccountTitle);
37
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.list.configPath(configPath)}`);
85
38
  uiLogger.log(`${indent(1)}${commands.account.subcommands.list.currentResolvedDefaultAccount(accountId)}`);
86
39
  uiLogger.log('');
40
+ if (overrideFilePath) {
41
+ uiLogger.log(commands.account.subcommands.list.overrideFilePathTitle);
42
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.list.overrideFilePath(overrideFilePath)}`);
43
+ uiLogger.log(`${indent(1)}${commands.account.subcommands.list.currentResolvedDefaultAccount(accountId)}`);
44
+ uiLogger.log('');
45
+ }
87
46
  }
88
- uiLogger.log(commands.account.subcommands.list.accounts);
89
- renderTable(tableHeader, accountData, true);
47
+ renderAccountTable(isLinked);
90
48
  }
91
49
  function accountListBuilder(yargs) {
92
50
  yargs.example([['$0 accounts list']]);
@@ -8,9 +8,11 @@ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHand
8
8
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
9
  import { uiLogger } from '../../lib/ui/logger.js';
10
10
  import { commands } from '../../lang/en.js';
11
+ import { warnIfLinkedDirectory } from '../../lib/link/warnIfLinkedDirectory.js';
11
12
  const command = 'remove [account]';
12
13
  const describe = commands.account.subcommands.remove.describe;
13
14
  async function handler(args) {
15
+ warnIfLinkedDirectory(args._);
14
16
  const { account: accountFlag } = args;
15
17
  let accountToRemoveConfig = accountFlag
16
18
  ? getConfigAccountIfExists(accountFlag)
@@ -9,10 +9,13 @@ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHand
9
9
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
10
10
  import { uiLogger } from '../../lib/ui/logger.js';
11
11
  import { commands } from '../../lang/en.js';
12
+ import { warnIfLinkedDirectory } from '../../lib/link/warnIfLinkedDirectory.js';
12
13
  const command = 'remove-override';
13
14
  const describe = commands.account.subcommands.removeOverride.describe(DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME);
14
15
  async function handler(args) {
15
16
  const { force, exit } = args;
17
+ // TODO: Block this command when linked directory exists (next breaking change)
18
+ warnIfLinkedDirectory(args._);
16
19
  const globalConfigExists = globalConfigFileExists();
17
20
  if (!globalConfigExists) {
18
21
  uiLogger.error(commands.account.subcommands.removeOverride.errors.globalConfigNotFound);
@@ -0,0 +1,4 @@
1
+ import { YargsCommandModule } from '../../types/Yargs.js';
2
+ import { LinkArgs } from '../../types/Link.js';
3
+ declare const unlinkCommand: YargsCommandModule<unknown, LinkArgs>;
4
+ export default unlinkCommand;
@@ -0,0 +1,70 @@
1
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
2
+ import { uiLogger } from '../../lib/ui/logger.js';
3
+ import { getAllConfigAccounts } from '@hubspot/local-dev-lib/config';
4
+ import { getCwd } from '@hubspot/local-dev-lib/path';
5
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
7
+ import { ACTION_RESULT_STATUS } from '../../types/Link.js';
8
+ import { ActionHandlers } from '../../lib/link/index.js';
9
+ import { hasDeprecatedConfigConflict, isDirectoryLinked, writeLinkedSettings, } from '../../lib/link/linkUtils.js';
10
+ import { commands } from '../../lang/en.js';
11
+ import { DEFAULT_HS_SETTINGS_PATH } from '@hubspot/local-dev-lib/constants/config';
12
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
13
+ const command = 'unlink';
14
+ // Hide the command until we're done testing and ready to make linking GA
15
+ // const describe = commands.account.subcommands.link.describe;
16
+ const describe = undefined;
17
+ async function handler(args) {
18
+ const { exit } = args;
19
+ if (hasDeprecatedConfigConflict(args._)) {
20
+ return exit(EXIT_CODES.ERROR);
21
+ }
22
+ const existingSettings = getHsSettingsFileIfExists();
23
+ if (!isDirectoryLinked(existingSettings)) {
24
+ const globalAccounts = getAllConfigAccounts();
25
+ uiLogger.log(commands.account.subcommands.link.shared.noLinkedAccounts);
26
+ uiLogger.log(commands.account.subcommands.link.shared.globalAccountsAvailable(globalAccounts.length));
27
+ uiLogger.log('');
28
+ uiLogger.log(commands.account.subcommands.link.shared.configurePrompt);
29
+ return exit(EXIT_CODES.SUCCESS);
30
+ }
31
+ uiLogger.log(commands.account.subcommands.link.managingLinkedAccounts(getCwd()));
32
+ uiLogger.log('');
33
+ const result = await ActionHandlers.unlink({
34
+ state: existingSettings,
35
+ context: {
36
+ globalAccountsList: getAllConfigAccounts(),
37
+ globalDefaultAccount: undefined,
38
+ accountOverrideId: null,
39
+ },
40
+ args,
41
+ });
42
+ if (result.status === ACTION_RESULT_STATUS.ERROR) {
43
+ uiLogger.error(result.reason);
44
+ return exit(EXIT_CODES.ERROR);
45
+ }
46
+ if (result.status === ACTION_RESULT_STATUS.NOOP) {
47
+ return exit(EXIT_CODES.SUCCESS);
48
+ }
49
+ const settingsPath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
50
+ if (!writeLinkedSettings(result.settings, settingsPath)) {
51
+ return exit(EXIT_CODES.ERROR);
52
+ }
53
+ uiLogger.success(commands.account.subcommands.link.shared.savedToSettings(settingsPath));
54
+ return exit(EXIT_CODES.SUCCESS);
55
+ }
56
+ function unlinkBuilder(yargs) {
57
+ yargs.example([['$0 account unlink']]);
58
+ return yargs;
59
+ }
60
+ const builder = makeYargsBuilder(unlinkBuilder, command, commands.account.subcommands.unlink.verboseDescribe, {
61
+ useGlobalOptions: true,
62
+ useConfigOptions: true,
63
+ });
64
+ const unlinkCommand = {
65
+ command,
66
+ describe,
67
+ handler: makeYargsHandlerWithUsageTracking('account-unlink', handler),
68
+ builder,
69
+ };
70
+ export default unlinkCommand;
@@ -1,5 +1,7 @@
1
1
  import { getConfigFilePath, setConfigAccountAsDefault, getConfigAccountIfExists, getConfigAccountByName, getConfigAccountById, globalConfigFileExists, getAllConfigAccounts, } from '@hubspot/local-dev-lib/config';
2
2
  import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
3
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, writeHsSettingsFile, } from '@hubspot/local-dev-lib/config/hsSettings';
4
+ import { getCwd } from '@hubspot/local-dev-lib/path';
3
5
  import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
4
6
  import { commands } from '../../lang/en.js';
5
7
  import { uiLogger } from '../../lib/ui/logger.js';
@@ -8,9 +10,69 @@ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHand
8
10
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
11
  import { authenticateNewAccount } from '../../lib/accountAuth.js';
10
12
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
13
+ import { confirmPrompt } from '../../lib/prompts/promptUtils.js';
14
+ import { handleLinkedUseAction } from '../../lib/link/index.js';
15
+ import { isDirectoryLinked } from '../../lib/link/linkUtils.js';
16
+ import { ACTION_RESULT_STATUS } from '../../types/Link.js';
17
+ import { DEFAULT_HS_SETTINGS_PATH } from '@hubspot/local-dev-lib/constants/config';
11
18
  const command = 'use [account]';
12
19
  const describe = commands.account.subcommands.use.describe;
13
- async function handler(args) {
20
+ async function handleLinkedUse(args, hsSettings) {
21
+ const { exit } = args;
22
+ uiLogger.log(commands.account.subcommands.use.linked.editingLinkedDefault(getCwd()));
23
+ uiLogger.log('');
24
+ if (!args.account && hsSettings.accounts.length === 1) {
25
+ uiLogger.log(commands.account.subcommands.use.linked.alreadyDefault(hsSettings.accounts[0]));
26
+ return exit(EXIT_CODES.SUCCESS);
27
+ }
28
+ let targetAccountId;
29
+ if (args.account) {
30
+ const account = getConfigAccountIfExists(args.account);
31
+ if (!account) {
32
+ uiLogger.error(commands.account.subcommands.use.errors.accountNotFound(args.account, getConfigFilePath()));
33
+ return exit(EXIT_CODES.ERROR);
34
+ }
35
+ if (!hsSettings.accounts.includes(account.accountId)) {
36
+ if (!process.stdin.isTTY) {
37
+ uiLogger.log(commands.account.subcommands.use.linked.nonInteractiveNotLinked(account.name));
38
+ setConfigAccountAsDefault(String(args.account));
39
+ uiLogger.success(commands.account.subcommands.use.success.defaultAccountUpdated(account.name));
40
+ return exit(EXIT_CODES.SUCCESS);
41
+ }
42
+ uiLogger.log(commands.account.subcommands.use.linked.accountNotLinked(account.name));
43
+ const shouldLink = await confirmPrompt(commands.account.subcommands.use.linked.promptToLink(account.name));
44
+ if (!shouldLink) {
45
+ uiLogger.log(commands.account.subcommands.use.linked.settingGlobalDefault);
46
+ setConfigAccountAsDefault(String(args.account));
47
+ uiLogger.success(commands.account.subcommands.use.success.defaultAccountUpdated(account.name));
48
+ return exit(EXIT_CODES.SUCCESS);
49
+ }
50
+ }
51
+ targetAccountId = account.accountId;
52
+ }
53
+ const result = await handleLinkedUseAction({
54
+ state: hsSettings,
55
+ targetAccountId,
56
+ });
57
+ if (result.status === ACTION_RESULT_STATUS.ERROR) {
58
+ uiLogger.error(result.reason);
59
+ return exit(EXIT_CODES.ERROR);
60
+ }
61
+ if (result.status === ACTION_RESULT_STATUS.NOOP) {
62
+ return exit(EXIT_CODES.SUCCESS);
63
+ }
64
+ const settingsPath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
65
+ try {
66
+ writeHsSettingsFile(result.settings);
67
+ }
68
+ catch (err) {
69
+ uiLogger.error(commands.account.subcommands.link.shared.writeSettingsFailed(settingsPath, err));
70
+ return exit(EXIT_CODES.ERROR);
71
+ }
72
+ uiLogger.success(commands.account.subcommands.link.shared.savedToSettings(settingsPath));
73
+ return exit(EXIT_CODES.SUCCESS);
74
+ }
75
+ async function handleGlobalUse(args) {
14
76
  const { exit } = args;
15
77
  let newDefaultAccount = args.account;
16
78
  const usingGlobalConfig = globalConfigFileExists();
@@ -52,6 +114,14 @@ async function handler(args) {
52
114
  setConfigAccountAsDefault(String(newDefaultAccount));
53
115
  return uiLogger.success(commands.account.subcommands.use.success.defaultAccountUpdated(account.name));
54
116
  }
117
+ async function handler(args) {
118
+ const hsSettings = getHsSettingsFileIfExists();
119
+ const isLinked = isDirectoryLinked(hsSettings);
120
+ if (isLinked) {
121
+ return handleLinkedUse(args, hsSettings);
122
+ }
123
+ return handleGlobalUse(args);
124
+ }
55
125
  function accountUseBuilder(yargs) {
56
126
  yargs.positional('account', {
57
127
  describe: commands.account.subcommands.use.options.account.describe,
@@ -8,12 +8,16 @@ import remove from './account/remove.js';
8
8
  import clean from './account/clean.js';
9
9
  import createOverride from './account/createOverride.js';
10
10
  import removeOverride from './account/removeOverride.js';
11
+ import link from './account/link.js';
12
+ import unlink from './account/unlink.js';
11
13
  import { makeYargsBuilder } from '../lib/yargsUtils.js';
12
14
  const command = ['account', 'accounts'];
13
15
  const describe = commands.account.describe;
14
16
  function accountBuilder(yargs) {
15
17
  yargs
16
18
  .command(auth)
19
+ .command(link)
20
+ .command(unlink)
17
21
  .command(list)
18
22
  .command(rename)
19
23
  .command(use)
@@ -0,0 +1,4 @@
1
+ import { AccountArgs, CommonArgs, ConfigArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
+ type ProjectInstallStatusArgs = CommonArgs & ConfigArgs & AccountArgs & JSONOutputArgs;
3
+ declare const projectInstallStatusCommand: YargsCommandModule<unknown, ProjectInstallStatusArgs>;
4
+ export default projectInstallStatusCommand;