@hubspot/cli 7.10.0 → 7.11.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 (211) hide show
  1. package/bin/cli.js +5 -4
  2. package/commands/__tests__/getStarted.test.js +10 -0
  3. package/commands/__tests__/project.test.js +3 -0
  4. package/commands/account/__tests__/rename.test.js +10 -3
  5. package/commands/account/auth.js +10 -14
  6. package/commands/account/clean.js +11 -19
  7. package/commands/account/createOverride.js +15 -11
  8. package/commands/account/info.js +8 -5
  9. package/commands/account/list.js +15 -19
  10. package/commands/account/remove.js +23 -22
  11. package/commands/account/removeOverride.js +6 -6
  12. package/commands/account/rename.js +2 -2
  13. package/commands/account/use.js +19 -8
  14. package/commands/app/__tests__/migrate.test.js +8 -4
  15. package/commands/app/migrate.js +2 -2
  16. package/commands/auth.js +18 -14
  17. package/commands/config/migrate.js +5 -5
  18. package/commands/customObject/createSchema.js +2 -3
  19. package/commands/customObject/updateSchema.js +2 -3
  20. package/commands/getStarted.js +2 -3
  21. package/commands/hubdb/__tests__/list.test.js +1 -0
  22. package/commands/hubdb/list.js +2 -2
  23. package/commands/init.js +36 -32
  24. package/commands/project/__tests__/deploy.test.js +16 -11
  25. package/commands/project/__tests__/devUnifiedFlow.test.js +6 -4
  26. package/commands/project/__tests__/lint.test.js +709 -0
  27. package/commands/project/__tests__/logs.test.js +4 -0
  28. package/commands/project/__tests__/validate.test.js +2 -2
  29. package/commands/project/cloneApp.js +2 -2
  30. package/commands/project/create.js +20 -14
  31. package/commands/project/deploy.js +2 -2
  32. package/commands/project/dev/deprecatedFlow.js +4 -5
  33. package/commands/project/dev/index.js +6 -3
  34. package/commands/project/dev/unifiedFlow.js +11 -6
  35. package/commands/project/lint.d.ts +6 -0
  36. package/commands/project/lint.js +178 -0
  37. package/commands/project/logs.js +2 -3
  38. package/commands/project/migrate.js +4 -13
  39. package/commands/project/profile/add.js +6 -7
  40. package/commands/project/profile/delete.js +2 -2
  41. package/commands/project/upload.js +2 -2
  42. package/commands/project/validate.js +2 -2
  43. package/commands/project.js +2 -0
  44. package/commands/sandbox/__tests__/create.test.js +14 -5
  45. package/commands/sandbox/create.js +4 -5
  46. package/commands/sandbox/delete.js +23 -20
  47. package/commands/testAccount/create.js +2 -2
  48. package/commands/testAccount/delete.js +9 -8
  49. package/lang/en.d.ts +54 -12
  50. package/lang/en.js +64 -16
  51. package/lib/__tests__/buildAccount.test.js +22 -30
  52. package/lib/__tests__/commonOpts.test.js +9 -13
  53. package/lib/__tests__/developerTestAccounts.test.js +29 -17
  54. package/lib/__tests__/importData.test.js +20 -10
  55. package/lib/__tests__/oauth.test.js +19 -8
  56. package/lib/__tests__/sandboxSync.test.js +33 -11
  57. package/lib/__tests__/sandboxes.test.js +30 -19
  58. package/lib/__tests__/usageTracking.test.js +10 -10
  59. package/lib/__tests__/validation.test.js +32 -32
  60. package/lib/accountTypes.d.ts +9 -9
  61. package/lib/accountTypes.js +2 -4
  62. package/lib/app/__tests__/migrate.test.js +15 -0
  63. package/lib/app/__tests__/migrate_legacy.test.js +9 -0
  64. package/lib/app/migrate_legacy.d.ts +2 -2
  65. package/lib/buildAccount.d.ts +4 -4
  66. package/lib/buildAccount.js +7 -14
  67. package/lib/commonOpts.js +3 -3
  68. package/lib/configMigrate.d.ts +2 -2
  69. package/lib/configMigrate.js +42 -18
  70. package/lib/configOptions.js +3 -2
  71. package/lib/developerTestAccounts.d.ts +3 -3
  72. package/lib/developerTestAccounts.js +4 -7
  73. package/lib/doctor/DiagnosticInfoBuilder.d.ts +1 -1
  74. package/lib/doctor/DiagnosticInfoBuilder.js +9 -6
  75. package/lib/doctor/Doctor.js +4 -3
  76. package/lib/doctor/__tests__/Diagnosis.test.js +4 -3
  77. package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +17 -9
  78. package/lib/doctor/__tests__/Doctor.test.js +14 -0
  79. package/lib/errorHandlers/index.js +10 -7
  80. package/lib/importData.js +8 -7
  81. package/lib/links.js +5 -5
  82. package/lib/middleware/{__test__ → __tests__}/commandTargetingUtils.test.js +3 -3
  83. package/lib/middleware/{__test__ → __tests__}/configMiddleware.test.js +23 -22
  84. package/lib/middleware/{__test__ → __tests__}/gitMiddleware.test.js +9 -7
  85. package/lib/middleware/autoUpdateMiddleware.js +34 -23
  86. package/lib/middleware/commandTargetingUtils.js +3 -2
  87. package/lib/middleware/configMiddleware.d.ts +6 -1
  88. package/lib/middleware/configMiddleware.js +36 -15
  89. package/lib/middleware/fireAlarmMiddleware.js +4 -15
  90. package/lib/middleware/gitMiddleware.js +8 -4
  91. package/lib/oauth.d.ts +2 -2
  92. package/lib/oauth.js +8 -10
  93. package/lib/projects/__tests__/AppDevModeInterface.test.js +17 -6
  94. package/lib/projects/__tests__/DevServerManager.test.js +1 -0
  95. package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
  96. package/lib/projects/__tests__/components.test.js +2 -22
  97. package/lib/projects/__tests__/deploy.test.js +16 -13
  98. package/lib/projects/__tests__/uieLinting.test.js +640 -0
  99. package/lib/projects/add/__tests__/legacyAddComponent.test.js +1 -1
  100. package/lib/projects/add/__tests__/v2AddComponent.test.js +30 -4
  101. package/lib/projects/add/legacyAddComponent.js +1 -1
  102. package/lib/projects/add/v2AddComponent.js +16 -5
  103. package/lib/projects/components.d.ts +8 -1
  104. package/lib/projects/components.js +91 -8
  105. package/lib/projects/create/__tests__/v2.test.js +11 -0
  106. package/lib/projects/deploy.js +21 -8
  107. package/lib/projects/localDev/AppDevModeInterface.js +2 -2
  108. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +11 -3
  109. package/lib/projects/localDev/LocalDevLogger.js +4 -4
  110. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
  111. package/lib/projects/localDev/helpers/account.d.ts +10 -10
  112. package/lib/projects/localDev/helpers/account.js +6 -11
  113. package/lib/projects/localDev/helpers/process.js +5 -3
  114. package/lib/projects/uieLinting.d.ts +33 -0
  115. package/lib/projects/uieLinting.js +222 -0
  116. package/lib/projects/urls.js +5 -6
  117. package/lib/prompts/__tests__/downloadProjectPrompt.test.js +7 -5
  118. package/lib/prompts/accountNamePrompt.js +3 -3
  119. package/lib/prompts/accountsPrompt.d.ts +1 -1
  120. package/lib/prompts/accountsPrompt.js +6 -7
  121. package/lib/prompts/confirmImportDataPrompt.js +2 -2
  122. package/lib/prompts/downloadProjectPrompt.d.ts +1 -0
  123. package/lib/prompts/downloadProjectPrompt.js +5 -2
  124. package/lib/prompts/importDataTestAccountSelectPrompt.js +4 -5
  125. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  126. package/lib/prompts/projectDevTargetAccountPrompt.d.ts +3 -3
  127. package/lib/prompts/projectDevTargetAccountPrompt.js +5 -7
  128. package/lib/prompts/sandboxesPrompt.js +7 -8
  129. package/lib/prompts/setAsDefaultAccountPrompt.js +7 -6
  130. package/lib/sandboxSync.d.ts +2 -2
  131. package/lib/sandboxSync.js +3 -9
  132. package/lib/sandboxes.d.ts +4 -4
  133. package/lib/sandboxes.js +6 -11
  134. package/lib/serverlessLogs.js +2 -2
  135. package/lib/theme/__tests__/migrate.test.js +15 -0
  136. package/lib/ui/SpinniesManager.d.ts +5 -7
  137. package/lib/ui/SpinniesManager.js +9 -12
  138. package/lib/ui/__tests__/SpinniesManager.test.d.ts +1 -0
  139. package/lib/ui/__tests__/SpinniesManager.test.js +489 -0
  140. package/lib/ui/index.js +6 -3
  141. package/lib/usageTracking.js +15 -8
  142. package/lib/validation.js +13 -11
  143. package/mcp-server/tools/cms/HsCreateFunctionTool.js +4 -2
  144. package/mcp-server/tools/cms/HsCreateModuleTool.js +4 -2
  145. package/mcp-server/tools/cms/HsCreateTemplateTool.js +4 -2
  146. package/mcp-server/tools/cms/HsFunctionLogsTool.js +4 -2
  147. package/mcp-server/tools/cms/HsListFunctionsTool.js +3 -1
  148. package/mcp-server/tools/cms/HsListTool.js +3 -1
  149. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -0
  150. package/mcp-server/tools/index.js +4 -0
  151. package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -2
  152. package/mcp-server/tools/project/CreateProjectTool.js +4 -2
  153. package/mcp-server/tools/project/CreateTestAccountTool.js +17 -7
  154. package/mcp-server/tools/project/DeployProjectTool.js +3 -1
  155. package/mcp-server/tools/project/DocFetchTool.js +6 -4
  156. package/mcp-server/tools/project/DocsSearchTool.d.ts +1 -1
  157. package/mcp-server/tools/project/DocsSearchTool.js +10 -8
  158. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +1 -1
  159. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -7
  160. package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
  161. package/mcp-server/tools/project/GetBuildLogsTool.d.ts +26 -0
  162. package/mcp-server/tools/project/GetBuildLogsTool.js +125 -0
  163. package/mcp-server/tools/project/GetBuildStatusTool.d.ts +26 -0
  164. package/mcp-server/tools/project/GetBuildStatusTool.js +166 -0
  165. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +1 -1
  166. package/mcp-server/tools/project/GetConfigValuesTool.js +9 -7
  167. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -1
  168. package/mcp-server/tools/project/GuidedWalkthroughTool.js +5 -3
  169. package/mcp-server/tools/project/UploadProjectTools.js +3 -1
  170. package/mcp-server/tools/project/ValidateProjectTool.js +4 -2
  171. package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +12 -2
  172. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +5 -1
  173. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +23 -11
  174. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +7 -5
  175. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +7 -5
  176. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.d.ts +1 -0
  177. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +305 -0
  178. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.d.ts +1 -0
  179. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +240 -0
  180. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -6
  181. package/mcp-server/utils/__tests__/content.test.js +21 -20
  182. package/mcp-server/utils/__tests__/feedbackTracking.test.js +34 -28
  183. package/mcp-server/utils/config.d.ts +1 -0
  184. package/mcp-server/utils/config.js +10 -0
  185. package/mcp-server/utils/content.d.ts +1 -1
  186. package/mcp-server/utils/content.js +2 -2
  187. package/mcp-server/utils/feedbackTracking.d.ts +1 -1
  188. package/mcp-server/utils/feedbackTracking.js +3 -3
  189. package/mcp-server/utils/toolUsageTracking.js +4 -3
  190. package/package.json +9 -9
  191. package/ui/components/BoxWithTitle.d.ts +2 -1
  192. package/ui/components/BoxWithTitle.js +2 -2
  193. package/ui/components/StatusMessageBoxes.d.ts +5 -4
  194. package/ui/components/StatusMessageBoxes.js +8 -8
  195. package/lib/middleware/__test__/notificationsMiddleware.test.js +0 -8
  196. package/lib/middleware/notificationsMiddleware.d.ts +0 -1
  197. package/lib/middleware/notificationsMiddleware.js +0 -28
  198. package/lib/ui/boxen.d.ts +0 -5
  199. package/lib/ui/boxen.js +0 -26
  200. package/mcp-server/utils/__tests__/cliConfig.test.js +0 -110
  201. package/mcp-server/utils/cliConfig.d.ts +0 -1
  202. package/mcp-server/utils/cliConfig.js +0 -12
  203. /package/{lib/middleware/__test__/commandTargetingUtils.test.d.ts → commands/project/__tests__/lint.test.d.ts} +0 -0
  204. /package/lib/middleware/{__test__/configMiddleware.test.d.ts → __tests__/commandTargetingUtils.test.d.ts} +0 -0
  205. /package/lib/middleware/{__test__/gitMiddleware.test.d.ts → __tests__/configMiddleware.test.d.ts} +0 -0
  206. /package/lib/middleware/{__test__/notificationsMiddleware.test.d.ts → __tests__/gitMiddleware.test.d.ts} +0 -0
  207. /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.d.ts +0 -0
  208. /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.js +0 -0
  209. /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.d.ts +0 -0
  210. /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.js +0 -0
  211. /package/{mcp-server/utils/__tests__/cliConfig.test.d.ts → lib/projects/__tests__/uieLinting.test.d.ts} +0 -0
