@hubspot/cli 7.7.27-experimental.2 → 7.7.29-experimental.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 (130) hide show
  1. package/README.md +0 -4
  2. package/api/__tests__/migrate.test.js +5 -5
  3. package/api/migrate.d.ts +10 -4
  4. package/api/migrate.js +2 -2
  5. package/commands/__tests__/create.test.js +20 -0
  6. package/commands/__tests__/testAccount.test.js +2 -0
  7. package/commands/app/__tests__/migrate.test.js +1 -0
  8. package/commands/create/function.js +2 -2
  9. package/commands/create/module.js +2 -2
  10. package/commands/create/template.js +2 -2
  11. package/commands/create.js +47 -0
  12. package/commands/getStarted.js +66 -4
  13. package/commands/mcp/setup.d.ts +0 -1
  14. package/commands/mcp/setup.js +3 -11
  15. package/commands/project/__tests__/create.test.js +57 -0
  16. package/commands/project/__tests__/devUnifiedFlow.test.js +18 -30
  17. package/commands/project/create.js +6 -1
  18. package/commands/project/deploy.js +31 -1
  19. package/commands/project/dev/deprecatedFlow.js +2 -1
  20. package/commands/project/dev/index.js +32 -12
  21. package/commands/project/dev/unifiedFlow.d.ts +1 -1
  22. package/commands/project/dev/unifiedFlow.js +10 -16
  23. package/commands/project/profile/delete.js +26 -14
  24. package/commands/testAccount/__tests__/importData.test.d.ts +1 -0
  25. package/commands/testAccount/__tests__/importData.test.js +93 -0
  26. package/commands/testAccount/create.js +23 -13
  27. package/commands/testAccount/importData.d.ts +9 -0
  28. package/commands/testAccount/importData.js +61 -0
  29. package/commands/testAccount.js +2 -0
  30. package/lang/en.d.ts +162 -46
  31. package/lang/en.js +177 -59
  32. package/lang/en.lyaml +35 -14
  33. package/lib/__tests__/importData.test.d.ts +1 -0
  34. package/lib/__tests__/importData.test.js +89 -0
  35. package/lib/accountTypes.js +2 -3
  36. package/lib/app/__tests__/migrate.test.js +81 -36
  37. package/lib/app/migrate.d.ts +17 -4
  38. package/lib/app/migrate.js +97 -19
  39. package/lib/constants.d.ts +1 -0
  40. package/lib/constants.js +1 -0
  41. package/lib/hasFeature.d.ts +1 -0
  42. package/lib/hasFeature.js +7 -0
  43. package/lib/importData.d.ts +3 -0
  44. package/lib/importData.js +50 -0
  45. package/lib/mcp/setup.d.ts +3 -5
  46. package/lib/mcp/setup.js +39 -139
  47. package/lib/process.js +15 -4
  48. package/lib/projects/__tests__/AppDevModeInterface.test.js +3 -3
  49. package/lib/projects/__tests__/LocalDevProcess.test.js +5 -95
  50. package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +6 -6
  51. package/lib/projects/__tests__/components.test.js +164 -7
  52. package/lib/projects/__tests__/localDevProjectHelpers.test.d.ts +1 -0
  53. package/lib/projects/__tests__/localDevProjectHelpers.test.js +118 -0
  54. package/lib/projects/add/v3AddComponent.js +16 -4
  55. package/lib/projects/components.d.ts +1 -0
  56. package/lib/projects/components.js +27 -1
  57. package/lib/projects/localDev/AppDevModeInterface.js +35 -3
  58. package/lib/projects/localDev/LocalDevLogger.d.ts +0 -4
  59. package/lib/projects/localDev/LocalDevLogger.js +2 -19
  60. package/lib/projects/localDev/LocalDevManager.js +1 -1
  61. package/lib/projects/localDev/LocalDevProcess.d.ts +1 -2
  62. package/lib/projects/localDev/LocalDevProcess.js +3 -26
  63. package/lib/projects/localDev/LocalDevState.d.ts +6 -7
  64. package/lib/projects/localDev/LocalDevState.js +16 -15
  65. package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +1 -0
  66. package/lib/projects/localDev/LocalDevWebsocketServer.js +17 -2
  67. package/lib/projects/localDev/{helpers.d.ts → helpers/account.d.ts} +1 -7
  68. package/lib/projects/localDev/{helpers.js → helpers/account.js} +44 -144
  69. package/lib/projects/localDev/helpers/project.d.ts +12 -0
  70. package/lib/projects/localDev/helpers/project.js +173 -0
  71. package/lib/projects/urls.d.ts +1 -0
  72. package/lib/projects/urls.js +4 -0
  73. package/lib/prompts/__tests__/createFunctionPrompt.test.d.ts +1 -0
  74. package/lib/prompts/__tests__/createFunctionPrompt.test.js +129 -0
  75. package/lib/prompts/__tests__/createModulePrompt.test.d.ts +1 -0
  76. package/lib/prompts/__tests__/createModulePrompt.test.js +187 -0
  77. package/lib/prompts/__tests__/createTemplatePrompt.test.d.ts +1 -0
  78. package/lib/prompts/__tests__/createTemplatePrompt.test.js +102 -0
  79. package/lib/prompts/confirmImportDataPrompt.d.ts +1 -0
  80. package/lib/prompts/confirmImportDataPrompt.js +12 -0
  81. package/lib/prompts/createFunctionPrompt.d.ts +2 -1
  82. package/lib/prompts/createFunctionPrompt.js +36 -7
  83. package/lib/prompts/createModulePrompt.d.ts +2 -1
  84. package/lib/prompts/createModulePrompt.js +48 -1
  85. package/lib/prompts/createTemplatePrompt.d.ts +3 -24
  86. package/lib/prompts/createTemplatePrompt.js +9 -1
  87. package/lib/prompts/importDataFilePathPrompt.d.ts +1 -0
  88. package/lib/prompts/importDataFilePathPrompt.js +24 -0
  89. package/lib/prompts/importDataTestAccountSelectPrompt.d.ts +3 -0
  90. package/lib/prompts/importDataTestAccountSelectPrompt.js +29 -0
  91. package/lib/prompts/projectDevTargetAccountPrompt.js +1 -0
  92. package/lib/prompts/promptUtils.d.ts +7 -1
  93. package/lib/prompts/promptUtils.js +14 -1
  94. package/lib/ui/__tests__/removeAnsiCodes.test.d.ts +1 -0
  95. package/lib/ui/__tests__/removeAnsiCodes.test.js +84 -0
  96. package/lib/ui/index.js +3 -6
  97. package/lib/ui/removeAnsiCodes.d.ts +1 -0
  98. package/lib/ui/removeAnsiCodes.js +4 -0
  99. package/mcp-server/server.js +2 -1
  100. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +38 -0
  101. package/mcp-server/tools/cms/HsCreateModuleTool.js +118 -0
  102. package/mcp-server/tools/cms/HsListTool.d.ts +23 -0
  103. package/mcp-server/tools/cms/HsListTool.js +58 -0
  104. package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.d.ts +1 -0
  105. package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +224 -0
  106. package/mcp-server/tools/cms/__tests__/HsListTool.test.d.ts +1 -0
  107. package/mcp-server/tools/cms/__tests__/HsListTool.test.js +120 -0
  108. package/mcp-server/tools/index.d.ts +1 -0
  109. package/mcp-server/tools/index.js +12 -0
  110. package/mcp-server/tools/project/DocFetchTool.d.ts +17 -0
  111. package/mcp-server/tools/project/DocFetchTool.js +49 -0
  112. package/mcp-server/tools/project/DocsSearchTool.d.ts +26 -0
  113. package/mcp-server/tools/project/DocsSearchTool.js +62 -0
  114. package/mcp-server/tools/project/GetConfigValuesTool.js +3 -2
  115. package/mcp-server/tools/project/__tests__/DocFetchTool.test.d.ts +1 -0
  116. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +117 -0
  117. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.d.ts +1 -0
  118. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +190 -0
  119. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +1 -1
  120. package/mcp-server/tools/project/constants.d.ts +2 -0
  121. package/mcp-server/tools/project/constants.js +6 -0
  122. package/mcp-server/utils/toolUsageTracking.d.ts +3 -1
  123. package/mcp-server/utils/toolUsageTracking.js +2 -1
  124. package/package.json +9 -6
  125. package/types/Cms.d.ts +16 -0
  126. package/types/Cms.js +25 -1
  127. package/types/LocalDev.d.ts +0 -3
  128. package/types/Prompts.d.ts +1 -0
  129. package/ui/index.d.ts +1 -0
  130. package/ui/index.js +6 -0
