@hubspot/cli 7.6.0-beta.10 → 7.6.0-beta.12
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.
- package/commands/app/__tests__/migrate.test.js +1 -0
- package/commands/getStarted.js +70 -22
- package/commands/mcp/setup.d.ts +0 -1
- package/commands/mcp/setup.js +3 -11
- package/commands/project/__tests__/add.test.js +64 -0
- package/commands/project/__tests__/create.test.js +57 -0
- package/commands/project/__tests__/deploy.test.js +3 -2
- package/commands/project/__tests__/devUnifiedFlow.test.js +14 -5
- package/commands/project/add.d.ts +1 -1
- package/commands/project/add.js +3 -5
- package/commands/project/create.js +7 -2
- package/commands/project/deploy.js +9 -61
- package/commands/project/dev/index.js +33 -13
- package/commands/project/dev/unifiedFlow.js +8 -7
- package/commands/project/upload.js +2 -2
- package/commands/project/validate.js +1 -1
- package/commands/project/watch.js +2 -2
- package/lang/en.d.ts +36 -13
- package/lang/en.js +49 -25
- package/lang/en.lyaml +12 -12
- package/lib/__tests__/hasFeature.test.js +145 -7
- package/lib/__tests__/importData.test.js +1 -1
- package/lib/app/migrate.js +9 -2
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +2 -0
- package/lib/errorHandlers/index.d.ts +4 -0
- package/lib/errorHandlers/index.js +1 -1
- package/lib/hasFeature.js +6 -0
- package/lib/importData.js +1 -1
- package/lib/mcp/setup.d.ts +0 -2
- package/lib/mcp/setup.js +4 -29
- package/lib/projects/__tests__/AppDevModeInterface.test.js +72 -44
- package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
- package/lib/projects/__tests__/components.test.js +164 -7
- package/lib/projects/__tests__/deploy.test.js +164 -0
- package/lib/projects/__tests__/platformVersion.test.d.ts +1 -0
- package/lib/projects/__tests__/{buildAndDeploy.test.js → platformVersion.test.js} +2 -2
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +49 -6
- package/lib/projects/add/__tests__/v3AddComponent.test.js +142 -8
- package/lib/projects/add/legacyAddComponent.d.ts +1 -1
- package/lib/projects/add/legacyAddComponent.js +5 -1
- package/lib/projects/add/v3AddComponent.d.ts +2 -1
- package/lib/projects/add/v3AddComponent.js +22 -5
- package/lib/projects/components.d.ts +1 -0
- package/lib/projects/components.js +27 -1
- package/lib/projects/create/__tests__/v3.test.js +97 -9
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/legacy.js +1 -1
- package/lib/projects/create/v3.d.ts +2 -2
- package/lib/projects/create/v3.js +35 -12
- package/lib/projects/deploy.d.ts +13 -0
- package/lib/projects/deploy.js +63 -0
- package/lib/projects/localDev/AppDevModeInterface.d.ts +5 -3
- package/lib/projects/localDev/AppDevModeInterface.js +132 -48
- package/lib/projects/localDev/DevServerManagerV2.js +1 -0
- package/lib/projects/localDev/LocalDevProcess.js +3 -1
- package/lib/projects/localDev/LocalDevState.d.ts +5 -2
- package/lib/projects/localDev/LocalDevState.js +9 -1
- package/lib/projects/localDev/helpers/account.js +2 -2
- package/lib/projects/localDev/helpers/project.d.ts +2 -2
- package/lib/projects/localDev/helpers/project.js +6 -8
- package/lib/projects/platformVersion.d.ts +1 -0
- package/lib/projects/platformVersion.js +10 -0
- package/lib/projects/{buildAndDeploy.d.ts → pollProjectBuildAndDeploy.d.ts} +0 -1
- package/lib/projects/{buildAndDeploy.js → pollProjectBuildAndDeploy.js} +0 -10
- package/lib/projects/upload.js +1 -1
- package/lib/projects/urls.d.ts +1 -0
- package/lib/projects/urls.js +3 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/projectAddPrompt.test.js +143 -0
- package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.d.ts +1 -0
- package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.js +160 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +1 -0
- package/lib/prompts/importDataFilePathPrompt.js +4 -2
- package/lib/prompts/installAppPrompt.d.ts +6 -1
- package/lib/prompts/installAppPrompt.js +6 -1
- package/lib/prompts/projectAddPrompt.js +1 -1
- package/lib/prompts/projectDevTargetAccountPrompt.js +1 -0
- package/lib/prompts/promptUtils.d.ts +7 -1
- package/lib/prompts/promptUtils.js +14 -1
- package/lib/prompts/selectProjectTemplatePrompt.js +1 -1
- package/lib/ui/index.js +3 -6
- package/mcp-server/server.js +2 -1
- package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +96 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +38 -0
- package/mcp-server/tools/cms/HsCreateModuleTool.js +118 -0
- package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +26 -0
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +75 -0
- package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +32 -0
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +76 -0
- package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListFunctionsTool.js +58 -0
- package/mcp-server/tools/cms/HsListTool.d.ts +23 -0
- package/mcp-server/tools/cms/HsListTool.js +58 -0
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +251 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +224 -0
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +206 -0
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +183 -0
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +120 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.d.ts +1 -0
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +120 -0
- package/mcp-server/tools/index.d.ts +1 -0
- package/mcp-server/tools/index.js +16 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +3 -3
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +5 -5
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/DocFetchTool.js +3 -3
- package/mcp-server/tools/project/DocsSearchTool.js +3 -3
- package/mcp-server/tools/project/GetConfigValuesTool.js +4 -4
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +2 -2
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +3 -3
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +3 -3
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -1
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -1
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -1
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/tools/project/constants.js +14 -6
- package/package.json +5 -4
- package/types/LocalDev.d.ts +2 -1
- package/types/Projects.d.ts +1 -0
- package/types/Prompts.d.ts +1 -0
- package/ui/components/BoxWithTitle.d.ts +8 -0
- package/ui/components/BoxWithTitle.js +9 -0
- package/ui/components/HorizontalSelectPrompt.d.ts +8 -0
- package/ui/components/HorizontalSelectPrompt.js +30 -0
- package/ui/components/StatusMessageBoxes.d.ts +12 -0
- package/ui/components/StatusMessageBoxes.js +31 -0
- package/ui/lib/ui-testing-utils.d.ts +9 -0
- package/ui/lib/ui-testing-utils.js +47 -0
- package/ui/lib/useTerminalSize.d.ts +13 -0
- package/ui/lib/useTerminalSize.js +31 -0
- package/ui/styles.d.ts +18 -0
- package/ui/styles.js +18 -0
- package/ui/views/UiSandbox.d.ts +5 -0
- package/ui/views/UiSandbox.js +25 -0
- /package/lib/projects/__tests__/{buildAndDeploy.test.d.ts → deploy.test.d.ts} +0 -0
|
@@ -10,6 +10,7 @@ vi.mock('@hubspot/local-dev-lib/config');
|
|
|
10
10
|
vi.mock('@hubspot/local-dev-lib/logger');
|
|
11
11
|
vi.mock('../../../lib/app/migrate');
|
|
12
12
|
vi.mock('../../../lib/app/migrate_legacy');
|
|
13
|
+
vi.mock('../../../lib/projects/config.js');
|
|
13
14
|
const mockYargs = yargs;
|
|
14
15
|
const mockedGetAccountConfig = getAccountConfig;
|
|
15
16
|
const mockedMigrateApp2023_2 = migrateApp2023_2;
|
package/commands/getStarted.js
CHANGED
|
@@ -4,7 +4,7 @@ import open from 'open';
|
|
|
4
4
|
import { getCwd } from '@hubspot/local-dev-lib/path';
|
|
5
5
|
import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
|
|
6
6
|
import { commands } from '../lang/en.js';
|
|
7
|
-
import { trackCommandUsage } from '../lib/usageTracking.js';
|
|
7
|
+
import { trackCommandMetadataUsage, trackCommandUsage, } from '../lib/usageTracking.js';
|
|
8
8
|
import { EXIT_CODES } from '../lib/enums/exitCodes.js';
|
|
9
9
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
10
10
|
import { promptUser } from '../lib/prompts/promptUtils.js';
|
|
@@ -16,7 +16,8 @@ import { handleProjectUpload } from '../lib/projects/upload.js';
|
|
|
16
16
|
import { PROJECT_CONFIG_FILE, GET_STARTED_OPTIONS, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, } from '../lib/constants.js';
|
|
17
17
|
import { writeProjectConfig, getProjectConfig, validateProjectConfig, } from '../lib/projects/config.js';
|
|
18
18
|
import { getProjectPackageJsonLocations, installPackages, } from '../lib/dependencyManagement.js';
|
|
19
|
-
import { pollProjectBuildAndDeploy
|
|
19
|
+
import { pollProjectBuildAndDeploy } from '../lib/projects/pollProjectBuildAndDeploy.js';
|
|
20
|
+
import { useV3Api } from '../lib/projects/platformVersion.js';
|
|
20
21
|
import { openLink } from '../lib/links.js';
|
|
21
22
|
import { getStaticAuthAppInstallUrl } from '../lib/app/urls.js';
|
|
22
23
|
import { getEnv } from '@hubspot/local-dev-lib/config';
|
|
@@ -27,11 +28,11 @@ export const describe = undefined;
|
|
|
27
28
|
async function handler(args) {
|
|
28
29
|
const { derivedAccountId } = args;
|
|
29
30
|
const env = getEnv(derivedAccountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD;
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
trackCommandUsage('get-started', {}, derivedAccountId);
|
|
31
|
+
await trackCommandUsage('get-started', {}, derivedAccountId);
|
|
32
|
+
const accountName = uiAccountDescription(derivedAccountId);
|
|
33
33
|
uiInfoSection(commands.getStarted.startTitle, () => {
|
|
34
34
|
uiLogger.log(commands.getStarted.startDescription);
|
|
35
|
+
uiLogger.log(commands.getStarted.guideOverview(accountName));
|
|
35
36
|
});
|
|
36
37
|
const { default: selectedOption } = await promptUser([
|
|
37
38
|
{
|
|
@@ -51,6 +52,8 @@ async function handler(args) {
|
|
|
51
52
|
default: GET_STARTED_OPTIONS.APP,
|
|
52
53
|
},
|
|
53
54
|
]);
|
|
55
|
+
// Track user's initial choice
|
|
56
|
+
await trackCommandMetadataUsage('get-started', { step: 'select-option', type: selectedOption }, derivedAccountId);
|
|
54
57
|
if (selectedOption === GET_STARTED_OPTIONS.CMS) {
|
|
55
58
|
uiLogger.log(' ');
|
|
56
59
|
uiLogger.log(commands.getStarted.designManager);
|
|
@@ -63,6 +66,11 @@ async function handler(args) {
|
|
|
63
66
|
message: commands.getStarted.openDesignManagerPrompt,
|
|
64
67
|
},
|
|
65
68
|
]);
|
|
69
|
+
// Track Design Manager browser action
|
|
70
|
+
await trackCommandMetadataUsage('get-started', {
|
|
71
|
+
step: 'open-design-manager',
|
|
72
|
+
type: shouldOpen ? 'opened' : 'declined',
|
|
73
|
+
}, derivedAccountId);
|
|
66
74
|
if (shouldOpen) {
|
|
67
75
|
uiLogger.log('');
|
|
68
76
|
openLink(derivedAccountId, 'design-manager');
|
|
@@ -73,36 +81,37 @@ async function handler(args) {
|
|
|
73
81
|
else {
|
|
74
82
|
uiLogger.log(' ');
|
|
75
83
|
uiLogger.log(commands.getStarted.logs.appSelected);
|
|
76
|
-
// 1. Fetch project templates
|
|
77
|
-
let latestRepoReleaseTag;
|
|
78
84
|
const { dest, name } = await projectNameAndDestPrompt(args);
|
|
79
|
-
// Specific template for get-started command
|
|
80
|
-
const projectTemplate = {
|
|
81
|
-
name: 'private-app-get-started-template',
|
|
82
|
-
label: 'CRM getting started project with private apps',
|
|
83
|
-
path: 'projects/private-app-get-started-template',
|
|
84
|
-
};
|
|
85
|
-
// 3. Create the project files
|
|
86
85
|
const projectDest = path.resolve(getCwd(), dest);
|
|
87
86
|
const { projectConfig: existingProjectConfig, projectDir: existingProjectDir, } = await getProjectConfig(projectDest);
|
|
88
87
|
if (existingProjectConfig &&
|
|
89
88
|
existingProjectDir &&
|
|
90
89
|
projectDest.startsWith(existingProjectDir)) {
|
|
90
|
+
// Track nested project error
|
|
91
|
+
await trackCommandMetadataUsage('get-started', {
|
|
92
|
+
successful: false,
|
|
93
|
+
step: 'project-creation',
|
|
94
|
+
}, derivedAccountId);
|
|
91
95
|
uiLogger.log(' ');
|
|
92
96
|
uiLogger.error(commands.project.create.errors.cannotNestProjects(existingProjectDir));
|
|
93
97
|
process.exit(EXIT_CODES.ERROR);
|
|
94
98
|
}
|
|
95
|
-
const repo = templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
|
|
96
99
|
// 4. Clone the project template from GitHub
|
|
97
|
-
// This is temporary until we have the UA template in the main repo
|
|
98
100
|
try {
|
|
99
|
-
await cloneGithubRepo(
|
|
100
|
-
sourceDir:
|
|
101
|
-
tag: latestRepoReleaseTag,
|
|
101
|
+
await cloneGithubRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDest, {
|
|
102
|
+
sourceDir: '2025.2/private-app-get-started-template',
|
|
102
103
|
hideLogs: true,
|
|
103
104
|
});
|
|
105
|
+
await trackCommandMetadataUsage('get-started', {
|
|
106
|
+
successful: true,
|
|
107
|
+
step: 'github-clone',
|
|
108
|
+
}, derivedAccountId);
|
|
104
109
|
}
|
|
105
110
|
catch (err) {
|
|
111
|
+
await trackCommandMetadataUsage('get-started', {
|
|
112
|
+
successful: false,
|
|
113
|
+
step: 'github-clone',
|
|
114
|
+
}, derivedAccountId);
|
|
106
115
|
debugError(err);
|
|
107
116
|
uiLogger.log(' ');
|
|
108
117
|
uiLogger.error(commands.project.create.errors.failedToDownloadProject);
|
|
@@ -121,6 +130,11 @@ async function handler(args) {
|
|
|
121
130
|
uiLogger.log(' ');
|
|
122
131
|
uiLogger.log(commands.getStarted.prompts.projectCreated.description);
|
|
123
132
|
uiLogger.log(' ');
|
|
133
|
+
// Track successful project creation
|
|
134
|
+
await trackCommandMetadataUsage('get-started', {
|
|
135
|
+
successful: true,
|
|
136
|
+
step: 'project-creation',
|
|
137
|
+
}, derivedAccountId);
|
|
124
138
|
// 5. Install dependencies
|
|
125
139
|
const installLocations = await getProjectPackageJsonLocations(projectDest);
|
|
126
140
|
try {
|
|
@@ -138,7 +152,6 @@ async function handler(args) {
|
|
|
138
152
|
uiLogger.log(' ');
|
|
139
153
|
}
|
|
140
154
|
// 6. Ask user if they want to upload the project
|
|
141
|
-
const accountName = uiAccountDescription(derivedAccountId);
|
|
142
155
|
const { shouldUpload } = await promptUser([
|
|
143
156
|
{
|
|
144
157
|
type: 'confirm',
|
|
@@ -147,22 +160,31 @@ async function handler(args) {
|
|
|
147
160
|
default: true,
|
|
148
161
|
},
|
|
149
162
|
]);
|
|
163
|
+
// Track upload decision
|
|
164
|
+
await trackCommandMetadataUsage('get-started', {
|
|
165
|
+
step: 'upload-decision',
|
|
166
|
+
type: shouldUpload ? 'upload' : 'skip',
|
|
167
|
+
}, derivedAccountId);
|
|
150
168
|
if (shouldUpload) {
|
|
151
169
|
try {
|
|
152
170
|
// Get the project config for the newly created project
|
|
153
171
|
const { projectConfig: newProjectConfig, projectDir: newProjectDir } = await getProjectConfig(projectDest);
|
|
154
172
|
if (!newProjectConfig || !newProjectDir) {
|
|
173
|
+
// Track config file not found error
|
|
174
|
+
await trackCommandMetadataUsage('get-started', {
|
|
175
|
+
successful: false,
|
|
176
|
+
step: 'config-file-not-found',
|
|
177
|
+
}, derivedAccountId);
|
|
155
178
|
uiLogger.log(' ');
|
|
156
179
|
uiLogger.error(commands.getStarted.errors.configFileNotFound);
|
|
157
180
|
process.exit(EXIT_CODES.ERROR);
|
|
158
181
|
}
|
|
159
182
|
validateProjectConfig(newProjectConfig, newProjectDir);
|
|
160
|
-
const targetAccountId = derivedAccountId;
|
|
161
183
|
uiLogger.log(' ');
|
|
162
184
|
uiLogger.log(commands.getStarted.logs.uploadingProject);
|
|
163
185
|
uiLogger.log(' ');
|
|
164
186
|
const { result, uploadError } = await handleProjectUpload({
|
|
165
|
-
accountId:
|
|
187
|
+
accountId: derivedAccountId,
|
|
166
188
|
projectConfig: newProjectConfig,
|
|
167
189
|
projectDir: newProjectDir,
|
|
168
190
|
callbackFunc: pollProjectBuildAndDeploy,
|
|
@@ -173,11 +195,22 @@ async function handler(args) {
|
|
|
173
195
|
skipValidation: false,
|
|
174
196
|
});
|
|
175
197
|
if (uploadError) {
|
|
198
|
+
// Track upload failure
|
|
199
|
+
await trackCommandMetadataUsage('get-started', {
|
|
200
|
+
successful: false,
|
|
201
|
+
step: 'upload',
|
|
202
|
+
}, derivedAccountId);
|
|
176
203
|
uiLogger.log(' ');
|
|
177
204
|
uiLogger.error(commands.getStarted.errors.uploadFailed);
|
|
178
205
|
debugError(uploadError);
|
|
179
206
|
}
|
|
180
207
|
else if (result) {
|
|
208
|
+
// Track successful upload completion
|
|
209
|
+
await trackCommandMetadataUsage('get-started', {
|
|
210
|
+
successful: true,
|
|
211
|
+
step: 'upload',
|
|
212
|
+
}, derivedAccountId);
|
|
213
|
+
uiLogger.log(' ');
|
|
181
214
|
uiLogger.success(commands.getStarted.logs.uploadSuccess);
|
|
182
215
|
const { data: { results }, } = await fetchPublicAppsForPortal(derivedAccountId);
|
|
183
216
|
const lastCreatedApp = results.sort((a, b) => b.createdAt - a.createdAt)[0];
|
|
@@ -192,6 +225,11 @@ async function handler(args) {
|
|
|
192
225
|
message: commands.getStarted.openInstallUrl,
|
|
193
226
|
},
|
|
194
227
|
]);
|
|
228
|
+
// Track Developer Overview browser action
|
|
229
|
+
await trackCommandMetadataUsage('get-started', {
|
|
230
|
+
step: 'open-distribution-page',
|
|
231
|
+
type: shouldOpenOverview ? 'opened' : 'declined',
|
|
232
|
+
}, derivedAccountId);
|
|
195
233
|
if (shouldOpenOverview) {
|
|
196
234
|
open(getStaticAuthAppInstallUrl({
|
|
197
235
|
targetAccountId: derivedAccountId,
|
|
@@ -207,6 +245,11 @@ async function handler(args) {
|
|
|
207
245
|
}
|
|
208
246
|
}
|
|
209
247
|
catch (err) {
|
|
248
|
+
// Track upload exception
|
|
249
|
+
await trackCommandMetadataUsage('get-started', {
|
|
250
|
+
successful: false,
|
|
251
|
+
step: 'upload',
|
|
252
|
+
}, derivedAccountId);
|
|
210
253
|
uiLogger.log(' ');
|
|
211
254
|
uiLogger.error(commands.getStarted.errors.uploadFailed);
|
|
212
255
|
debugError(err);
|
|
@@ -214,6 +257,11 @@ async function handler(args) {
|
|
|
214
257
|
}
|
|
215
258
|
}
|
|
216
259
|
}
|
|
260
|
+
// Track successful completion of get-started command
|
|
261
|
+
await trackCommandMetadataUsage('get-started', {
|
|
262
|
+
successful: true,
|
|
263
|
+
step: 'command-completed',
|
|
264
|
+
}, derivedAccountId);
|
|
217
265
|
process.exit(EXIT_CODES.SUCCESS);
|
|
218
266
|
}
|
|
219
267
|
function getStartedBuilder(yargs) {
|
package/commands/mcp/setup.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { CommonArgs, YargsCommandModule } from '../../types/Yargs.js';
|
|
2
2
|
interface MCPSetupArgs extends CommonArgs {
|
|
3
3
|
client?: string[];
|
|
4
|
-
addDocsSearch?: boolean;
|
|
5
4
|
}
|
|
6
5
|
declare const mcpSetupCommand: YargsCommandModule<unknown, MCPSetupArgs>;
|
|
7
6
|
export default mcpSetupCommand;
|
package/commands/mcp/setup.js
CHANGED
|
@@ -2,7 +2,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
|
2
2
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
3
3
|
import { commands } from '../../lang/en.js';
|
|
4
4
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
5
|
-
import { addMcpServerToConfig,
|
|
5
|
+
import { addMcpServerToConfig, supportedTools } from '../../lib/mcp/setup.js';
|
|
6
6
|
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
7
7
|
const command = ['setup', 'update'];
|
|
8
8
|
const describe = undefined; // Leave hidden for now
|
|
@@ -16,10 +16,7 @@ async function handler(args) {
|
|
|
16
16
|
}
|
|
17
17
|
trackCommandUsage('mcp-setup', {}, args.derivedAccountId);
|
|
18
18
|
try {
|
|
19
|
-
|
|
20
|
-
if (args.addDocsSearch) {
|
|
21
|
-
await addMintlifyMcpServer(derivedTargets);
|
|
22
|
-
}
|
|
19
|
+
await addMcpServerToConfig(args.client);
|
|
23
20
|
}
|
|
24
21
|
catch (e) {
|
|
25
22
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -27,15 +24,10 @@ async function handler(args) {
|
|
|
27
24
|
process.exit(EXIT_CODES.SUCCESS);
|
|
28
25
|
}
|
|
29
26
|
function setupBuilder(yargs) {
|
|
30
|
-
yargs
|
|
31
|
-
.option('client', {
|
|
27
|
+
yargs.option('client', {
|
|
32
28
|
describe: commands.mcp.setup.args.client,
|
|
33
29
|
type: 'array',
|
|
34
30
|
choices: [...supportedTools.map(tool => tool.value)],
|
|
35
|
-
})
|
|
36
|
-
.option('add-docs-search', {
|
|
37
|
-
type: 'boolean',
|
|
38
|
-
hidden: true,
|
|
39
31
|
});
|
|
40
32
|
return yargs;
|
|
41
33
|
}
|
|
@@ -1,7 +1,22 @@
|
|
|
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';
|
|
5
|
+
import { legacyAddComponent } from '../../../lib/projects/add/legacyAddComponent.js';
|
|
6
|
+
import { getProjectConfig } from '../../../lib/projects/config.js';
|
|
7
|
+
import { useV3Api } from '../../../lib/projects/platformVersion.js';
|
|
8
|
+
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
4
9
|
vi.mock('../../../lib/commonOpts');
|
|
10
|
+
vi.mock('../../../lib/projects/add/v3AddComponent');
|
|
11
|
+
vi.mock('../../../lib/projects/add/legacyAddComponent');
|
|
12
|
+
vi.mock('../../../lib/projects/config');
|
|
13
|
+
vi.mock('../../../lib/projects/platformVersion');
|
|
14
|
+
vi.mock('../../../lib/usageTracking');
|
|
15
|
+
const mockedV3AddComponent = vi.mocked(v3AddComponent);
|
|
16
|
+
const mockedLegacyAddComponent = vi.mocked(legacyAddComponent);
|
|
17
|
+
const mockedGetProjectConfig = vi.mocked(getProjectConfig);
|
|
18
|
+
const mockedUseV3Api = vi.mocked(useV3Api);
|
|
19
|
+
const mockedTrackCommandUsage = vi.mocked(trackCommandUsage);
|
|
5
20
|
describe('commands/project/add', () => {
|
|
6
21
|
const yargsMock = yargs;
|
|
7
22
|
describe('command', () => {
|
|
@@ -40,4 +55,53 @@ describe('commands/project/add', () => {
|
|
|
40
55
|
});
|
|
41
56
|
});
|
|
42
57
|
});
|
|
58
|
+
describe('handler', () => {
|
|
59
|
+
const mockProjectConfig = {
|
|
60
|
+
name: 'test-project',
|
|
61
|
+
srcDir: 'src',
|
|
62
|
+
platformVersion: 'v3',
|
|
63
|
+
};
|
|
64
|
+
const mockProjectDir = '/path/to/project';
|
|
65
|
+
const mockArgs = {
|
|
66
|
+
derivedAccountId: 123,
|
|
67
|
+
name: 'test-component',
|
|
68
|
+
type: 'module',
|
|
69
|
+
};
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
mockedGetProjectConfig.mockResolvedValue({
|
|
72
|
+
projectConfig: mockProjectConfig,
|
|
73
|
+
projectDir: mockProjectDir,
|
|
74
|
+
});
|
|
75
|
+
mockedTrackCommandUsage.mockResolvedValue();
|
|
76
|
+
mockedV3AddComponent.mockResolvedValue();
|
|
77
|
+
mockedLegacyAddComponent.mockResolvedValue();
|
|
78
|
+
vi.spyOn(process, 'exit').mockImplementation(() => {
|
|
79
|
+
throw new Error('process.exit called');
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it('should call v3AddComponent with accountId for v3 projects', async () => {
|
|
83
|
+
mockedUseV3Api.mockReturnValue(true);
|
|
84
|
+
await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
|
|
85
|
+
expect(mockedV3AddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
|
|
86
|
+
expect(mockedLegacyAddComponent).not.toHaveBeenCalled();
|
|
87
|
+
});
|
|
88
|
+
it('should call legacyAddComponent for non-v3 projects', async () => {
|
|
89
|
+
mockedUseV3Api.mockReturnValue(false);
|
|
90
|
+
await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
|
|
91
|
+
expect(mockedLegacyAddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
|
|
92
|
+
expect(mockedV3AddComponent).not.toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
it('should exit with error when project config is not found', async () => {
|
|
95
|
+
mockedGetProjectConfig.mockResolvedValue({
|
|
96
|
+
projectConfig: null,
|
|
97
|
+
projectDir: null,
|
|
98
|
+
});
|
|
99
|
+
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
|
|
100
|
+
throw new Error('process.exit called');
|
|
101
|
+
});
|
|
102
|
+
await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
|
|
103
|
+
expect(mockExit).toHaveBeenCalledWith(1);
|
|
104
|
+
mockExit.mockRestore();
|
|
105
|
+
});
|
|
106
|
+
});
|
|
43
107
|
});
|
|
@@ -27,14 +27,71 @@ describe('commands/project/create', () => {
|
|
|
27
27
|
it('should define project creation options', () => {
|
|
28
28
|
const optionsSpy = vi.spyOn(yargsMock, 'options');
|
|
29
29
|
const exampleSpy = vi.spyOn(yargsMock, 'example');
|
|
30
|
+
const conflictsSpy = vi.spyOn(yargsMock, 'conflicts');
|
|
30
31
|
projectCreateCommand.builder(yargsMock);
|
|
31
32
|
expect(optionsSpy).toHaveBeenCalledWith(expect.objectContaining({
|
|
32
33
|
name: expect.any(Object),
|
|
33
34
|
dest: expect.any(Object),
|
|
34
35
|
template: expect.any(Object),
|
|
35
36
|
'template-source': expect.any(Object),
|
|
37
|
+
'platform-version': expect.any(Object),
|
|
38
|
+
'project-base': expect.any(Object),
|
|
39
|
+
distribution: expect.any(Object),
|
|
40
|
+
auth: expect.any(Object),
|
|
41
|
+
features: expect.any(Object),
|
|
36
42
|
}));
|
|
43
|
+
expect(conflictsSpy).toHaveBeenCalledWith('template', 'features');
|
|
37
44
|
expect(exampleSpy).toHaveBeenCalled();
|
|
38
45
|
});
|
|
46
|
+
it('should define platform version option with correct choices', () => {
|
|
47
|
+
const optionsSpy = vi.spyOn(yargsMock, 'options');
|
|
48
|
+
projectCreateCommand.builder(yargsMock);
|
|
49
|
+
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
50
|
+
expect(optionsCall['platform-version']).toEqual(expect.objectContaining({
|
|
51
|
+
hidden: true,
|
|
52
|
+
type: 'string',
|
|
53
|
+
choices: ['2023.2', '2025.1', '2025.2'],
|
|
54
|
+
default: '2023.2',
|
|
55
|
+
}));
|
|
56
|
+
});
|
|
57
|
+
it('should define project base option with correct choices', () => {
|
|
58
|
+
const optionsSpy = vi.spyOn(yargsMock, 'options');
|
|
59
|
+
projectCreateCommand.builder(yargsMock);
|
|
60
|
+
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
61
|
+
expect(optionsCall['project-base']).toEqual(expect.objectContaining({
|
|
62
|
+
hidden: true,
|
|
63
|
+
type: 'string',
|
|
64
|
+
choices: ['empty', 'app'],
|
|
65
|
+
}));
|
|
66
|
+
});
|
|
67
|
+
it('should define distribution option with correct choices', () => {
|
|
68
|
+
const optionsSpy = vi.spyOn(yargsMock, 'options');
|
|
69
|
+
projectCreateCommand.builder(yargsMock);
|
|
70
|
+
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
71
|
+
expect(optionsCall.distribution).toEqual(expect.objectContaining({
|
|
72
|
+
hidden: true,
|
|
73
|
+
type: 'string',
|
|
74
|
+
choices: ['private', 'marketplace'],
|
|
75
|
+
}));
|
|
76
|
+
});
|
|
77
|
+
it('should define auth option with correct choices', () => {
|
|
78
|
+
const optionsSpy = vi.spyOn(yargsMock, 'options');
|
|
79
|
+
projectCreateCommand.builder(yargsMock);
|
|
80
|
+
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
81
|
+
expect(optionsCall.auth).toEqual(expect.objectContaining({
|
|
82
|
+
hidden: true,
|
|
83
|
+
type: 'string',
|
|
84
|
+
choices: ['oauth', 'static'],
|
|
85
|
+
}));
|
|
86
|
+
});
|
|
87
|
+
it('should define features option as array', () => {
|
|
88
|
+
const optionsSpy = vi.spyOn(yargsMock, 'options');
|
|
89
|
+
projectCreateCommand.builder(yargsMock);
|
|
90
|
+
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
91
|
+
expect(optionsCall.features).toEqual(expect.objectContaining({
|
|
92
|
+
hidden: true,
|
|
93
|
+
type: 'array',
|
|
94
|
+
}));
|
|
95
|
+
});
|
|
39
96
|
});
|
|
40
97
|
});
|
|
@@ -8,7 +8,7 @@ import * as ui from '../../../lib/ui/index.js';
|
|
|
8
8
|
import { addAccountOptions, addConfigOptions, addJSONOutputOptions, addUseEnvironmentOptions, } from '../../../lib/commonOpts.js';
|
|
9
9
|
import * as projectUtils from '../../../lib/projects/config.js';
|
|
10
10
|
import * as projectUrlUtils from '../../../lib/projects/urls.js';
|
|
11
|
-
import { pollDeployStatus } from '../../../lib/projects/
|
|
11
|
+
import { pollDeployStatus } from '../../../lib/projects/pollProjectBuildAndDeploy.js';
|
|
12
12
|
import * as projectNamePrompt from '../../../lib/prompts/projectNamePrompt.js';
|
|
13
13
|
import * as promptUtils from '../../../lib/prompts/promptUtils.js';
|
|
14
14
|
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
@@ -23,7 +23,8 @@ vi.mock('../../../lib/commonOpts');
|
|
|
23
23
|
vi.mock('../../../lib/validation');
|
|
24
24
|
vi.mock('../../../lib/projects/config');
|
|
25
25
|
vi.mock('../../../lib/projects/urls');
|
|
26
|
-
vi.mock('../../../lib/projects/
|
|
26
|
+
vi.mock('../../../lib/projects/pollProjectBuildAndDeploy');
|
|
27
|
+
vi.mock('../../../lib/projects/platformVersion');
|
|
27
28
|
vi.mock('../../../lib/prompts/projectNamePrompt');
|
|
28
29
|
vi.mock('../../../lib/prompts/promptUtils');
|
|
29
30
|
vi.mock('../../../lib/usageTracking');
|
|
@@ -380,17 +380,26 @@ describe('unifiedProjectDevFlow', () => {
|
|
|
380
380
|
beforeEach(() => {
|
|
381
381
|
isTestAccountOrSandbox.mockReturnValue(false);
|
|
382
382
|
});
|
|
383
|
-
it('should
|
|
384
|
-
|
|
383
|
+
it('should log info message when default account is a sandbox or test account', async () => {
|
|
384
|
+
isTestAccountOrSandbox.mockReturnValue(true);
|
|
385
|
+
await unifiedProjectDevFlow({
|
|
386
|
+
args: mockArgs,
|
|
387
|
+
targetProjectAccountId: mockTargetProjectAccountId,
|
|
388
|
+
projectConfig: mockProjectConfig,
|
|
389
|
+
projectDir: mockProjectDir,
|
|
390
|
+
});
|
|
391
|
+
expect(uiLogger.log).toHaveBeenCalledWith(commands.project.dev.logs.defaultSandboxOrDevTestTestingAccountExplanation(mockTargetProjectAccountId));
|
|
392
|
+
});
|
|
393
|
+
it('should log info message when testingAccount flag is provided', async () => {
|
|
394
|
+
const providedTestingAccountId = 999;
|
|
385
395
|
await unifiedProjectDevFlow({
|
|
386
396
|
args: mockArgs,
|
|
387
397
|
targetProjectAccountId: mockTargetProjectAccountId,
|
|
398
|
+
providedTargetTestingAccountId: providedTestingAccountId,
|
|
388
399
|
projectConfig: mockProjectConfig,
|
|
389
400
|
projectDir: mockProjectDir,
|
|
390
401
|
});
|
|
391
|
-
expect(
|
|
392
|
-
expect(uiLogger.log).toHaveBeenCalledWith(commands.project.dev.logs.accountTypeInformation);
|
|
393
|
-
expect(uiLogger.log).toHaveBeenCalledWith(commands.project.dev.logs.learnMoreMessage);
|
|
402
|
+
expect(uiLogger.log).toHaveBeenCalledWith(commands.project.dev.logs.testingAccountFlagExplanation(providedTestingAccountId));
|
|
394
403
|
});
|
|
395
404
|
});
|
|
396
405
|
});
|
package/commands/project/add.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
2
|
-
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
3
2
|
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
4
3
|
import { uiBetaTag } from '../../lib/ui/index.js';
|
|
5
4
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
6
5
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
7
6
|
import { commands } from '../../lang/en.js';
|
|
8
|
-
import { useV3Api } from '../../lib/projects/
|
|
7
|
+
import { useV3Api } from '../../lib/projects/platformVersion.js';
|
|
9
8
|
import { legacyAddComponent } from '../../lib/projects/add/legacyAddComponent.js';
|
|
10
9
|
import { v3AddComponent } from '../../lib/projects/add/v3AddComponent.js';
|
|
11
10
|
import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../lib/constants.js';
|
|
@@ -15,7 +14,6 @@ const describe = uiBetaTag(commands.project.add.describe, false);
|
|
|
15
14
|
async function handler(args) {
|
|
16
15
|
try {
|
|
17
16
|
const { derivedAccountId } = args;
|
|
18
|
-
trackCommandUsage('project-add', undefined, derivedAccountId);
|
|
19
17
|
const { projectConfig, projectDir } = await getProjectConfig();
|
|
20
18
|
if (!projectDir || !projectConfig) {
|
|
21
19
|
uiLogger.error(commands.project.add.error.locationInProject);
|
|
@@ -23,10 +21,10 @@ async function handler(args) {
|
|
|
23
21
|
}
|
|
24
22
|
const isV3ProjectCreate = useV3Api(projectConfig.platformVersion);
|
|
25
23
|
if (isV3ProjectCreate) {
|
|
26
|
-
await v3AddComponent(args, projectDir, projectConfig);
|
|
24
|
+
await v3AddComponent(args, projectDir, projectConfig, derivedAccountId);
|
|
27
25
|
}
|
|
28
26
|
else {
|
|
29
|
-
await legacyAddComponent(args, projectDir, projectConfig);
|
|
27
|
+
await legacyAddComponent(args, projectDir, projectConfig, derivedAccountId);
|
|
30
28
|
}
|
|
31
29
|
}
|
|
32
30
|
catch (e) {
|
|
@@ -16,6 +16,8 @@ import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
|
|
|
16
16
|
import { commands } from '../../lang/en.js';
|
|
17
17
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
18
18
|
import { handleProjectCreationFlow, } from '../../lib/projects/create/index.js';
|
|
19
|
+
import { getProjectMetadata, } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
20
|
+
import { updateHsMetaFilesWithAutoGeneratedFields } from '../../lib/projects/components.js';
|
|
19
21
|
const command = ['create', 'init'];
|
|
20
22
|
const describe = uiBetaTag(commands.project.create.describe, false);
|
|
21
23
|
const { v2023_2, v2025_1, v2025_2 } = PLATFORM_VERSIONS;
|
|
@@ -39,7 +41,7 @@ async function handler(args) {
|
|
|
39
41
|
type: selectProjectTemplatePromptResponse.projectTemplate?.name ||
|
|
40
42
|
(selectProjectTemplatePromptResponse.componentTemplates || [])
|
|
41
43
|
// @ts-expect-error
|
|
42
|
-
.map((item) => item.
|
|
44
|
+
.map((item) => item.type)
|
|
43
45
|
.join(','),
|
|
44
46
|
}, derivedAccountId);
|
|
45
47
|
const projectDest = path.resolve(getCwd(), projectNameAndDestPromptResponse.dest);
|
|
@@ -73,10 +75,13 @@ async function handler(args) {
|
|
|
73
75
|
}
|
|
74
76
|
const projectConfigPath = path.join(projectDest, PROJECT_CONFIG_FILE);
|
|
75
77
|
const parsedConfigFile = JSON.parse(fs.readFileSync(projectConfigPath).toString());
|
|
78
|
+
const projectName = projectNameAndDestPromptResponse.name;
|
|
76
79
|
writeProjectConfig(projectConfigPath, {
|
|
77
80
|
...parsedConfigFile,
|
|
78
|
-
name:
|
|
81
|
+
name: projectName,
|
|
79
82
|
});
|
|
83
|
+
const projectMetadata = await getProjectMetadata(path.join(projectDest, parsedConfigFile.srcDir));
|
|
84
|
+
updateHsMetaFilesWithAutoGeneratedFields(projectName, projectMetadata.hsMetaFiles);
|
|
80
85
|
// If the template is 'no-template', we need to manually create a src directory
|
|
81
86
|
if (selectProjectTemplatePromptResponse.projectTemplate?.name ===
|
|
82
87
|
EMPTY_PROJECT_TEMPLATE_NAME ||
|