@@ -5,9 +5,9 @@ import { createV2App } from '../../create/v2.js';
5
5
  import { confirmPrompt } from '../../../prompts/promptUtils.js';
6
6
  import { projectAddPromptV2 } from '../../../prompts/projectAddPrompt.js';
7
7
  import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
8
- import { uiLogger } from '../../../ui/logger.js';
9
8
  import { getProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
10
9
  import { trackCommandUsage } from '../../../usageTracking.js';
10
+ import { updateHsMetaFilesWithAutoGeneratedFields } from '../../components.js';
11
11
  import { commands } from '../../../../lang/en.js';
12
12
  vi.mock('fs');
13
13
  vi.mock('../../../prompts/promptUtils');
@@ -16,17 +16,19 @@ vi.mock('../../create/v2');
16
16
  vi.mock('../../../prompts/projectAddPrompt');
17
17
  vi.mock('@hubspot/local-dev-lib/github');
18
18
  vi.mock('../../../ui/logger.js');
19
+ vi.mock('../../../ui/SpinniesManager.js');
19
20
  vi.mock('@hubspot/project-parsing-lib/src/lib/project');
20
21
  vi.mock('../../../usageTracking');
22
+ vi.mock('../../components.js');
21
23
  const mockedFs = vi.mocked(fs);
22
24
  const mockedGetConfigForPlatformVersion = vi.mocked(getConfigForPlatformVersion);
23
25
  const mockedConfirmPrompt = vi.mocked(confirmPrompt);
24
26
  const mockedCreateV2App = vi.mocked(createV2App);
25
27
  const mockedProjectAddPromptV2 = vi.mocked(projectAddPromptV2);
26
28
  const mockedCloneGithubRepo = vi.mocked(cloneGithubRepo);
27
- const mockedUiLogger = vi.mocked(uiLogger);
28
29
  const mockedGetProjectMetadata = vi.mocked(getProjectMetadata);
29
30
  const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
31
+ const mockedUpdateHsMetaFilesWithAutoGeneratedFields = vi.mocked(updateHsMetaFilesWithAutoGeneratedFields);
30
32
  describe('lib/projects/add/v2AddComponent', () => {
31
33
  const mockProjectConfig = {
32
34
  name: 'test-project',
@@ -75,6 +77,7 @@ describe('lib/projects/add/v2AddComponent', () => {
75
77
  describe('v2AddComponent()', () => {
76
78
  it('successfully adds a component when app already exists', async () => {
77
79
  const mockAppMeta = {
80
+ name: 'Test App',
78
81
  config: {
79
82
  distribution: 'private',
80
83
  auth: { type: 'oauth' },
@@ -83,14 +86,33 @@ describe('lib/projects/add/v2AddComponent', () => {
83
86
  const mockPromptResponse = {
84
87
  componentTemplate: [mockComponentTemplate],
85
88
  };
89
+ const mockUpdatedProjectMetadata = {
90
+ hsMetaFiles: ['/path/to/new-module.meta.json'],
91
+ components: {
92
+ app: {
93
+ count: 1,
94
+ maxCount: 1,
95
+ hsMetaFiles: ['/path/to/app.meta.json'],
96
+ },
97
+ module: {
98
+ count: 1,
99
+ maxCount: 5,
100
+ hsMetaFiles: ['/path/to/new-module.meta.json'],
101
+ },
102
+ },
103
+ };
86
104
  mockedGetConfigForPlatformVersion.mockResolvedValue(mockConfig);
87
- mockedGetProjectMetadata.mockResolvedValue(mockProjectMetadata);
105
+ mockedGetProjectMetadata
106
+ .mockResolvedValueOnce(mockProjectMetadata)
107
+ .mockResolvedValueOnce(mockUpdatedProjectMetadata);
88
108
  mockedFs.readFileSync.mockReturnValue(JSON.stringify(mockAppMeta));
89
109
  mockedProjectAddPromptV2.mockResolvedValue(mockPromptResponse);
90
110
  mockedCloneGithubRepo.mockResolvedValue(true);
111
+ mockedUpdateHsMetaFilesWithAutoGeneratedFields.mockResolvedValue(undefined);
91
112
  await v2AddComponent(mockArgs, projectDir, mockProjectConfig, mockAccountId);
92
113
  expect(mockedGetConfigForPlatformVersion).toHaveBeenCalledWith('2025.2');
93
114
  expect(mockedGetProjectMetadata).toHaveBeenCalledWith('/path/to/project/src');
115
+ expect(mockedGetProjectMetadata).toHaveBeenCalledTimes(2);
94
116
  expect(mockedProjectAddPromptV2).toHaveBeenCalled();
95
117
  expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', {
96
118
  type: 'module',
@@ -100,7 +122,11 @@ describe('lib/projects/add/v2AddComponent', () => {
100
122
  hideLogs: true,
101
123
  branch: 'main',
102
124
  }));
103
- expect(mockedUiLogger.success).toHaveBeenCalled();
125
+ expect(mockedUpdateHsMetaFilesWithAutoGeneratedFields).toHaveBeenCalledWith('test-project', ['/path/to/new-module.meta.json'], [], expect.objectContaining({
126
+ currentProjectMetadata: mockProjectMetadata,
127
+ updatedProjectMetadata: mockUpdatedProjectMetadata,
128
+ showSuccessMessage: true,
129
+ }));
104
130
  });
105
131
  it('creates an app when no app exists and user confirms', async () => {
106
132
  const mockProjectMetadataNoApps = {
@@ -38,7 +38,7 @@ export async function legacyAddComponent(args, projectDir, projectConfig, derive
38
38
  branch: DEFAULT_PROJECT_TEMPLATE_BRANCH,
39
39
  hideLogs: true,
40
40
  });
41
- uiLogger.success(commands.project.add.success(projectAddPromptResponse.name));
41
+ uiLogger.success(commands.project.add.success(projectConfig.name));
42
42
  }
43
43
  catch (error) {
44
44
  throw new Error(commands.project.add.error.failedToDownloadComponent);
@@ -13,8 +13,8 @@ import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
13
13
  import { debugError } from '../../errorHandlers/index.js';
14
14
  import { uiLogger } from '../../ui/logger.js';
15
15
  import { trackCommandUsage } from '../../usageTracking.js';
16
+ import SpinniesManager from '../../ui/SpinniesManager.js';
16
17
  export async function v2AddComponent(args, projectDir, projectConfig, accountId) {
17
- uiLogger.log(commands.project.add.creatingComponent(projectConfig.name));
18
18
  const config = await getConfigForPlatformVersion(projectConfig.platformVersion);
19
19
  const { components, parentComponents } = config;
20
20
  if (!components || !components.length) {
@@ -52,6 +52,10 @@ export async function v2AddComponent(args, projectDir, projectConfig, accountId)
52
52
  await trackCommandUsage('project-add', {
53
53
  type: componentTypes?.join(','),
54
54
  }, accountId);
55
+ SpinniesManager.init();
56
+ SpinniesManager.add('project-add', {
57
+ text: commands.project.add.creatingComponent(projectConfig.name),
58
+ });
55
59
  try {
56
60
  const components = projectAddPromptResponse.componentTemplate?.map((componentTemplate) => {
57
61
  return path.join(projectConfig.platformVersion, componentTemplate.path);
@@ -87,12 +91,19 @@ export async function v2AddComponent(args, projectDir, projectConfig, accountId)
87
91
  return '';
88
92
  }
89
93
  });
90
- updateHsMetaFilesWithAutoGeneratedFields(projectConfig.name, newHsMetaFiles, existingUids);
91
- uiLogger.success(commands.project.add.success(projectAddPromptResponse.componentTemplate
92
- .map(template => `'${template.label}'`)
93
- .join(', '), projectAddPromptResponse.componentTemplate.length > 1));
94
+ SpinniesManager.succeed('project-add', {
95
+ text: commands.project.add.success(projectConfig.name),
96
+ });
97
+ await updateHsMetaFilesWithAutoGeneratedFields(projectConfig.name, newHsMetaFiles, existingUids, {
98
+ currentProjectMetadata,
99
+ updatedProjectMetadata,
100
+ showSuccessMessage: true,
101
+ });
94
102
  }
95
103
  catch (error) {
104
+ SpinniesManager.fail('project-add', {
105
+ text: commands.project.add.failure(projectConfig.name),
106
+ });
96
107
  debugError(error);
97
108
  throw new Error(commands.project.add.error.failedToDownloadComponent, {
98
109
  cause: error,
@@ -1,3 +1,10 @@
1
1
  import { Collision } from '@hubspot/local-dev-lib/types/Archive';
2
+ import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
2
3
  export declare function handleComponentCollision({ dest, src, collisions }: Collision): void;
3
- export declare function updateHsMetaFilesWithAutoGeneratedFields(projectName: string, hsMetaFilePaths: string[], existingUids?: string[]): void;
4
+ export declare function updateHsMetaFilesWithAutoGeneratedFields(projectName: string, hsMetaFilePaths: string[], existingUids?: string[], options?: {
5
+ currentProjectMetadata?: ProjectMetadata;
6
+ updatedProjectMetadata?: ProjectMetadata;
7
+ showSuccessMessage?: boolean;
8
+ isProjectEmpty?: boolean;
9
+ projectDest?: string;
10
+ }): Promise<void>;
@@ -6,8 +6,59 @@ import { uiLogger } from '../ui/logger.js';
6
6
  import { AppKey } from '@hubspot/project-parsing-lib/src/lib/constants.js';
7
7
  import { lib } from '../../lang/en.js';
8
8
  import { debugError } from '../errorHandlers/index.js';
9
+ import { uiLink } from '../ui/index.js';
10
+ import chalk from 'chalk';
11
+ import { renderInline } from '../../ui/index.js';
12
+ import { getSuccessBox } from '../../ui/components/StatusMessageBoxes.js';
9
13
  // Prefix for the metafile extension
10
14
  const metafileExtensionPrefix = path.parse(metafileExtension).name;
15
+ function buildProjectTree(projectName, uids, componentsByType, showOnlyNew) {
16
+ const lines = [];
17
+ lines.push(chalk.bold(projectName));
18
+ const types = Array.from(componentsByType.keys());
19
+ for (const uid of uids) {
20
+ lines.push(`├─ [app] ${uid}`);
21
+ for (let i = 0; i < types.length; i++) {
22
+ const type = types[i];
23
+ const allComponents = componentsByType.get(type) || [];
24
+ const components = showOnlyNew
25
+ ? allComponents.filter(c => c.isNew)
26
+ : allComponents;
27
+ if (components.length === 0)
28
+ continue;
29
+ const isLastType = i === types.length - 1;
30
+ const typePrefix = isLastType ? '│ └─' : '│ ├─';
31
+ const typeConnector = isLastType ? ' ' : '│ ';
32
+ lines.push(`${typePrefix} ${type}`);
33
+ for (let j = 0; j < components.length; j++) {
34
+ const component = components[j];
35
+ const isLastComponent = j === components.length - 1;
36
+ const componentPrefix = isLastComponent ? '└─' : '├─';
37
+ const addedLabel = component.isNew ? chalk.green(' (added)') : '';
38
+ lines.push(`│ ${typeConnector}${componentPrefix} ${component.filename}${addedLabel}`);
39
+ }
40
+ }
41
+ }
42
+ return lines.join('\n');
43
+ }
44
+ function buildSuccessMessage(projectName, uids, componentsByType, newComponentsCount, showOnlyNew, isProjectEmpty, projectDest) {
45
+ const messages = lib.projects.components.buildSuccessMessage;
46
+ const tree = buildProjectTree(projectName, uids, componentsByType, showOnlyNew);
47
+ const featureText = `${newComponentsCount} feature${newComponentsCount > 1 ? 's' : ''}`;
48
+ const uid = uids.length === 1 ? uids[0] : projectName;
49
+ const docsLink = uiLink(messages.seeOurDocs, messages.docsUrl);
50
+ const header = projectDest
51
+ ? messages.headerCreated(projectName, projectDest)
52
+ : messages.headerAdded(featureText, uid, newComponentsCount > 1);
53
+ // Use \n\n between sections to create gaps, \n within sections for no gaps
54
+ const sections = [
55
+ header,
56
+ isProjectEmpty ? null : tree,
57
+ messages.docsDetails(docsLink),
58
+ `${messages.uploadPrompt}\n${messages.devPrompt}`,
59
+ ].filter(Boolean);
60
+ return sections.join('\n\n');
61
+ }
11
62
  function applyDifferentiatorToFilename(filename, differentiator, isHsMetaFile) {
12
63
  const { name, ext, dir } = path.parse(filename);
13
64
  if (isHsMetaFile) {
@@ -120,9 +171,7 @@ function handlePackageJsonCollisions(dest, src, packageJsonFiles) {
120
171
  fs.writeFileSync(path.join(dest, file), JSON.stringify(existingPackageJsonContents, null, 2));
121
172
  });
122
173
  }
123
- export function updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths, existingUids = []) {
124
- uiLogger.log('');
125
- uiLogger.log(lib.projects.updateHsMetaFilesWithAutoGeneratedFields.header);
174
+ export async function updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFilePaths, existingUids = [], options) {
126
175
  for (const hsMetaFile of hsMetaFilePaths) {
127
176
  try {
128
177
  const component = JSON.parse(fs.readFileSync(hsMetaFile).toString());
@@ -142,10 +191,6 @@ export function updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFile
142
191
  component.uid = uid;
143
192
  if (component.type === AppKey && component.config) {
144
193
  component.config.name = `${projectName}-Application`;
145
- uiLogger.log(lib.projects.updateHsMetaFilesWithAutoGeneratedFields.applicationLog(component.type, component.uid, component.config.name));
146
- }
147
- else {
148
- uiLogger.log(lib.projects.updateHsMetaFilesWithAutoGeneratedFields.componentLog(component.type, component.uid));
149
194
  }
150
195
  fs.writeFileSync(hsMetaFile, JSON.stringify(component, null, 2));
151
196
  }
@@ -154,5 +199,43 @@ export function updateHsMetaFilesWithAutoGeneratedFields(projectName, hsMetaFile
154
199
  uiLogger.error(lib.projects.updateHsMetaFilesWithAutoGeneratedFields.failedToUpdate(hsMetaFile));
155
200
  }
156
201
  }
157
- uiLogger.log('');
202
+ if (options?.showSuccessMessage && options?.updatedProjectMetadata) {
203
+ const { currentProjectMetadata, updatedProjectMetadata, isProjectEmpty, projectDest, } = options;
204
+ const uids = [];
205
+ const updatedAppsMetadata = updatedProjectMetadata.components[AppKey];
206
+ // Get UID(s) from -hsmeta.json files
207
+ if (updatedAppsMetadata?.hsMetaFiles) {
208
+ updatedAppsMetadata.hsMetaFiles.forEach(appLocation => {
209
+ try {
210
+ const appConfig = JSON.parse(fs.readFileSync(appLocation, 'utf-8'));
211
+ uids.push(appConfig.uid || 'unknown app'); // fallback to unknown app incase we can't get uid
212
+ }
213
+ catch (err) {
214
+ uiLogger.debug(lib.projects.components.unableToGetUidFromHsmeta);
215
+ }
216
+ });
217
+ }
218
+ // Fallback if no app hsmeta files found or all failed to parse
219
+ if (uids.length === 0) {
220
+ uids.push('unknown app');
221
+ }
222
+ const componentsByType = new Map();
223
+ const addComponent = (hsMetaPath, isNew) => {
224
+ const type = path.basename(path.dirname(hsMetaPath));
225
+ const existing = componentsByType.get(type) || [];
226
+ existing.push({ filename: path.basename(hsMetaPath), isNew });
227
+ componentsByType.set(type, existing);
228
+ };
229
+ // Add new files
230
+ hsMetaFilePaths.forEach(hsMetaFile => addComponent(hsMetaFile, true));
231
+ if (currentProjectMetadata) {
232
+ Object.entries(currentProjectMetadata.components)
233
+ .filter(([type, metadata]) => type !== AppKey && metadata.count > 0)
234
+ .flatMap(([, metadata]) => metadata.hsMetaFiles)
235
+ .forEach(hsMetaFile => addComponent(hsMetaFile, false));
236
+ }
237
+ const newComponentsCount = hsMetaFilePaths.length;
238
+ const successMessage = buildSuccessMessage(projectName, uids, componentsByType, newComponentsCount, false, isProjectEmpty, projectDest);
239
+ await renderInline(getSuccessBox({ title: 'SUCCESS', message: successMessage }));
240
+ }
158
241
  }
@@ -1,12 +1,23 @@
1
1
  import { calculateComponentTemplateChoices } from '../v2.js';
2
2
  import { hasFeature } from '../../../hasFeature.js';
3
+ import { getConfigAccountById as __getConfigAccountById } from '@hubspot/local-dev-lib/config';
4
+ const getConfigAccountById = __getConfigAccountById;
3
5
  vi.mock('../../ui/logger.js');
4
6
  vi.mock('@hubspot/local-dev-lib/api/github');
5
7
  vi.mock('../../../hasFeature.js');
8
+ vi.mock('@hubspot/local-dev-lib/config');
6
9
  const mockHasFeature = vi.mocked(hasFeature);
7
10
  describe('lib/projects/create/v2', () => {
8
11
  beforeEach(() => {
9
12
  mockHasFeature.mockResolvedValue(true);
13
+ // Mock account config
14
+ getConfigAccountById.mockReturnValue({
15
+ accountId: 123,
16
+ name: 'Test Account',
17
+ authType: 'personalaccesskey',
18
+ personalAccessKey: 'test-key',
19
+ env: 'prod',
20
+ });
10
21
  });
11
22
  describe('calculateComponentTemplateChoices()', () => {
12
23
  beforeEach(() => {
@@ -1,7 +1,7 @@
1
1
  import { uiLogger } from '../ui/logger.js';
2
2
  import { commands } from '../../lang/en.js';
3
3
  import { PROJECT_ERROR_TYPES } from '../constants.js';
4
- import { deployProject } from '@hubspot/local-dev-lib/api/projects';
4
+ import { deployProjectV1, deployProjectV2, } from '@hubspot/local-dev-lib/api/projects';
5
5
  import { pollDeployStatus } from './pollProjectBuildAndDeploy.js';
6
6
  export function validateBuildIdForDeploy(buildId, deployedBuildId, latestBuildId, projectName, accountId) {
7
7
  if (Number(buildId) > latestBuildId) {
@@ -48,16 +48,29 @@ function handleBlockedDeploy(deployResp) {
48
48
  });
49
49
  }
50
50
  export async function handleProjectDeploy(targetAccountId, projectName, buildId, isV2Project, force) {
51
- const { data: deployResp } = await deployProject(targetAccountId, projectName, buildId, isV2Project, force);
52
- if (!deployResp || deployResp.buildResultType !== 'DEPLOY_QUEUED') {
53
- if (deployResp?.buildResultType === 'DEPLOY_BLOCKED') {
54
- handleBlockedDeploy(deployResp);
51
+ let deployId;
52
+ if (isV2Project) {
53
+ const { data: deployResp } = await deployProjectV2(targetAccountId, projectName, buildId, force);
54
+ if (!deployResp || deployResp.buildResultType !== 'DEPLOY_QUEUED') {
55
+ if (deployResp?.buildResultType === 'DEPLOY_BLOCKED') {
56
+ handleBlockedDeploy(deployResp);
57
+ }
58
+ else {
59
+ uiLogger.error(commands.project.deploy.errors.deploy);
60
+ }
61
+ return;
55
62
  }
56
- else {
63
+ deployId = deployResp.id;
64
+ }
65
+ else {
66
+ const response = await deployProjectV1(targetAccountId, projectName, buildId, force);
67
+ const { data: deployResp } = response;
68
+ if (!deployResp) {
57
69
  uiLogger.error(commands.project.deploy.errors.deploy);
70
+ return;
58
71
  }
59
- return;
72
+ deployId = deployResp.id;
60
73
  }
61
- const deployResult = await pollDeployStatus(targetAccountId, projectName, Number(deployResp.id), buildId);
74
+ const deployResult = await pollDeployStatus(targetAccountId, projectName, Number(deployId), buildId);
62
75
  return deployResult;
63
76
  }
@@ -1,6 +1,6 @@
1
1
  import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
2
2
  import { fetchAppMetadataByUid, fetchPublicAppProductionInstallCounts, installStaticAuthAppOnTestAccount, } from '@hubspot/local-dev-lib/api/appsDev';
3
- import { getAccountConfig } from '@hubspot/local-dev-lib/config';
3
+ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
4
4
  import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, APP_INSTALLATION_STATES, LOCAL_DEV_SERVER_MESSAGE_TYPES, } from '../../constants.js';
5
5
  import { EXIT_CODES } from '../../enums/exitCodes.js';
6
6
  import { isAppIRNode } from '../../projects/structure.js';
@@ -67,7 +67,7 @@ class AppDevModeInterface {
67
67
  return (this.appNode?.config.auth.type.toLowerCase() === APP_AUTH_TYPES.OAUTH);
68
68
  }
69
69
  isAutomaticallyInstallable() {
70
- const targetTestingAccount = getAccountConfig(this.localDevState.targetTestingAccountId);
70
+ const targetTestingAccount = getConfigAccountById(this.localDevState.targetTestingAccountId);
71
71
  if (!targetTestingAccount) {
72
72
  return false;
73
73
  }
@@ -2,10 +2,12 @@ import { logger } from '@hubspot/local-dev-lib/logger';
2
2
  import { DevModeInterface as UIEDevModeInterface } from '@hubspot/ui-extensions-dev-server';
3
3
  import { startPortManagerServer, stopPortManagerServer, requestPorts, } from '@hubspot/local-dev-lib/portManager';
4
4
  import { getHubSpotApiOrigin, getHubSpotWebsiteOrigin, } from '@hubspot/local-dev-lib/urls';
5
- import { getAccountConfig } from '@hubspot/local-dev-lib/config';
5
+ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
6
6
  import { ComponentTypes, } from '../../../types/Projects.js';
7
7
  import { lib } from '../../../lang/en.js';
8
8
  import { uiLogger } from '../../ui/logger.js';
9
+ import { logError } from '../../errorHandlers/index.js';
10
+ import { EXIT_CODES } from '../../enums/exitCodes.js';
9
11
  const SERVER_KEYS = {
10
12
  privateApp: 'privateApp',
11
13
  publicApp: 'publicApp',
@@ -58,11 +60,17 @@ class DevServerManager_DEPRECATED {
58
60
  async setup({ components, onUploadRequired, accountId, setActiveApp, }) {
59
61
  this.componentsByType = this.arrangeComponentsByType(components);
60
62
  let env;
61
- const accountConfig = getAccountConfig(accountId);
63
+ const accountConfig = getConfigAccountById(accountId);
62
64
  if (accountConfig) {
63
65
  env = accountConfig.env;
64
66
  }
65
- await startPortManagerServer();
67
+ try {
68
+ await startPortManagerServer();
69
+ }
70
+ catch (e) {
71
+ logError(e);
72
+ process.exit(EXIT_CODES.ERROR);
73
+ }
66
74
  await this.iterateDevServers(async (serverInterface, compatibleComponents) => {
67
75
  if (serverInterface.setup) {
68
76
  await serverInterface.setup({
@@ -1,5 +1,5 @@
1
- import { getAccountId, hasLocalStateFlag } from '@hubspot/local-dev-lib/config';
2
- import { getConfigDefaultAccount } from '@hubspot/local-dev-lib/config';
1
+ import { hasLocalStateFlag } from '@hubspot/local-dev-lib/config';
2
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
3
3
  import { uiLogger } from '../../ui/logger.js';
4
4
  import { uiLine, uiAccountDescription, uiCommandReference, } from '../../ui/index.js';
5
5
  import { lib } from '../../../lang/en.js';
@@ -30,9 +30,9 @@ class LocalDevLogger {
30
30
  uiLogger.error(langFunction(e instanceof Error ? e.message : ''));
31
31
  }
32
32
  getUploadCommand() {
33
- const currentDefaultAccount = getConfigDefaultAccount() || undefined;
33
+ const currentDefaultAccount = getConfigDefaultAccountIfExists();
34
34
  return this.state.targetProjectAccountId !==
35
- getAccountId(currentDefaultAccount)
35
+ currentDefaultAccount?.accountId
36
36
  ? uiCommandReference(`hs project upload --account=${this.state.targetProjectAccountId}`)
37
37
  : uiCommandReference('hs project upload');
38
38
  }
@@ -3,7 +3,7 @@ import chokidar from 'chokidar';
3
3
  import chalk from 'chalk';
4
4
  import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
5
5
  import { fetchPublicAppsForPortal, fetchPublicAppProductionInstallCounts, } from '@hubspot/local-dev-lib/api/appsDev';
6
- import { getAccountId, getConfigDefaultAccount, } from '@hubspot/local-dev-lib/config';
6
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
7
7
  import { PROJECT_CONFIG_FILE } from '../../constants.js';
8
8
  import SpinniesManager from '../../ui/SpinniesManager.js';
9
9
  import DevServerManager_DEPRECATED from './DevServerManager_DEPRECATED.js';
@@ -200,8 +200,8 @@ class LocalDevManager {
200
200
  });
201
201
  }
202
202
  getUploadCommand() {
203
- const currentDefaultAccount = getConfigDefaultAccount() || undefined;
204
- return this.targetProjectAccountId !== getAccountId(currentDefaultAccount)
203
+ const currentDefaultAccount = getConfigDefaultAccountIfExists();
204
+ return this.targetProjectAccountId !== currentDefaultAccount?.accountId
205
205
  ? uiCommandReference(`hs project upload --account=${this.targetProjectAccountId}`)
206
206
  : uiCommandReference('hs project upload');
207
207
  }
@@ -1,14 +1,14 @@
1
- import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
1
+ import { HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
2
  import { Environment } from '@hubspot/local-dev-lib/types/Config';
3
3
  import { DeveloperTestAccount } from '@hubspot/local-dev-lib/types/developerTestAccounts.js';
4
4
  import { ProjectDevTargetAccountPromptResponse } from '../../../prompts/projectDevTargetAccountPrompt.js';
5
- export declare function confirmDefaultAccountIsTarget(accountConfig: CLIAccount): Promise<void>;
6
- export declare function checkIfDefaultAccountIsSupported(accountConfig: CLIAccount, hasPublicApps: boolean): Promise<void>;
7
- export declare function checkIfParentAccountIsAuthed(accountConfig: CLIAccount): void;
8
- export declare function checkIfAccountFlagIsSupported(accountConfig: CLIAccount, hasPublicApps: boolean): void;
9
- export declare function suggestRecommendedNestedAccount(accounts: CLIAccount[], accountConfig: CLIAccount, hasPublicApps: boolean): Promise<ProjectDevTargetAccountPromptResponse>;
10
- export declare function createSandboxForLocalDev(accountId: number, accountConfig: CLIAccount, env: Environment): Promise<number>;
11
- export declare function createDeveloperTestAccountForLocalDev(accountId: number, accountConfig: CLIAccount, env: Environment, useV2?: boolean): Promise<number>;
5
+ export declare function confirmDefaultAccountIsTarget(accountConfig: HubSpotConfigAccount): Promise<void>;
6
+ export declare function checkIfDefaultAccountIsSupported(accountConfig: HubSpotConfigAccount, hasPublicApps: boolean): Promise<void>;
7
+ export declare function checkIfParentAccountIsAuthed(accountConfig: HubSpotConfigAccount): void;
8
+ export declare function checkIfAccountFlagIsSupported(accountConfig: HubSpotConfigAccount, hasPublicApps: boolean): void;
9
+ export declare function suggestRecommendedNestedAccount(accounts: HubSpotConfigAccount[], accountConfig: HubSpotConfigAccount, hasPublicApps: boolean): Promise<ProjectDevTargetAccountPromptResponse>;
10
+ export declare function createSandboxForLocalDev(accountId: number, accountConfig: HubSpotConfigAccount, env: Environment): Promise<number>;
11
+ export declare function createDeveloperTestAccountForLocalDev(accountId: number, accountConfig: HubSpotConfigAccount, env: Environment, useV2?: boolean): Promise<number>;
12
12
  export declare function useExistingDevTestAccount(env: Environment, account: DeveloperTestAccount): Promise<void>;
13
- export declare function hasSandboxes(account: CLIAccount): Promise<boolean>;
14
- export declare function selectAccountTypePrompt(accountConfig: CLIAccount): Promise<string | null>;
13
+ export declare function hasSandboxes(account: HubSpotConfigAccount): Promise<boolean>;
14
+ export declare function selectAccountTypePrompt(accountConfig: HubSpotConfigAccount): Promise<string | null>;
@@ -1,6 +1,5 @@
1
1
  import { HUBSPOT_ACCOUNT_TYPE_STRINGS } from '@hubspot/local-dev-lib/constants/config';
2
- import { getAccountConfig } from '@hubspot/local-dev-lib/config';
3
- import { getAccountIdentifier } from '@hubspot/local-dev-lib/config/getAccountIdentifier';
2
+ import { getConfigAccountById, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
4
3
  import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
5
4
  import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
6
5
  import { isMissingScopeError } from '@hubspot/local-dev-lib/errors/index';
@@ -60,8 +59,8 @@ export async function checkIfDefaultAccountIsSupported(accountConfig, hasPublicA
60
59
  }
61
60
  export function checkIfParentAccountIsAuthed(accountConfig) {
62
61
  if (!accountConfig.parentAccountId ||
63
- !getAccountConfig(accountConfig.parentAccountId)) {
64
- uiLogger.error(lib.localDevHelpers.account.checkIfParentAccountIsAuthed.notAuthedError(accountConfig.parentAccountId || '', uiAccountDescription(getAccountIdentifier(accountConfig))));
62
+ !getConfigAccountIfExists(accountConfig.parentAccountId)?.accountId) {
63
+ uiLogger.error(lib.localDevHelpers.account.checkIfParentAccountIsAuthed.notAuthedError(accountConfig.parentAccountId || '', uiAccountDescription(accountConfig.accountId)));
65
64
  process.exit(EXIT_CODES.SUCCESS);
66
65
  }
67
66
  }
@@ -122,11 +121,7 @@ export async function createSandboxForLocalDev(accountId, accountConfig, env) {
122
121
  trackCommandMetadataUsage('sandbox-create', { step: 'project-dev' }, accountId);
123
122
  const result = await buildSandbox(name, accountConfig, HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX, env);
124
123
  const targetAccountId = result.sandbox.sandboxHubId;
125
- const sandboxAccountConfig = getAccountConfig(result.sandbox.sandboxHubId);
126
- if (!sandboxAccountConfig) {
127
- uiLogger.error(lib.sandbox.create.developer.failure.generic);
128
- process.exit(EXIT_CODES.ERROR);
129
- }
124
+ const sandboxAccountConfig = getConfigAccountById(result.sandbox.sandboxHubId);
130
125
  const syncTasks = await getAvailableSyncTypes(accountConfig, sandboxAccountConfig);
131
126
  // For v1 sandboxes, keep sync here. Once we migrate to v2, this will be handled by BE automatically
132
127
  await syncSandbox(sandboxAccountConfig, accountConfig, env, syncTasks, true);
@@ -190,7 +185,7 @@ export async function useExistingDevTestAccount(env, account) {
190
185
  uiLogger.success(lib.developerTestAccount.create.success.configFileUpdated(devTestAcctConfigName, PERSONAL_ACCESS_KEY_AUTH_METHOD.name));
191
186
  }
192
187
  export async function hasSandboxes(account) {
193
- const accountId = getAccountIdentifier(account);
188
+ const accountId = account.accountId;
194
189
  if (!accountId) {
195
190
  return false;
196
191
  }
@@ -206,7 +201,7 @@ export async function hasSandboxes(account) {
206
201
  // Top level prompt to choose the type of account to test on
207
202
  export async function selectAccountTypePrompt(accountConfig) {
208
203
  const hasAccessToSandboxes = await hasSandboxes(accountConfig);
209
- const accountId = getAccountIdentifier(accountConfig);
204
+ const accountId = accountConfig.accountId;
210
205
  const result = await listPrompt(lib.localDevHelpers.account.selectAccountTypePrompt.message, {
211
206
  choices: [
212
207
  {
@@ -5,9 +5,11 @@ import { uiLogger } from '../../../ui/logger.js';
5
5
  import { commands } from '../../../../lang/en.js';
6
6
  export async function confirmLocalDevIsNotRunning() {
7
7
  try {
8
- await getServerPortByInstanceId(LOCAL_DEV_WEBSOCKET_SERVER_INSTANCE_ID);
9
- uiLogger.error(commands.project.dev.errors.localDevAlreadyRunning);
10
- process.exit(EXIT_CODES.ERROR);
8
+ const existingPortInUse = await getServerPortByInstanceId(LOCAL_DEV_WEBSOCKET_SERVER_INSTANCE_ID);
9
+ if (existingPortInUse) {
10
+ uiLogger.error(commands.project.dev.errors.localDevAlreadyRunning);
11
+ process.exit(EXIT_CODES.ERROR);
12
+ }
11
13
  }
12
14
  catch (error) {
13
15
  return;
@@ -0,0 +1,33 @@
1
+ export declare const REQUIRED_PACKAGES_AND_MIN_VERSIONS: {
2
+ readonly eslint: "9.0.0";
3
+ readonly '@typescript-eslint/eslint-plugin': "8.46.4";
4
+ readonly '@typescript-eslint/parser': "8.46.4";
5
+ readonly 'typescript-eslint': "8.46.4";
6
+ readonly jiti: "2.6.1";
7
+ };
8
+ export declare function isEslintInstalled(directory: string): boolean;
9
+ export declare function areAllLintPackagesInstalled(directory: string): boolean;
10
+ export declare function getMissingLintPackages(directory: string): {
11
+ missingPackages: string[];
12
+ };
13
+ export declare function hasEslintConfig(directory: string): boolean;
14
+ export declare function hasDeprecatedEslintConfig(directory: string): boolean;
15
+ export declare function getDeprecatedEslintConfigFiles(directory: string): string[];
16
+ export declare function createEslintConfig(directory: string): string;
17
+ export declare function lintPackagesInDirectory(directory: string, projectDir?: string): Promise<{
18
+ success: boolean;
19
+ output: string;
20
+ }>;
21
+ export declare function lintPackages(lintLocations?: string[], projectDir?: string): Promise<{
22
+ success: boolean;
23
+ results: Array<{
24
+ location: string;
25
+ success: boolean;
26
+ output: string;
27
+ }>;
28
+ }>;
29
+ export declare function displayLintResults(results: Array<{
30
+ location: string;
31
+ success: boolean;
32
+ output: string;
33
+ }>): void;