@@ -6,3 +6,4 @@ export declare function getProjectActivityUrl(projectName: string, accountId: nu
6
6
  export declare function getProjectBuildDetailUrl(projectName: string, buildId: number, accountId: number): string;
7
7
  export declare function getProjectDeployDetailUrl(projectName: string, deployId: number, accountId: number): string;
8
8
  export declare function getLocalDevUiUrl(accountId: number, showWelcomeScreen?: boolean): string;
9
+ export declare function getAccountHomeUrl(accountId: number): string;
@@ -37,3 +37,7 @@ export function getProjectDeployDetailUrl(projectName, deployId, accountId) {
37
37
  export function getLocalDevUiUrl(accountId, showWelcomeScreen) {
38
38
  return `${getBaseUrl(accountId)}/developer-projects-local-dev/${accountId}${showWelcomeScreen ? '?welcome' : ''}`;
39
39
  }
40
+ export function getAccountHomeUrl(accountId) {
41
+ const baseUrl = getHubSpotWebsiteOrigin(getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD);
42
+ return `${baseUrl}/home?portalId=${accountId}`;
43
+ }
@@ -0,0 +1,129 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { createFunctionPrompt } from '../createFunctionPrompt.js';
3
+ import { promptUser } from '../promptUtils.js';
4
+ vi.mock('../promptUtils.js');
5
+ const mockPromptUser = vi.mocked(promptUser);
6
+ describe('createFunctionPrompt', () => {
7
+ beforeEach(() => {
8
+ vi.resetAllMocks();
9
+ });
10
+ describe('when all parameters are provided', () => {
11
+ it('should return provided values without prompting', async () => {
12
+ const commandArgs = {
13
+ functionsFolder: 'my-functions',
14
+ filename: 'my-function',
15
+ endpointMethod: 'POST',
16
+ endpointPath: '/api/test',
17
+ };
18
+ const result = await createFunctionPrompt(commandArgs);
19
+ expect(mockPromptUser).not.toHaveBeenCalled();
20
+ expect(result).toEqual({
21
+ functionsFolder: 'my-functions',
22
+ filename: 'my-function',
23
+ endpointMethod: 'POST',
24
+ endpointPath: '/api/test',
25
+ });
26
+ });
27
+ it('should use default GET method when endpointMethod not provided', async () => {
28
+ const commandArgs = {
29
+ functionsFolder: 'my-functions',
30
+ filename: 'my-function',
31
+ endpointPath: '/api/test',
32
+ };
33
+ const result = await createFunctionPrompt(commandArgs);
34
+ expect(mockPromptUser).not.toHaveBeenCalled();
35
+ expect(result).toEqual({
36
+ functionsFolder: 'my-functions',
37
+ filename: 'my-function',
38
+ endpointMethod: 'GET',
39
+ endpointPath: '/api/test',
40
+ });
41
+ });
42
+ });
43
+ describe('when some parameters are missing', () => {
44
+ it('should only prompt for missing parameters', async () => {
45
+ const commandArgs = {
46
+ functionsFolder: 'my-functions',
47
+ endpointMethod: 'POST',
48
+ };
49
+ mockPromptUser.mockResolvedValue({
50
+ filename: 'prompted-function',
51
+ endpointPath: '/prompted-path',
52
+ });
53
+ const result = await createFunctionPrompt(commandArgs);
54
+ expect(mockPromptUser).toHaveBeenCalledWith([
55
+ expect.objectContaining({ name: 'filename' }),
56
+ expect.objectContaining({ name: 'endpointPath' }),
57
+ ]);
58
+ expect(result).toEqual({
59
+ functionsFolder: 'my-functions',
60
+ filename: 'prompted-function',
61
+ endpointMethod: 'POST',
62
+ endpointPath: '/prompted-path',
63
+ });
64
+ });
65
+ });
66
+ describe('when no parameters are provided', () => {
67
+ it('should prompt for all parameters', async () => {
68
+ mockPromptUser.mockResolvedValue({
69
+ functionsFolder: 'prompted-functions',
70
+ filename: 'prompted-function',
71
+ endpointMethod: 'GET',
72
+ endpointPath: '/prompted-path',
73
+ });
74
+ const result = await createFunctionPrompt();
75
+ expect(mockPromptUser).toHaveBeenCalledWith([
76
+ expect.objectContaining({ name: 'functionsFolder' }),
77
+ expect.objectContaining({ name: 'filename' }),
78
+ expect.objectContaining({ name: 'endpointMethod' }),
79
+ expect.objectContaining({ name: 'endpointPath' }),
80
+ ]);
81
+ expect(result).toEqual({
82
+ functionsFolder: 'prompted-functions',
83
+ filename: 'prompted-function',
84
+ endpointMethod: 'GET',
85
+ endpointPath: '/prompted-path',
86
+ });
87
+ });
88
+ });
89
+ describe('parameter precedence', () => {
90
+ it('should prioritize command args over prompted values', async () => {
91
+ const commandArgs = {
92
+ functionsFolder: 'arg-functions',
93
+ };
94
+ mockPromptUser.mockResolvedValue({
95
+ filename: 'prompted-function',
96
+ endpointMethod: 'POST',
97
+ endpointPath: '/prompted-path',
98
+ });
99
+ const result = await createFunctionPrompt(commandArgs);
100
+ expect(result).toEqual({
101
+ functionsFolder: 'arg-functions', // from commandArgs
102
+ filename: 'prompted-function', // from prompt
103
+ endpointMethod: 'POST', // from prompt
104
+ endpointPath: '/prompted-path', // from prompt
105
+ });
106
+ });
107
+ it('should handle mixed scenario with partial command args and prompting', async () => {
108
+ const commandArgs = {
109
+ functionsFolder: 'my-funcs',
110
+ endpointMethod: 'DELETE',
111
+ };
112
+ mockPromptUser.mockResolvedValue({
113
+ filename: 'delete-handler',
114
+ endpointPath: '/api/delete',
115
+ });
116
+ const result = await createFunctionPrompt(commandArgs);
117
+ expect(mockPromptUser).toHaveBeenCalledWith([
118
+ expect.objectContaining({ name: 'filename' }),
119
+ expect.objectContaining({ name: 'endpointPath' }),
120
+ ]);
121
+ expect(result).toEqual({
122
+ functionsFolder: 'my-funcs', // from commandArgs
123
+ filename: 'delete-handler', // from prompt
124
+ endpointMethod: 'DELETE', // from commandArgs
125
+ endpointPath: '/api/delete', // from prompt
126
+ });
127
+ });
128
+ });
129
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,187 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { createModulePrompt } from '../createModulePrompt.js';
3
+ import { promptUser } from '../promptUtils.js';
4
+ vi.mock('../promptUtils.js');
5
+ const mockPromptUser = vi.mocked(promptUser);
6
+ describe('createModulePrompt', () => {
7
+ beforeEach(() => {
8
+ vi.resetAllMocks();
9
+ });
10
+ describe('when all parameters are provided', () => {
11
+ it('should return provided values without prompting', async () => {
12
+ const commandArgs = {
13
+ moduleLabel: 'My Module',
14
+ reactType: true,
15
+ contentTypes: 'LANDING_PAGE,SITE_PAGE',
16
+ global: false,
17
+ availableForNewContent: true,
18
+ };
19
+ const result = await createModulePrompt(commandArgs);
20
+ expect(mockPromptUser).not.toHaveBeenCalled();
21
+ expect(result).toEqual({
22
+ moduleLabel: 'My Module',
23
+ reactType: true,
24
+ contentTypes: ['LANDING_PAGE', 'SITE_PAGE'],
25
+ global: false,
26
+ availableForNewContent: true,
27
+ });
28
+ });
29
+ it('should use default values when optional parameters not provided', async () => {
30
+ const commandArgs = {
31
+ moduleLabel: 'My Module',
32
+ };
33
+ mockPromptUser.mockResolvedValue({
34
+ reactType: false,
35
+ contentTypes: ['ANY'],
36
+ global: false,
37
+ availableForNewContent: true,
38
+ });
39
+ const result = await createModulePrompt(commandArgs);
40
+ expect(mockPromptUser).toHaveBeenCalledWith([
41
+ expect.objectContaining({ name: 'reactType' }),
42
+ expect.objectContaining({ name: 'contentTypes' }),
43
+ expect.objectContaining({ name: 'global' }),
44
+ expect.objectContaining({ name: 'availableForNewContent' }),
45
+ ]);
46
+ expect(result).toEqual({
47
+ moduleLabel: 'My Module',
48
+ reactType: false,
49
+ contentTypes: ['ANY'],
50
+ global: false,
51
+ availableForNewContent: true,
52
+ });
53
+ });
54
+ it('should parse contentTypes string correctly', async () => {
55
+ const commandArgs = {
56
+ moduleLabel: 'Test Module',
57
+ contentTypes: 'BLOG_POST, EMAIL, LANDING_PAGE',
58
+ };
59
+ mockPromptUser.mockResolvedValue({
60
+ reactType: false,
61
+ global: false,
62
+ availableForNewContent: true,
63
+ });
64
+ const result = await createModulePrompt(commandArgs);
65
+ expect(result.contentTypes).toEqual([
66
+ 'BLOG_POST',
67
+ 'EMAIL',
68
+ 'LANDING_PAGE',
69
+ ]);
70
+ });
71
+ });
72
+ describe('when some parameters are missing', () => {
73
+ it('should only prompt for missing parameters', async () => {
74
+ const commandArgs = {
75
+ moduleLabel: 'My Module',
76
+ reactType: true,
77
+ };
78
+ mockPromptUser.mockResolvedValue({
79
+ contentTypes: ['SITE_PAGE'],
80
+ global: true,
81
+ availableForNewContent: false,
82
+ });
83
+ const result = await createModulePrompt(commandArgs);
84
+ expect(mockPromptUser).toHaveBeenCalledWith([
85
+ expect.objectContaining({ name: 'contentTypes' }),
86
+ expect.objectContaining({ name: 'global' }),
87
+ expect.objectContaining({ name: 'availableForNewContent' }),
88
+ ]);
89
+ expect(result).toEqual({
90
+ moduleLabel: 'My Module',
91
+ reactType: true,
92
+ contentTypes: ['SITE_PAGE'],
93
+ global: true,
94
+ availableForNewContent: false,
95
+ });
96
+ });
97
+ });
98
+ describe('when no parameters are provided', () => {
99
+ it('should prompt for all parameters', async () => {
100
+ mockPromptUser.mockResolvedValue({
101
+ moduleLabel: 'Prompted Module',
102
+ reactType: false,
103
+ contentTypes: ['ANY'],
104
+ global: false,
105
+ availableForNewContent: true,
106
+ });
107
+ const result = await createModulePrompt();
108
+ expect(mockPromptUser).toHaveBeenCalledWith([
109
+ expect.objectContaining({ name: 'moduleLabel' }),
110
+ expect.objectContaining({ name: 'reactType' }),
111
+ expect.objectContaining({ name: 'contentTypes' }),
112
+ expect.objectContaining({ name: 'global' }),
113
+ expect.objectContaining({ name: 'availableForNewContent' }),
114
+ ]);
115
+ expect(result).toEqual({
116
+ moduleLabel: 'Prompted Module',
117
+ reactType: false,
118
+ contentTypes: ['ANY'],
119
+ global: false,
120
+ availableForNewContent: true,
121
+ });
122
+ });
123
+ });
124
+ describe('parameter precedence', () => {
125
+ it('should prioritize command args over prompted values', async () => {
126
+ const commandArgs = {
127
+ moduleLabel: 'Args Module',
128
+ global: true,
129
+ };
130
+ mockPromptUser.mockResolvedValue({
131
+ reactType: false,
132
+ contentTypes: ['EMAIL'],
133
+ availableForNewContent: false,
134
+ });
135
+ const result = await createModulePrompt(commandArgs);
136
+ expect(result).toEqual({
137
+ moduleLabel: 'Args Module', // from commandArgs
138
+ reactType: false, // from prompt
139
+ contentTypes: ['EMAIL'], // from prompt
140
+ global: true, // from commandArgs
141
+ availableForNewContent: false, // from prompt
142
+ });
143
+ });
144
+ it('should handle boolean false values correctly', async () => {
145
+ const commandArgs = {
146
+ moduleLabel: 'Test Module',
147
+ reactType: false,
148
+ contentTypes: 'ANY',
149
+ global: false,
150
+ availableForNewContent: false,
151
+ };
152
+ const result = await createModulePrompt(commandArgs);
153
+ expect(mockPromptUser).not.toHaveBeenCalled();
154
+ expect(result).toEqual({
155
+ moduleLabel: 'Test Module',
156
+ reactType: false,
157
+ contentTypes: ['ANY'],
158
+ global: false,
159
+ availableForNewContent: false,
160
+ });
161
+ });
162
+ it('should handle mixed scenario with partial command args and prompting', async () => {
163
+ const commandArgs = {
164
+ moduleLabel: 'Partial Module',
165
+ contentTypes: 'BLOG_POST,BLOG_LISTING',
166
+ };
167
+ mockPromptUser.mockResolvedValue({
168
+ reactType: true,
169
+ global: false,
170
+ availableForNewContent: true,
171
+ });
172
+ const result = await createModulePrompt(commandArgs);
173
+ expect(mockPromptUser).toHaveBeenCalledWith([
174
+ expect.objectContaining({ name: 'reactType' }),
175
+ expect.objectContaining({ name: 'global' }),
176
+ expect.objectContaining({ name: 'availableForNewContent' }),
177
+ ]);
178
+ expect(result).toEqual({
179
+ moduleLabel: 'Partial Module', // from commandArgs
180
+ reactType: true, // from prompt
181
+ contentTypes: ['BLOG_POST', 'BLOG_LISTING'], // from commandArgs (parsed)
182
+ global: false, // from prompt
183
+ availableForNewContent: true, // from prompt
184
+ });
185
+ });
186
+ });
187
+ });
@@ -0,0 +1,102 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import { createTemplatePrompt } from '../createTemplatePrompt.js';
3
+ import { promptUser } from '../promptUtils.js';
4
+ vi.mock('../promptUtils.js');
5
+ const mockPromptUser = vi.mocked(promptUser);
6
+ describe('createTemplatePrompt', () => {
7
+ beforeEach(() => {
8
+ vi.resetAllMocks();
9
+ });
10
+ describe('when templateType is provided', () => {
11
+ it('should return provided templateType without prompting', async () => {
12
+ const commandArgs = {
13
+ templateType: 'page-template',
14
+ };
15
+ const result = await createTemplatePrompt(commandArgs);
16
+ expect(mockPromptUser).not.toHaveBeenCalled();
17
+ expect(result).toEqual({
18
+ templateType: 'page-template',
19
+ });
20
+ });
21
+ it('should work with different template types', async () => {
22
+ const testCases = [
23
+ 'email-template',
24
+ 'partial',
25
+ 'global-partial',
26
+ 'blog-listing-template',
27
+ 'blog-post-template',
28
+ 'search-template',
29
+ 'section',
30
+ ];
31
+ for (const templateType of testCases) {
32
+ const commandArgs = { templateType };
33
+ const result = await createTemplatePrompt(commandArgs);
34
+ expect(mockPromptUser).not.toHaveBeenCalled();
35
+ expect(result).toEqual({ templateType });
36
+ vi.resetAllMocks();
37
+ }
38
+ });
39
+ });
40
+ describe('when templateType is not provided', () => {
41
+ it('should prompt for templateType', async () => {
42
+ mockPromptUser.mockResolvedValue({
43
+ templateType: 'page-template',
44
+ });
45
+ const result = await createTemplatePrompt();
46
+ expect(mockPromptUser).toHaveBeenCalledWith([
47
+ expect.objectContaining({
48
+ name: 'templateType',
49
+ type: 'list',
50
+ choices: expect.any(Array),
51
+ }),
52
+ ]);
53
+ expect(result).toEqual({
54
+ templateType: 'page-template',
55
+ });
56
+ });
57
+ it('should prompt when commandArgs is empty', async () => {
58
+ mockPromptUser.mockResolvedValue({
59
+ templateType: 'email-template',
60
+ });
61
+ const result = await createTemplatePrompt({});
62
+ expect(mockPromptUser).toHaveBeenCalledWith([
63
+ expect.objectContaining({ name: 'templateType' }),
64
+ ]);
65
+ expect(result).toEqual({
66
+ templateType: 'email-template',
67
+ });
68
+ });
69
+ it('should prompt when templateType is undefined', async () => {
70
+ const commandArgs = {
71
+ templateType: undefined,
72
+ };
73
+ mockPromptUser.mockResolvedValue({
74
+ templateType: 'partial',
75
+ });
76
+ const result = await createTemplatePrompt(commandArgs);
77
+ expect(mockPromptUser).toHaveBeenCalledWith([
78
+ expect.objectContaining({ name: 'templateType' }),
79
+ ]);
80
+ expect(result).toEqual({
81
+ templateType: 'partial',
82
+ });
83
+ });
84
+ });
85
+ describe('integration scenarios', () => {
86
+ it('should handle mixed usage patterns', async () => {
87
+ // First call with templateType provided
88
+ let result = await createTemplatePrompt({
89
+ templateType: 'blog-post-template',
90
+ });
91
+ expect(result.templateType).toBe('blog-post-template');
92
+ expect(mockPromptUser).not.toHaveBeenCalled();
93
+ // Second call without templateType
94
+ mockPromptUser.mockResolvedValue({
95
+ templateType: 'section',
96
+ });
97
+ result = await createTemplatePrompt();
98
+ expect(result.templateType).toBe('section');
99
+ expect(mockPromptUser).toHaveBeenCalledTimes(1);
100
+ });
101
+ });
102
+ });
@@ -0,0 +1 @@
1
+ export declare function confirmImportDataPrompt(targetAccountId: number, dataFileNames: string[]): Promise<boolean>;
@@ -0,0 +1,12 @@
1
+ import { getAccountConfig } from '@hubspot/local-dev-lib/config';
2
+ import { promptUser } from './promptUtils.js';
3
+ import { lib } from '../../lang/en.js';
4
+ export async function confirmImportDataPrompt(targetAccountId, dataFileNames) {
5
+ const account = getAccountConfig(targetAccountId);
6
+ const { confirmImportData } = await promptUser({
7
+ type: 'confirm',
8
+ name: 'confirmImportData',
9
+ message: lib.prompts.confirmImportDataPrompt.message(dataFileNames, account),
10
+ });
11
+ return confirmImportData;
12
+ }
@@ -1,8 +1,9 @@
1
+ import { CreateArgs } from '../../types/Cms.js';
1
2
  type CreateFunctionPromptResponse = {
2
3
  functionsFolder: string;
3
4
  filename: string;
4
5
  endpointMethod: string;
5
6
  endpointPath: string;
6
7
  };
7
- export declare function createFunctionPrompt(): Promise<CreateFunctionPromptResponse>;
8
+ export declare function createFunctionPrompt(commandArgs?: Partial<CreateArgs>): Promise<CreateFunctionPromptResponse>;
8
9
  export {};
@@ -55,11 +55,40 @@ const ENDPOINT_PATH_PROMPT = {
55
55
  return true;
56
56
  },
57
57
  };
58
- export function createFunctionPrompt() {
59
- return promptUser([
60
- FUNCTIONS_FOLDER_PROMPT,
61
- FUNCTION_FILENAME_PROMPT,
62
- ENDPOINT_METHOD_PROMPT,
63
- ENDPOINT_PATH_PROMPT,
64
- ]);
58
+ export function createFunctionPrompt(commandArgs = {}) {
59
+ // Check if all required parameters are provided (endpointMethod has default)
60
+ const hasAllRequired = commandArgs.functionsFolder &&
61
+ commandArgs.filename &&
62
+ commandArgs.endpointPath;
63
+ if (hasAllRequired) {
64
+ return Promise.resolve({
65
+ functionsFolder: commandArgs.functionsFolder,
66
+ filename: commandArgs.filename,
67
+ endpointMethod: commandArgs.endpointMethod || 'GET',
68
+ endpointPath: commandArgs.endpointPath,
69
+ });
70
+ }
71
+ const prompts = [];
72
+ // Only prompt for missing parameters
73
+ if (!commandArgs.functionsFolder) {
74
+ prompts.push(FUNCTIONS_FOLDER_PROMPT);
75
+ }
76
+ if (!commandArgs.filename) {
77
+ prompts.push(FUNCTION_FILENAME_PROMPT);
78
+ }
79
+ if (!commandArgs.endpointMethod) {
80
+ prompts.push(ENDPOINT_METHOD_PROMPT);
81
+ }
82
+ if (!commandArgs.endpointPath) {
83
+ prompts.push(ENDPOINT_PATH_PROMPT);
84
+ }
85
+ return promptUser(prompts).then(promptResponse => {
86
+ // Merge prompted values with provided commandArgs
87
+ return {
88
+ functionsFolder: commandArgs.functionsFolder || promptResponse.functionsFolder,
89
+ filename: commandArgs.filename || promptResponse.filename,
90
+ endpointMethod: commandArgs.endpointMethod || promptResponse.endpointMethod || 'GET',
91
+ endpointPath: commandArgs.endpointPath || promptResponse.endpointPath,
92
+ };
93
+ });
65
94
  }
@@ -1,3 +1,4 @@
1
+ import { CreateArgs } from '../../types/Cms.js';
1
2
  type CreateModulePromptResponse = {
2
3
  moduleLabel: string;
3
4
  reactType: boolean;
@@ -5,5 +6,5 @@ type CreateModulePromptResponse = {
5
6
  global: boolean;
6
7
  availableForNewContent: boolean;
7
8
  };
8
- export declare function createModulePrompt(): Promise<CreateModulePromptResponse>;
9
+ export declare function createModulePrompt(commandArgs?: Partial<CreateArgs>): Promise<CreateModulePromptResponse>;
9
10
  export {};
@@ -58,7 +58,54 @@ const AVAILABLE_FOR_NEW_CONTENT = {
58
58
  message: i18n(`lib.prompts.createModulePrompt.availableForNewContent`),
59
59
  default: true,
60
60
  };
61
- export function createModulePrompt() {
61
+ export function createModulePrompt(commandArgs = {}) {
62
+ // Check if moduleLabel is provided (main requirement to skip full prompting)
63
+ // but still allow individual parameter prompting for enhanced UX
64
+ if (commandArgs.moduleLabel) {
65
+ const prompts = [];
66
+ // Only prompt for parameters not explicitly provided
67
+ if (commandArgs.reactType === undefined) {
68
+ prompts.push(REACT_TYPE_PROMPT);
69
+ }
70
+ if (!commandArgs.contentTypes) {
71
+ prompts.push(CONTENT_TYPES_PROMPT);
72
+ }
73
+ if (commandArgs.global === undefined) {
74
+ prompts.push(GLOBAL_PROMPT);
75
+ }
76
+ if (commandArgs.availableForNewContent === undefined) {
77
+ prompts.push(AVAILABLE_FOR_NEW_CONTENT);
78
+ }
79
+ // If no additional prompts needed, return with defaults
80
+ if (prompts.length === 0) {
81
+ const contentTypesArray = commandArgs.contentTypes
82
+ ? commandArgs.contentTypes.split(',').map((t) => t.trim())
83
+ : ['ANY'];
84
+ return Promise.resolve({
85
+ moduleLabel: commandArgs.moduleLabel,
86
+ reactType: commandArgs.reactType ?? false,
87
+ contentTypes: contentTypesArray,
88
+ global: commandArgs.global ?? false,
89
+ availableForNewContent: commandArgs.availableForNewContent ?? true,
90
+ });
91
+ }
92
+ // Prompt only for missing optional parameters
93
+ return promptUser(prompts).then(promptResponse => {
94
+ const contentTypesArray = commandArgs.contentTypes
95
+ ? commandArgs.contentTypes.split(',').map((t) => t.trim())
96
+ : promptResponse.contentTypes || ['ANY'];
97
+ return {
98
+ moduleLabel: commandArgs.moduleLabel,
99
+ reactType: commandArgs.reactType ?? promptResponse.reactType ?? false,
100
+ contentTypes: contentTypesArray,
101
+ global: commandArgs.global ?? promptResponse.global ?? false,
102
+ availableForNewContent: commandArgs.availableForNewContent ??
103
+ promptResponse.availableForNewContent ??
104
+ true,
105
+ };
106
+ });
107
+ }
108
+ // No moduleLabel provided, prompt for everything (original behavior)
62
109
  return promptUser([
63
110
  MODULE_LABEL_PROMPT,
64
111
  REACT_TYPE_PROMPT,
@@ -1,27 +1,6 @@
1
- declare const templateTypeChoices: [{
2
- readonly name: "page";
3
- readonly value: "page-template";
4
- }, {
5
- readonly name: "email";
6
- readonly value: "email-template";
7
- }, {
8
- readonly name: "partial";
9
- readonly value: "partial";
10
- }, {
11
- readonly name: "global partial";
12
- readonly value: "global-partial";
13
- }, {
14
- readonly name: "blog listing";
15
- readonly value: "blog-listing-template";
16
- }, {
17
- readonly name: "blog post";
18
- readonly value: "blog-post-template";
19
- }, {
20
- readonly name: "search results";
21
- readonly value: "search-template";
22
- }];
1
+ import { CreateArgs, TemplateType } from '../../types/Cms.js';
23
2
  interface CreateTemplatePromptResponse {
24
- templateType: (typeof templateTypeChoices)[number]['value'];
3
+ templateType: TemplateType;
25
4
  }
26
- export declare function createTemplatePrompt(): Promise<CreateTemplatePromptResponse>;
5
+ export declare function createTemplatePrompt(commandArgs?: Partial<CreateArgs>): Promise<CreateTemplatePromptResponse>;
27
6
  export {};
@@ -8,6 +8,7 @@ const templateTypeChoices = [
8
8
  { name: 'blog listing', value: 'blog-listing-template' },
9
9
  { name: 'blog post', value: 'blog-post-template' },
10
10
  { name: 'search results', value: 'search-template' },
11
+ { name: 'section', value: 'section' },
11
12
  ];
12
13
  const TEMPLATE_TYPE_PROMPT = {
13
14
  type: 'list',
@@ -16,6 +17,13 @@ const TEMPLATE_TYPE_PROMPT = {
16
17
  default: 'page',
17
18
  choices: templateTypeChoices,
18
19
  };
19
- export function createTemplatePrompt() {
20
+ export function createTemplatePrompt(commandArgs = {}) {
21
+ // If templateType is provided, return it directly
22
+ if (commandArgs.templateType) {
23
+ return Promise.resolve({
24
+ templateType: commandArgs.templateType,
25
+ });
26
+ }
27
+ // No templateType provided, prompt for it (original behavior)
20
28
  return promptUser([TEMPLATE_TYPE_PROMPT]);
21
29
  }
@@ -0,0 +1 @@
1
+ export declare function importDataFilePathPrompt(): Promise<string>;
@@ -0,0 +1,24 @@
1
+ import { validateImportRequestFile } from '@hubspot/local-dev-lib/crm';
2
+ import { promptUser } from './promptUtils.js';
3
+ import { lib } from '../../lang/en.js';
4
+ import { logError } from '../errorHandlers/index.js';
5
+ import { uiLogger } from '../ui/logger.js';
6
+ export async function importDataFilePathPrompt() {
7
+ uiLogger.log(lib.prompts.importDataFilePathPrompt.promptContext);
8
+ const { filePath } = await promptUser({
9
+ type: 'input',
10
+ name: 'filePath',
11
+ message: lib.prompts.importDataFilePathPrompt.promptMessage,
12
+ validate: (filePath) => {
13
+ try {
14
+ validateImportRequestFile(filePath);
15
+ return true;
16
+ }
17
+ catch (error) {
18
+ logError(error);
19
+ return false;
20
+ }
21
+ },
22
+ });
23
+ return filePath;
24
+ }