@hubspot/cli 7.8.0-beta.0 → 7.8.0-beta.1

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 (90) hide show
  1. package/commands/__tests__/project.test.js +2 -0
  2. package/commands/account/auth.js +1 -0
  3. package/commands/auth.js +1 -0
  4. package/commands/feedback.js +1 -1
  5. package/commands/project/__tests__/add.test.js +12 -12
  6. package/commands/project/__tests__/list.test.js +31 -0
  7. package/commands/project/__tests__/migrate.test.js +1 -0
  8. package/commands/project/add.d.ts +2 -2
  9. package/commands/project/add.js +3 -2
  10. package/commands/project/create.js +1 -1
  11. package/commands/project/dev/deprecatedFlow.js +2 -2
  12. package/commands/project/dev/index.js +5 -5
  13. package/commands/project/dev/unifiedFlow.js +6 -3
  14. package/commands/project/download.js +5 -2
  15. package/commands/project/installDeps.d.ts +2 -2
  16. package/commands/project/installDeps.js +1 -0
  17. package/commands/project/list.d.ts +4 -0
  18. package/commands/project/list.js +62 -0
  19. package/commands/project/migrate.js +5 -2
  20. package/commands/project.js +2 -0
  21. package/commands/sandbox/delete.js +5 -2
  22. package/commands/testAccount/create.js +2 -2
  23. package/commands/theme/preview.js +1 -4
  24. package/lang/en.d.ts +49 -14
  25. package/lang/en.js +121 -86
  26. package/lang/en.lyaml +2 -2
  27. package/lib/__tests__/buildAccount.test.js +2 -2
  28. package/lib/app/migrate.js +1 -1
  29. package/lib/buildAccount.d.ts +2 -2
  30. package/lib/buildAccount.js +7 -7
  31. package/lib/configMigrate.js +88 -9
  32. package/lib/constants.d.ts +8 -1
  33. package/lib/constants.js +8 -1
  34. package/lib/doctor/Doctor.js +2 -2
  35. package/lib/errorHandlers/suppressError.js +2 -2
  36. package/lib/middleware/commandTargetingUtils.d.ts +1 -1
  37. package/lib/middleware/commandTargetingUtils.js +16 -20
  38. package/lib/projects/__tests__/AppDevModeInterface.test.js +85 -90
  39. package/lib/projects/__tests__/LocalDevProcess.test.js +6 -5
  40. package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +6 -6
  41. package/lib/projects/__tests__/deploy.test.js +9 -9
  42. package/lib/projects/__tests__/upload.test.js +2 -2
  43. package/lib/projects/add/__tests__/{v3AddComponent.test.js → v2AddComponent.test.js} +35 -35
  44. package/lib/projects/add/{v3AddComponent.d.ts → v2AddComponent.d.ts} +1 -1
  45. package/lib/projects/add/{v3AddComponent.js → v2AddComponent.js} +5 -5
  46. package/lib/projects/create/__tests__/v2.test.d.ts +1 -0
  47. package/lib/projects/create/__tests__/{v3.test.js → v2.test.js} +2 -2
  48. package/lib/projects/create/index.js +2 -2
  49. package/lib/projects/create/{v3.d.ts → v2.d.ts} +3 -3
  50. package/lib/projects/create/{v3.js → v2.js} +3 -3
  51. package/lib/projects/deploy.d.ts +1 -1
  52. package/lib/projects/deploy.js +2 -2
  53. package/lib/projects/localDev/AppDevModeInterface.d.ts +8 -1
  54. package/lib/projects/localDev/AppDevModeInterface.js +106 -86
  55. package/lib/projects/localDev/DevServerManager.d.ts +11 -29
  56. package/lib/projects/localDev/DevServerManager.js +19 -61
  57. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +40 -0
  58. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +120 -0
  59. package/lib/projects/localDev/{LocalDevManager.js → LocalDevManager_DEPRECATED.js} +6 -6
  60. package/lib/projects/localDev/LocalDevProcess.js +3 -2
  61. package/lib/projects/localDev/LocalDevState.d.ts +3 -0
  62. package/lib/projects/localDev/LocalDevState.js +9 -0
  63. package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +4 -0
  64. package/lib/projects/localDev/LocalDevWebsocketServer.js +34 -2
  65. package/lib/projects/localDev/helpers/account.d.ts +1 -1
  66. package/lib/projects/localDev/helpers/account.js +2 -2
  67. package/lib/projects/localDev/helpers/project.js +2 -3
  68. package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +3 -0
  69. package/lib/projects/localDev/localDevWebsocketServerUtils.js +9 -0
  70. package/lib/projects/urls.d.ts +0 -1
  71. package/lib/projects/urls.js +0 -3
  72. package/lib/prompts/__tests__/downloadProjectPrompt.test.js +1 -0
  73. package/lib/prompts/__tests__/projectAddPrompt.test.js +10 -10
  74. package/lib/prompts/installAppPrompt.d.ts +1 -6
  75. package/lib/prompts/installAppPrompt.js +1 -6
  76. package/lib/prompts/projectAddPrompt.d.ts +2 -2
  77. package/lib/prompts/projectAddPrompt.js +1 -1
  78. package/lib/prompts/projectDevTargetAccountPrompt.js +1 -1
  79. package/lib/theme/__tests__/migrate.test.js +4 -4
  80. package/lib/ui/index.d.ts +4 -0
  81. package/lib/ui/index.js +9 -1
  82. package/lib/ui/uiMessages.d.ts +4 -0
  83. package/lib/ui/uiMessages.js +4 -0
  84. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
  85. package/package.json +6 -5
  86. package/lib/projects/localDev/DevServerManagerV2.d.ts +0 -22
  87. package/lib/projects/localDev/DevServerManagerV2.js +0 -81
  88. /package/{lib/projects/add/__tests__/v3AddComponent.test.d.ts → commands/project/__tests__/list.test.d.ts} +0 -0
  89. /package/lib/projects/{create/__tests__/v3.test.d.ts → add/__tests__/v2AddComponent.test.d.ts} +0 -0
  90. /package/lib/projects/localDev/{LocalDevManager.d.ts → LocalDevManager_DEPRECATED.d.ts} +0 -0
@@ -15,6 +15,7 @@ import cloneApp from '../project/cloneApp.js';
15
15
  import installDeps from '../project/installDeps.js';
16
16
  import validate from '../project/validate.js';
17
17
  import profileCommands from '../project/profile.js';
18
+ import list from '../project/list.js';
18
19
  import projectCommand from '../project.js';
19
20
  vi.mock('../project/deploy');
20
21
  vi.mock('../project/create');
@@ -73,6 +74,7 @@ describe('commands/project', () => {
73
74
  installDeps,
74
75
  profileCommands,
75
76
  validate,
77
+ list,
76
78
  ];
77
79
  it('should demand the command takes one positional argument', () => {
78
80
  projectCommand.builder(yargs);
@@ -141,6 +141,7 @@ async function handler(args) {
141
141
  await setAsDefaultAccountPrompt(updatedConfig.name);
142
142
  }
143
143
  uiFeatureHighlight([
144
+ 'getStartedCommand',
144
145
  'helpCommand',
145
146
  'accountAuthCommand',
146
147
  'accountsListCommand',
package/commands/auth.js CHANGED
@@ -121,6 +121,7 @@ async function handler(args) {
121
121
  await setAsDefaultAccountPrompt(accountName);
122
122
  uiLogger.success(commands.auth.success.configFileUpdated(accountName, DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME, successAuthMethod));
123
123
  uiFeatureHighlight([
124
+ 'getStartedCommand',
124
125
  'accountsUseCommand',
125
126
  'accountOption',
126
127
  'accountsListCommand',
@@ -11,7 +11,7 @@ async function handler() {
11
11
  const shouldOpen = await confirmPrompt(commands.project.feedback.openPrompt);
12
12
  if (!shouldOpen) {
13
13
  uiLogger.log(commands.project.feedback.error(FEEDBACK_URL));
14
- process.exit(EXIT_CODES.ERROR);
14
+ process.exit(EXIT_CODES.SUCCESS);
15
15
  }
16
16
  open(FEEDBACK_URL, { url: true });
17
17
  uiLogger.success(commands.project.feedback.success(FEEDBACK_URL));
@@ -1,7 +1,7 @@
1
1
  import yargs from 'yargs';
2
2
  import projectAddCommand from '../add.js';
3
3
  import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../../lib/constants.js';
4
- import { v3AddComponent } from '../../../lib/projects/add/v3AddComponent.js';
4
+ import { v2AddComponent } from '../../../lib/projects/add/v2AddComponent.js';
5
5
  import { legacyAddComponent } from '../../../lib/projects/add/legacyAddComponent.js';
6
6
  import { getProjectConfig } from '../../../lib/projects/config.js';
7
7
  import { isV2Project } from '../../../lib/projects/platformVersion.js';
@@ -9,15 +9,15 @@ import { trackCommandUsage } from '../../../lib/usageTracking.js';
9
9
  vi.mock('../../../lib/commonOpts');
10
10
  vi.mock('../../../lib/ui/logger.js');
11
11
  vi.mock('../../../lib/errorHandlers/index.js');
12
- vi.mock('../../../lib/projects/add/v3AddComponent');
12
+ vi.mock('../../../lib/projects/add/v2AddComponent');
13
13
  vi.mock('../../../lib/projects/add/legacyAddComponent');
14
14
  vi.mock('../../../lib/projects/config');
15
15
  vi.mock('../../../lib/projects/platformVersion');
16
16
  vi.mock('../../../lib/usageTracking');
17
- const mockedV3AddComponent = vi.mocked(v3AddComponent);
17
+ const mockedV2AddComponent = vi.mocked(v2AddComponent);
18
18
  const mockedLegacyAddComponent = vi.mocked(legacyAddComponent);
19
19
  const mockedGetProjectConfig = vi.mocked(getProjectConfig);
20
- const mockedUseV3Api = vi.mocked(isV2Project);
20
+ const mockedUseV2Api = vi.mocked(isV2Project);
21
21
  const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
22
22
  describe('commands/project/add', () => {
23
23
  const yargsMock = yargs;
@@ -61,7 +61,7 @@ describe('commands/project/add', () => {
61
61
  const mockProjectConfig = {
62
62
  name: 'test-project',
63
63
  srcDir: 'src',
64
- platformVersion: 'v3',
64
+ platformVersion: '2025.2',
65
65
  };
66
66
  const mockProjectDir = '/path/to/project';
67
67
  const mockArgs = {
@@ -75,23 +75,23 @@ describe('commands/project/add', () => {
75
75
  projectDir: mockProjectDir,
76
76
  });
77
77
  mockedTrackCommandUsage.mockResolvedValue();
78
- mockedV3AddComponent.mockResolvedValue();
78
+ mockedV2AddComponent.mockResolvedValue();
79
79
  mockedLegacyAddComponent.mockResolvedValue();
80
80
  vi.spyOn(process, 'exit').mockImplementation(() => {
81
81
  throw new Error('process.exit called');
82
82
  });
83
83
  });
84
- it('should call v3AddComponent with accountId for v3 projects', async () => {
85
- mockedUseV3Api.mockReturnValue(true);
84
+ it('should call v2AddComponent with accountId for v2 projects', async () => {
85
+ mockedUseV2Api.mockReturnValue(true);
86
86
  await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
87
- expect(mockedV3AddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
87
+ expect(mockedV2AddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
88
88
  expect(mockedLegacyAddComponent).not.toHaveBeenCalled();
89
89
  });
90
- it('should call legacyAddComponent for non-v3 projects', async () => {
91
- mockedUseV3Api.mockReturnValue(false);
90
+ it('should call legacyAddComponent for non-v2 projects', async () => {
91
+ mockedUseV2Api.mockReturnValue(false);
92
92
  await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
93
93
  expect(mockedLegacyAddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
94
- expect(mockedV3AddComponent).not.toHaveBeenCalled();
94
+ expect(mockedV2AddComponent).not.toHaveBeenCalled();
95
95
  });
96
96
  it('should exit with error when project config is not found', async () => {
97
97
  mockedGetProjectConfig.mockResolvedValue({
@@ -0,0 +1,31 @@
1
+ import yargs from 'yargs';
2
+ import { addAccountOptions, addConfigOptions, } from '../../../lib/commonOpts.js';
3
+ import projectListCommand from '../list.js';
4
+ vi.mock('../../../lib/commonOpts');
5
+ describe('commands/project/list', () => {
6
+ const yargsMock = yargs;
7
+ describe('command', () => {
8
+ it('should have the correct command structure', () => {
9
+ expect(projectListCommand.command).toEqual(['list', 'ls']);
10
+ });
11
+ });
12
+ describe('describe', () => {
13
+ it('should provide a description', () => {
14
+ expect(projectListCommand.describe).toBeDefined();
15
+ });
16
+ });
17
+ describe('builder', () => {
18
+ it('should support the correct options', () => {
19
+ projectListCommand.builder(yargsMock);
20
+ expect(addAccountOptions).toHaveBeenCalledTimes(1);
21
+ expect(addAccountOptions).toHaveBeenCalledWith(yargsMock);
22
+ expect(addConfigOptions).toHaveBeenCalledTimes(1);
23
+ expect(addConfigOptions).toHaveBeenCalledWith(yargsMock);
24
+ });
25
+ it('should define examples', () => {
26
+ const exampleSpy = vi.spyOn(yargsMock, 'example');
27
+ projectListCommand.builder(yargsMock);
28
+ expect(exampleSpy).toHaveBeenCalled();
29
+ });
30
+ });
31
+ });
@@ -10,6 +10,7 @@ vi.mock('../../../lib/ui/logger.js');
10
10
  vi.mock('../../../lib/app/migrate');
11
11
  vi.mock('../../../lib/projects/config');
12
12
  vi.mock('../../../lib/ui');
13
+ vi.mock('../../../lib/usageTracking.js');
13
14
  const { v2025_2 } = PLATFORM_VERSIONS;
14
15
  describe('commands/project/migrate', () => {
15
16
  const yargsMock = yargs;
@@ -1,5 +1,5 @@
1
- import { YargsCommandModule, CommonArgs } from '../../types/Yargs.js';
2
- export type ProjectAddArgs = CommonArgs & {
1
+ import { YargsCommandModule, CommonArgs, ConfigArgs } from '../../types/Yargs.js';
2
+ export type ProjectAddArgs = CommonArgs & ConfigArgs & {
3
3
  type?: string;
4
4
  name?: string;
5
5
  features?: string[];
@@ -5,7 +5,7 @@ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
5
5
  import { commands } from '../../lang/en.js';
6
6
  import { isV2Project } from '../../lib/projects/platformVersion.js';
7
7
  import { legacyAddComponent } from '../../lib/projects/add/legacyAddComponent.js';
8
- import { v3AddComponent } from '../../lib/projects/add/v3AddComponent.js';
8
+ import { v2AddComponent } from '../../lib/projects/add/v2AddComponent.js';
9
9
  import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../lib/constants.js';
10
10
  import { uiLogger } from '../../lib/ui/logger.js';
11
11
  const command = 'add';
@@ -20,7 +20,7 @@ async function handler(args) {
20
20
  }
21
21
  const isV2ProjectCreate = isV2Project(projectConfig.platformVersion);
22
22
  if (isV2ProjectCreate) {
23
- await v3AddComponent(args, projectDir, projectConfig, derivedAccountId);
23
+ await v2AddComponent(args, projectDir, projectConfig, derivedAccountId);
24
24
  }
25
25
  else {
26
26
  await legacyAddComponent(args, projectDir, projectConfig, derivedAccountId);
@@ -68,6 +68,7 @@ function projectAddBuilder(yargs) {
68
68
  }
69
69
  const builder = makeYargsBuilder(projectAddBuilder, command, describe, {
70
70
  useGlobalOptions: true,
71
+ useConfigOptions: true,
71
72
  });
72
73
  const projectAddCommand = {
73
74
  command,
@@ -5,7 +5,7 @@ import { getCwd } from '@hubspot/local-dev-lib/path';
5
5
  import { trackCommandUsage } from '../../lib/usageTracking.js';
6
6
  import { writeProjectConfig, getProjectConfig, } from '../../lib/projects/config.js';
7
7
  import { EMPTY_PROJECT_TEMPLATE_NAME } from '../../lib/projects/create/legacy.js';
8
- import { generateComponentPaths } from '../../lib/projects/create/v3.js';
8
+ import { generateComponentPaths } from '../../lib/projects/create/v2.js';
9
9
  import { PROJECT_WITH_APP, EMPTY_PROJECT } from '../../lib/constants.js';
10
10
  import { uiFeatureHighlight } from '../../lib/ui/index.js';
11
11
  import { debugError, logError } from '../../lib/errorHandlers/index.js';
@@ -6,7 +6,7 @@ import { commands } from '../../../lang/en.js';
6
6
  import { uiLogger } from '../../../lib/ui/logger.js';
7
7
  import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
8
8
  import SpinniesManager from '../../../lib/ui/SpinniesManager.js';
9
- import LocalDevManager from '../../../lib/projects/localDev/LocalDevManager.js';
9
+ import LocalDevManager_DEPRECATED from '../../../lib/projects/localDev/LocalDevManager_DEPRECATED.js';
10
10
  import { confirmDefaultAccountIsTarget, suggestRecommendedNestedAccount, checkIfAccountFlagIsSupported, checkIfDefaultAccountIsSupported, createSandboxForLocalDev, createDeveloperTestAccountForLocalDev, useExistingDevTestAccount, checkIfParentAccountIsAuthed, hasSandboxes, } from '../../../lib/projects/localDev/helpers/account.js';
11
11
  import { createInitialBuildForNewProject, createNewProjectForLocalDev, } from '../../../lib/projects/localDev/helpers/project.js';
12
12
  import { handleExit } from '../../../lib/process.js';
@@ -121,7 +121,7 @@ export async function deprecatedProjectDevFlow({ args, accountId, projectConfig,
121
121
  project = await createNewProjectForLocalDev(projectConfig, targetProjectAccountId, createNewSandbox, hasPublicApps);
122
122
  deployedBuild = await createInitialBuildForNewProject(projectConfig, projectDir, targetProjectAccountId);
123
123
  }
124
- const LocalDev = new LocalDevManager({
124
+ const LocalDev = new LocalDevManager_DEPRECATED({
125
125
  runnableComponents,
126
126
  debug: args.debug,
127
127
  deployedBuild,
@@ -12,14 +12,14 @@ import { commands } from '../../../lang/en.js';
12
12
  import { uiLogger } from '../../../lib/ui/logger.js';
13
13
  const command = 'dev';
14
14
  const describe = commands.project.dev.describe;
15
- function validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV3) {
15
+ function validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV2) {
16
16
  // Legacy projects do not support targetTestingAccount and targetProjectAccount
17
- if (testingAccount && projectAccount && !useV3) {
17
+ if (testingAccount && projectAccount && !useV2) {
18
18
  uiLogger.error(commands.project.dev.errors.unsupportedAccountFlagLegacy);
19
19
  process.exit(EXIT_CODES.ERROR);
20
20
  }
21
- if (userProvidedAccount && useV3) {
22
- uiLogger.error(commands.project.dev.errors.unsupportedAccountFlagV3);
21
+ if (userProvidedAccount && useV2) {
22
+ uiLogger.error(commands.project.dev.errors.unsupportedAccountFlagV2);
23
23
  process.exit(EXIT_CODES.ERROR);
24
24
  }
25
25
  }
@@ -35,7 +35,7 @@ async function handler(args) {
35
35
  validateAccountFlags(testingAccount, projectAccount, userProvidedAccount, useV2Projects);
36
36
  uiLogger.log(commands.project.dev.logs.header);
37
37
  if (useV2Projects) {
38
- uiLogger.log(commands.project.dev.logs.learnMoreMessageV3);
38
+ uiLogger.log(commands.project.dev.logs.learnMoreMessageV2);
39
39
  }
40
40
  else {
41
41
  uiLogger.log(commands.project.dev.logs.learnMoreMessageLegacy);
@@ -1,6 +1,7 @@
1
1
  import path from 'path';
2
2
  import util from 'util';
3
3
  import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
4
+ import { startPortManagerServer, stopPortManagerServer, } from '@hubspot/local-dev-lib/portManager';
4
5
  import { isTranslationError } from '@hubspot/project-parsing-lib/src/lib/errors.js';
5
6
  import { translateForLocalDev } from '@hubspot/project-parsing-lib';
6
7
  import { getEnv, getConfigAccounts, getAccountConfig, } from '@hubspot/local-dev-lib/config';
@@ -121,6 +122,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
121
122
  // Check for missing/outdated dependencies
122
123
  await checkAndInstallDependencies();
123
124
  // End setup, start local dev process
125
+ await startPortManagerServer();
124
126
  const localDevProcess = new LocalDevProcess({
125
127
  initialProjectNodes: projectNodes,
126
128
  initialProjectProfileData: projectProfileData,
@@ -133,11 +135,11 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
133
135
  projectData: project,
134
136
  env,
135
137
  });
136
- await localDevProcess.start();
137
- const watcher = new LocalDevWatcher(localDevProcess);
138
- watcher.start();
139
138
  const websocketServer = new LocalDevWebsocketServer(localDevProcess, args.debug);
139
+ const watcher = new LocalDevWatcher(localDevProcess);
140
140
  await websocketServer.start();
141
+ await localDevProcess.start();
142
+ watcher.start();
141
143
  handleKeypress(async (key) => {
142
144
  if ((key.ctrl && key.name === 'c') || key.name === 'q') {
143
145
  await Promise.all([
@@ -151,5 +153,6 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
151
153
  localDevProcess.stop(!isSIGHUP);
152
154
  watcher.stop();
153
155
  websocketServer.shutdown();
156
+ stopPortManagerServer();
154
157
  });
155
158
  }
@@ -35,9 +35,12 @@ async function handler(args) {
35
35
  uiLogger.error(commands.project.download.errors.noBuildIdToDownload);
36
36
  process.exit(EXIT_CODES.ERROR);
37
37
  }
38
- const absoluteDestPath = dest ? path.resolve(getCwd(), dest) : getCwd();
38
+ const sanitizedProjectName = sanitizeFileName(projectName);
39
+ const absoluteDestPath = dest
40
+ ? path.resolve(getCwd(), dest, sanitizedProjectName)
41
+ : path.resolve(getCwd(), sanitizedProjectName);
39
42
  const { data: zippedProject } = await downloadProject(derivedAccountId, projectName, buildNumberToDownload);
40
- await extractZipArchive(zippedProject, sanitizeFileName(projectName), path.resolve(absoluteDestPath), { includesRootDir: false });
43
+ await extractZipArchive(zippedProject, sanitizeFileName(projectName), path.resolve(absoluteDestPath));
41
44
  uiLogger.log(commands.project.download.logs.downloadSucceeded(buildNumberToDownload, projectName));
42
45
  process.exit(EXIT_CODES.SUCCESS);
43
46
  }
@@ -1,5 +1,5 @@
1
- import { CommonArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- export type ProjectInstallDepsArgs = CommonArgs & {
1
+ import { CommonArgs, ConfigArgs, YargsCommandModule } from '../../types/Yargs.js';
2
+ export type ProjectInstallDepsArgs = CommonArgs & ConfigArgs & {
3
3
  packages?: string[];
4
4
  };
5
5
  declare const projectInstallDepsCommand: YargsCommandModule<unknown, ProjectInstallDepsArgs>;
@@ -69,6 +69,7 @@ function projectInstallDepsBuilder(yargs) {
69
69
  }
70
70
  const builder = makeYargsBuilder(projectInstallDepsBuilder, command, describe, {
71
71
  useGlobalOptions: true,
72
+ useConfigOptions: true,
72
73
  });
73
74
  const projectInstallDepsCommand = {
74
75
  command,
@@ -0,0 +1,4 @@
1
+ import { AccountArgs, CommonArgs, ConfigArgs, YargsCommandModule } from '../../types/Yargs.js';
2
+ type ProjectListArgs = CommonArgs & ConfigArgs & AccountArgs;
3
+ declare const projectListCommand: YargsCommandModule<unknown, ProjectListArgs>;
4
+ export default projectListCommand;
@@ -0,0 +1,62 @@
1
+ import { trackCommandUsage } from '../../lib/usageTracking.js';
2
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
3
+ import { fetchProjects } from '@hubspot/local-dev-lib/api/projects';
4
+ import { logError } from '../../lib/errorHandlers/index.js';
5
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
+ import { getTableContents, getTableHeader } from '../../lib/ui/table.js';
7
+ import { uiLogger } from '../../lib/ui/logger.js';
8
+ import { commands } from '../../lang/en.js';
9
+ const command = ['list', 'ls'];
10
+ const describe = commands.project.list.describe;
11
+ async function getProjectData(accountId) {
12
+ try {
13
+ const { data: projects } = await fetchProjects(accountId);
14
+ return projects.results;
15
+ }
16
+ catch (e) {
17
+ logError(e);
18
+ process.exit(EXIT_CODES.ERROR);
19
+ }
20
+ }
21
+ function formatProjectsAsTableRows(projects) {
22
+ const projectListData = [];
23
+ projects.forEach(project => {
24
+ projectListData.push([
25
+ project.name,
26
+ project.latestBuild ? project.latestBuild.platformVersion : '',
27
+ ]);
28
+ });
29
+ return projectListData;
30
+ }
31
+ async function handler(args) {
32
+ const { derivedAccountId } = args;
33
+ trackCommandUsage('projects-list', undefined, derivedAccountId);
34
+ const projectData = await getProjectData(derivedAccountId);
35
+ if (projectData.length === 0) {
36
+ uiLogger.error(commands.project.list.errors.noProjectsFound(derivedAccountId));
37
+ process.exit(EXIT_CODES.ERROR);
38
+ }
39
+ const projectListData = formatProjectsAsTableRows(projectData);
40
+ projectListData.unshift(getTableHeader([
41
+ commands.project.list.labels.name,
42
+ commands.project.list.labels.platformVersion,
43
+ ]));
44
+ uiLogger.log(commands.project.list.projects);
45
+ uiLogger.log(getTableContents(projectListData, { border: { bodyLeft: ' ' } }));
46
+ }
47
+ function projectListBuilder(yargs) {
48
+ yargs.example([['$0 project list']]);
49
+ return yargs;
50
+ }
51
+ const builder = makeYargsBuilder(projectListBuilder, command, describe, {
52
+ useGlobalOptions: true,
53
+ useConfigOptions: true,
54
+ useAccountOptions: true,
55
+ });
56
+ const projectListCommand = {
57
+ command,
58
+ describe,
59
+ handler,
60
+ builder,
61
+ };
62
+ export default projectListCommand;
@@ -13,11 +13,13 @@ import { getWarningBox } from '../../ui/components/StatusMessageBoxes.js';
13
13
  import { getHasMigratableThemes, migrateThemes2025_2, } from '../../lib/theme/migrate.js';
14
14
  import { hasFeature } from '../../lib/hasFeature.js';
15
15
  import { FEATURES } from '../../lib/constants.js';
16
+ import { trackCommandMetadataUsage, trackCommandUsage, } from '../../lib/usageTracking.js';
16
17
  const { v2025_2 } = PLATFORM_VERSIONS;
17
18
  const command = 'migrate';
18
19
  const describe = commands.project.migrate.describe;
19
20
  async function handler(args) {
20
- const { platformVersion, unstable } = args;
21
+ const { platformVersion, unstable, derivedAccountId } = args;
22
+ await trackCommandUsage('project-migrate', {}, derivedAccountId);
21
23
  const projectConfig = await getProjectConfig();
22
24
  if (!projectConfig.projectConfig) {
23
25
  uiLogger.error(commands.project.migrate.errors.noProjectConfig(uiCommandReference('hs app migrate')));
@@ -37,7 +39,6 @@ async function handler(args) {
37
39
  }));
38
40
  }
39
41
  }
40
- const { derivedAccountId } = args;
41
42
  try {
42
43
  const { hasMigratableThemes, migratableThemesCount } = await getHasMigratableThemes(projectConfig);
43
44
  if (hasMigratableThemes) {
@@ -64,9 +65,11 @@ async function handler(args) {
64
65
  }
65
66
  }
66
67
  catch (error) {
68
+ await trackCommandMetadataUsage('project-migrate', { successful: false }, derivedAccountId);
67
69
  logError(error);
68
70
  return process.exit(EXIT_CODES.ERROR);
69
71
  }
72
+ await trackCommandMetadataUsage('project-migrate', { successful: true }, derivedAccountId);
70
73
  return process.exit(EXIT_CODES.SUCCESS);
71
74
  }
72
75
  function projectMigrateBuilder(yargs) {
@@ -15,6 +15,7 @@ import cloneApp from './project/cloneApp.js';
15
15
  import installDeps from './project/installDeps.js';
16
16
  import profile from './project/profile.js';
17
17
  import projectValidate from './project/validate.js';
18
+ import list from './project/list.js';
18
19
  import { makeYargsBuilder } from '../lib/yargsUtils.js';
19
20
  const command = ['project', 'projects'];
20
21
  const describe = commands.project.describe;
@@ -23,6 +24,7 @@ function projectBuilder(yargs) {
23
24
  .command(create)
24
25
  .command(add)
25
26
  .command(watch)
27
+ .command(list)
26
28
  .command(dev)
27
29
  .command(upload)
28
30
  .command(deploy)
@@ -12,7 +12,7 @@ import { deleteSandboxPrompt } from '../../lib/prompts/sandboxesPrompt.js';
12
12
  import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt.js';
13
13
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
14
14
  import { promptUser } from '../../lib/prompts/promptUtils.js';
15
- import { uiBetaTag } from '../../lib/ui/index.js';
15
+ import { uiAuthCommandReference, uiBetaTag } from '../../lib/ui/index.js';
16
16
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
17
17
  const command = 'delete';
18
18
  const describe = uiBetaTag(commands.sandbox.subcommands.delete.describe, false);
@@ -65,7 +65,10 @@ async function handler(args) {
65
65
  }
66
66
  }
67
67
  const url = `${baseUrl}/sandboxes/${parentAccountId}`;
68
- const command = `hs auth ${getEnv(sandboxAccountId) === 'qa' ? '--qa' : ''} --account=${parentAccountId}`;
68
+ const command = uiAuthCommandReference({
69
+ accountId: parentAccountId || undefined,
70
+ qa: getEnv(sandboxAccountId) === 'qa',
71
+ });
69
72
  if (parentAccountId && !getAccountId(parentAccountId)) {
70
73
  uiLogger.log('');
71
74
  uiLogger.error(commands.sandbox.subcommands.delete.failure.noParentPortalAvailable(command, url));
@@ -13,7 +13,7 @@ import { commands } from '../../lang/en.js';
13
13
  import { createDeveloperTestAccountConfigPrompt } from '../../lib/prompts/createDeveloperTestAccountConfigPrompt.js';
14
14
  import { debugError, logError } from '../../lib/errorHandlers/index.js';
15
15
  import SpinniesManager from '../../lib/ui/SpinniesManager.js';
16
- import { createDeveloperTestAccountV3, saveAccountToConfig, } from '../../lib/buildAccount.js';
16
+ import { createDeveloperTestAccountV2, saveAccountToConfig, } from '../../lib/buildAccount.js';
17
17
  const command = 'create';
18
18
  const describe = commands.testAccount.create.describe;
19
19
  async function handler(args) {
@@ -69,7 +69,7 @@ async function handler(args) {
69
69
  text: commands.testAccount.create.polling.start(testAccountConfig.accountName),
70
70
  });
71
71
  try {
72
- const createResult = await createDeveloperTestAccountV3(derivedAccountId, testAccountConfig);
72
+ const createResult = await createDeveloperTestAccountV2(derivedAccountId, testAccountConfig);
73
73
  resultJson.accountName = createResult.accountName;
74
74
  resultJson.accountId = createResult.accountId;
75
75
  resultJson.personalAccessKey = createResult.personalAccessKey;
@@ -15,8 +15,6 @@ import { handleExit, handleKeypress } from '../../lib/process.js';
15
15
  import { getProjectConfig } from '../../lib/projects/config.js';
16
16
  import { findProjectComponents } from '../../lib/projects/structure.js';
17
17
  import { ComponentTypes } from '../../types/Projects.js';
18
- import { hasFeature } from '../../lib/hasFeature.js';
19
- import { FEATURES } from '../../lib/constants.js';
20
18
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
21
19
  import { uiLogger } from '../../lib/ui/logger.js';
22
20
  const command = 'preview [--src] [--dest]';
@@ -150,8 +148,7 @@ async function handler(args) {
150
148
  catch (e) {
151
149
  uiLogger.warn('Unified dev server requires node 20 to run. Defaulting to legacy preview.');
152
150
  }
153
- const isUngatedForUnified = await hasFeature(derivedAccountId, FEATURES.UNIFIED_THEME_PREVIEW);
154
- if (isUngatedForUnified && createUnifiedDevServer) {
151
+ if (createUnifiedDevServer) {
155
152
  if (port) {
156
153
  process.env['PORT'] = port.toString();
157
154
  }