@hubspot/cli 8.0.2-experimental.0 → 8.0.3-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.
- package/commands/__tests__/getStarted.test.js +2 -2
- package/commands/__tests__/project.test.js +30 -0
- package/commands/account/auth.js +8 -97
- package/commands/account/use.js +19 -4
- package/commands/cms/module/marketplace-validate.js +23 -5
- package/commands/cms/theme/marketplace-validate.js +25 -6
- package/commands/mcp/setup.js +1 -2
- package/commands/mcp.js +1 -2
- package/commands/project.js +22 -1
- package/lang/en.d.ts +22 -1
- package/lang/en.js +26 -5
- package/lib/__tests__/accountAuth.test.d.ts +1 -0
- package/lib/__tests__/accountAuth.test.js +258 -0
- package/lib/accountAuth.d.ts +10 -0
- package/lib/accountAuth.js +105 -0
- package/lib/app/urls.d.ts +1 -0
- package/lib/app/urls.js +4 -0
- package/lib/errors/ProjectErrors.d.ts +15 -0
- package/lib/errors/ProjectErrors.js +30 -0
- package/lib/getStarted/getStartedV2.js +3 -41
- package/lib/getStartedV2Actions.d.ts +29 -0
- package/lib/getStartedV2Actions.js +104 -9
- package/lib/marketplaceValidate.d.ts +1 -1
- package/lib/marketplaceValidate.js +23 -41
- package/lib/projects/ProjectLogsManager.d.ts +12 -3
- package/lib/projects/ProjectLogsManager.js +70 -12
- package/lib/projects/__tests__/ProjectLogsManager.test.js +131 -18
- package/lib/projects/__tests__/platformVersion.test.js +37 -1
- package/lib/projects/__tests__/projects.test.js +6 -2
- package/lib/projects/components.d.ts +6 -0
- package/lib/projects/components.js +1 -1
- package/lib/projects/config.js +9 -2
- package/lib/projects/localDev/helpers/project.d.ts +4 -1
- package/lib/projects/localDev/helpers/project.js +13 -8
- package/lib/projects/platformVersion.d.ts +8 -0
- package/lib/projects/platformVersion.js +31 -2
- package/lib/prompts/accountsPrompt.d.ts +2 -1
- package/lib/prompts/accountsPrompt.js +10 -2
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +20 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +6 -10
- package/mcp-server/tools/project/CreateProjectTool.d.ts +24 -4
- package/mcp-server/tools/project/CreateProjectTool.js +5 -10
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +5 -8
- package/mcp-server/tools/project/GetBuildLogsTool.d.ts +2 -2
- package/mcp-server/tools/project/GetBuildLogsTool.js +3 -4
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +1 -1
- package/mcp-server/tools/project/GetBuildStatusTool.js +3 -4
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +6 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -6
- package/mcp-server/tools/project/constants.d.ts +12 -1
- package/mcp-server/tools/project/constants.js +12 -16
- package/package.json +2 -2
- package/ui/components/ActionSection.d.ts +1 -1
- package/ui/components/BoxWithTitle.js +1 -1
- package/ui/components/getStarted/GetStartedFlow.d.ts +8 -0
- package/ui/components/getStarted/GetStartedFlow.js +136 -0
- package/ui/components/getStarted/reducer.d.ts +59 -0
- package/ui/components/getStarted/reducer.js +72 -0
- package/ui/components/getStarted/screens/ProjectSetupScreen.d.ts +16 -0
- package/ui/components/getStarted/screens/ProjectSetupScreen.js +39 -0
- package/ui/components/getStarted/screens/UploadScreen.d.ts +7 -0
- package/ui/components/getStarted/screens/UploadScreen.js +43 -0
- package/ui/components/getStarted/selectors.d.ts +2 -0
- package/ui/components/getStarted/selectors.js +1 -0
- package/ui/lib/constants.d.ts +16 -0
- package/ui/lib/constants.js +16 -0
- package/ui/render.js +6 -0
- package/ui/components/GetStartedFlow.d.ts +0 -24
- package/ui/components/GetStartedFlow.js +0 -128
|
@@ -10,7 +10,7 @@ import { GET_STARTED_OPTIONS } from '../../lib/constants.js';
|
|
|
10
10
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
11
11
|
import open from 'open';
|
|
12
12
|
import { renderInteractive } from '../../ui/render.js';
|
|
13
|
-
import { getGetStartedFlow } from '../../ui/components/GetStartedFlow.js';
|
|
13
|
+
import { getGetStartedFlow } from '../../ui/components/getStarted/GetStartedFlow.js';
|
|
14
14
|
vi.mock('../../lib/prompts/promptUtils');
|
|
15
15
|
vi.mock('../../lib/prompts/projectNameAndDestPrompt');
|
|
16
16
|
vi.mock('../../lib/projects/config');
|
|
@@ -19,7 +19,7 @@ vi.mock('@hubspot/local-dev-lib/github');
|
|
|
19
19
|
vi.mock('../../lib/dependencyManagement');
|
|
20
20
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
21
21
|
vi.mock('../../ui/render');
|
|
22
|
-
vi.mock('../../ui/components/GetStartedFlow');
|
|
22
|
+
vi.mock('../../ui/components/getStarted/GetStartedFlow');
|
|
23
23
|
vi.mock('open');
|
|
24
24
|
vi.mock('fs-extra', () => ({
|
|
25
25
|
default: {
|
|
@@ -17,6 +17,9 @@ import validate from '../project/validate.js';
|
|
|
17
17
|
import profileCommands from '../project/profile.js';
|
|
18
18
|
import list from '../project/list.js';
|
|
19
19
|
import projectCommand from '../project.js';
|
|
20
|
+
import * as projectConfigLib from '../../lib/projects/config.js';
|
|
21
|
+
import * as platformVersionLib from '../../lib/projects/platformVersion.js';
|
|
22
|
+
import { uiLogger } from '../../lib/ui/logger.js';
|
|
20
23
|
vi.mock('../project/deploy');
|
|
21
24
|
vi.mock('../project/create');
|
|
22
25
|
vi.mock('../project/upload');
|
|
@@ -40,13 +43,24 @@ vi.mock('../project/installDeps');
|
|
|
40
43
|
vi.mock('../project/lint');
|
|
41
44
|
vi.mock('../project/profile');
|
|
42
45
|
vi.mock('../../lib/commonOpts');
|
|
46
|
+
vi.mock('../../lib/projects/config.js');
|
|
47
|
+
vi.mock('../../lib/projects/platformVersion.js');
|
|
43
48
|
const commandSpy = vi
|
|
44
49
|
.spyOn(yargs, 'command')
|
|
45
50
|
.mockReturnValue(yargs);
|
|
46
51
|
const demandCommandSpy = vi
|
|
47
52
|
.spyOn(yargs, 'demandCommand')
|
|
48
53
|
.mockReturnValue(yargs);
|
|
54
|
+
const getProjectConfigSpy = vi.spyOn(projectConfigLib, 'getProjectConfig');
|
|
55
|
+
const isUnsupportedPlatformVersionSpy = vi.spyOn(platformVersionLib, 'isUnsupportedPlatformVersion');
|
|
56
|
+
const processExitSpy = vi.spyOn(process, 'exit');
|
|
57
|
+
const uiLoggerErrorSpy = vi.spyOn(uiLogger, 'error');
|
|
49
58
|
describe('commands/project', () => {
|
|
59
|
+
beforeEach(() => {
|
|
60
|
+
vi.clearAllMocks();
|
|
61
|
+
// @ts-expect-error Mock implementation
|
|
62
|
+
processExitSpy.mockImplementation(() => { });
|
|
63
|
+
});
|
|
50
64
|
describe('command', () => {
|
|
51
65
|
it('should have the correct command structure', () => {
|
|
52
66
|
expect(projectCommand.command).toEqual(['project', 'projects']);
|
|
@@ -92,4 +106,20 @@ describe('commands/project', () => {
|
|
|
92
106
|
expect(commandSpy).toHaveBeenCalledWith(module);
|
|
93
107
|
});
|
|
94
108
|
});
|
|
109
|
+
describe('middleware - validatePlatformVersion', () => {
|
|
110
|
+
it('should have platform version validation functions available', () => {
|
|
111
|
+
// Verify the necessary functions are available for middleware
|
|
112
|
+
expect(getProjectConfigSpy).toBeDefined();
|
|
113
|
+
expect(isUnsupportedPlatformVersionSpy).toBeDefined();
|
|
114
|
+
expect(uiLoggerErrorSpy).toBeDefined();
|
|
115
|
+
expect(processExitSpy).toBeDefined();
|
|
116
|
+
});
|
|
117
|
+
it('should register middleware when building', async () => {
|
|
118
|
+
// Verify middleware is registered during builder execution
|
|
119
|
+
await projectCommand.builder(yargs);
|
|
120
|
+
// The middleware should be registered (we can't easily test async middleware execution)
|
|
121
|
+
// but we verify the builder completes successfully
|
|
122
|
+
expect(projectCommand.builder).toBeDefined();
|
|
123
|
+
});
|
|
124
|
+
});
|
|
95
125
|
});
|
package/commands/account/auth.js
CHANGED
|
@@ -1,96 +1,21 @@
|
|
|
1
|
-
import { updateConfigAccount, createEmptyConfigFile, deleteConfigFileIfEmpty, getConfigFilePath, localConfigFileExists, globalConfigFileExists, } from '@hubspot/local-dev-lib/config';
|
|
2
|
-
import { getAccessToken, updateConfigWithAccessToken, } from '@hubspot/local-dev-lib/personalAccessKey';
|
|
3
1
|
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
4
|
-
import { toKebabCase } from '@hubspot/local-dev-lib/text';
|
|
5
2
|
import { PERSONAL_ACCESS_KEY_AUTH_METHOD } from '@hubspot/local-dev-lib/constants/auth';
|
|
6
|
-
import {
|
|
3
|
+
import { deleteConfigFileIfEmpty } from '@hubspot/local-dev-lib/config';
|
|
7
4
|
import { handleExit } from '../../lib/process.js';
|
|
8
|
-
import { debugError } from '../../lib/errorHandlers/index.js';
|
|
9
5
|
import { trackCommandUsage, trackAuthAction } from '../../lib/usageTracking.js';
|
|
10
|
-
import { personalAccessKeyPrompt } from '../../lib/prompts/personalAccessKeyPrompt.js';
|
|
11
|
-
import { cliAccountNamePrompt } from '../../lib/prompts/accountNamePrompt.js';
|
|
12
|
-
import { setAsDefaultAccountPrompt } from '../../lib/prompts/setAsDefaultAccountPrompt.js';
|
|
13
|
-
import { logError } from '../../lib/errorHandlers/index.js';
|
|
14
6
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
15
7
|
import { uiFeatureHighlight } from '../../lib/ui/index.js';
|
|
16
8
|
import { parseStringToNumber } from '../../lib/parsing.js';
|
|
17
9
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
18
10
|
import { commands } from '../../lang/en.js';
|
|
19
11
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
12
|
+
import { authenticateNewAccount } from '../../lib/accountAuth.js';
|
|
20
13
|
const TRACKING_STATUS = {
|
|
21
14
|
STARTED: 'started',
|
|
22
15
|
ERROR: 'error',
|
|
23
16
|
COMPLETE: 'complete',
|
|
24
17
|
};
|
|
25
18
|
const authType = PERSONAL_ACCESS_KEY_AUTH_METHOD.value;
|
|
26
|
-
async function updateConfigWithNewAccount(env, configAlreadyExists, providedPersonalAccessKey, accountId) {
|
|
27
|
-
try {
|
|
28
|
-
const { personalAccessKey } = providedPersonalAccessKey
|
|
29
|
-
? { personalAccessKey: providedPersonalAccessKey }
|
|
30
|
-
: await personalAccessKeyPrompt({
|
|
31
|
-
env,
|
|
32
|
-
account: accountId,
|
|
33
|
-
});
|
|
34
|
-
const token = await getAccessToken(personalAccessKey, env);
|
|
35
|
-
const defaultAccountName = token.hubName
|
|
36
|
-
? toKebabCase(token.hubName)
|
|
37
|
-
: undefined;
|
|
38
|
-
const accountName = configAlreadyExists
|
|
39
|
-
? undefined
|
|
40
|
-
: (await cliAccountNamePrompt(defaultAccountName)).name;
|
|
41
|
-
const updatedConfig = await updateConfigWithAccessToken(token, personalAccessKey, env, accountName, !configAlreadyExists);
|
|
42
|
-
if (!updatedConfig)
|
|
43
|
-
return null;
|
|
44
|
-
// Can happen if the user is re-authenticating an account with no name
|
|
45
|
-
if (configAlreadyExists && !updatedConfig.name) {
|
|
46
|
-
updatedConfig.name = (await cliAccountNamePrompt(defaultAccountName)).name;
|
|
47
|
-
updateConfigAccount({
|
|
48
|
-
...updatedConfig,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
return updatedConfig;
|
|
52
|
-
}
|
|
53
|
-
catch (e) {
|
|
54
|
-
debugError(e);
|
|
55
|
-
return null;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
async function handleConfigMigration() {
|
|
59
|
-
const deprecatedConfigExists = localConfigFileExists();
|
|
60
|
-
const globalConfigExists = globalConfigFileExists();
|
|
61
|
-
// No deprecated config exists, so no migration is needed
|
|
62
|
-
if (!deprecatedConfigExists) {
|
|
63
|
-
return true;
|
|
64
|
-
}
|
|
65
|
-
// Global config exists, so we need to merge the deprecated config with the global config
|
|
66
|
-
if (globalConfigExists) {
|
|
67
|
-
try {
|
|
68
|
-
const mergeConfirmed = await handleMerge();
|
|
69
|
-
if (!mergeConfirmed) {
|
|
70
|
-
uiLogger.log('');
|
|
71
|
-
uiLogger.log(commands.account.subcommands.auth.errors.mergeNotConfirmed);
|
|
72
|
-
}
|
|
73
|
-
return mergeConfirmed;
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
logError(error);
|
|
77
|
-
return false;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// Global config does not exist, so we only need to migrate the deprecated config
|
|
81
|
-
try {
|
|
82
|
-
const migrationConfirmed = await handleMigration();
|
|
83
|
-
if (!migrationConfirmed) {
|
|
84
|
-
uiLogger.log('');
|
|
85
|
-
uiLogger.log(commands.account.subcommands.auth.errors.migrationNotConfirmed);
|
|
86
|
-
}
|
|
87
|
-
return migrationConfirmed;
|
|
88
|
-
}
|
|
89
|
-
catch (error) {
|
|
90
|
-
logError(error);
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
19
|
const describe = commands.account.subcommands.auth.describe;
|
|
95
20
|
const command = 'auth';
|
|
96
21
|
async function handler(args) {
|
|
@@ -109,33 +34,19 @@ async function handler(args) {
|
|
|
109
34
|
trackCommandUsage('account-auth', {}, parsedUserProvidedAccountId);
|
|
110
35
|
await trackAuthAction('account-auth', authType, TRACKING_STATUS.STARTED);
|
|
111
36
|
}
|
|
112
|
-
const configMigrationSuccess = await handleConfigMigration();
|
|
113
|
-
if (!configMigrationSuccess) {
|
|
114
|
-
await trackAuthAction('account-auth', authType, TRACKING_STATUS.ERROR);
|
|
115
|
-
process.exit(EXIT_CODES.ERROR);
|
|
116
|
-
}
|
|
117
|
-
const configAlreadyExists = globalConfigFileExists();
|
|
118
|
-
if (!configAlreadyExists) {
|
|
119
|
-
createEmptyConfigFile(true);
|
|
120
|
-
}
|
|
121
37
|
handleExit(deleteConfigFileIfEmpty);
|
|
122
|
-
const updatedConfig = await
|
|
38
|
+
const updatedConfig = await authenticateNewAccount({
|
|
39
|
+
env: args.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD,
|
|
40
|
+
providedPersonalAccessKey,
|
|
41
|
+
accountId: parsedUserProvidedAccountId,
|
|
42
|
+
});
|
|
123
43
|
if (!updatedConfig) {
|
|
124
44
|
if (!disableTracking) {
|
|
125
45
|
await trackAuthAction('account-auth', authType, TRACKING_STATUS.ERROR);
|
|
126
46
|
}
|
|
127
|
-
uiLogger.error(commands.account.subcommands.auth.errors.failedToUpdateConfig);
|
|
128
47
|
return process.exit(EXIT_CODES.ERROR);
|
|
129
48
|
}
|
|
130
|
-
const { accountId
|
|
131
|
-
if (!configAlreadyExists) {
|
|
132
|
-
uiLogger.log('');
|
|
133
|
-
uiLogger.success(commands.account.subcommands.auth.success.configFileCreated(getConfigFilePath()));
|
|
134
|
-
uiLogger.success(commands.account.subcommands.auth.success.configFileUpdated(accountId));
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
await setAsDefaultAccountPrompt(name);
|
|
138
|
-
}
|
|
49
|
+
const { accountId } = updatedConfig;
|
|
139
50
|
uiFeatureHighlight([
|
|
140
51
|
'getStartedCommand',
|
|
141
52
|
'helpCommand',
|
package/commands/account/use.js
CHANGED
|
@@ -1,24 +1,39 @@
|
|
|
1
|
-
import { getConfigFilePath, setConfigAccountAsDefault, getConfigAccountIfExists, getConfigAccountByName, getConfigAccountById, getAllConfigAccounts, } from '@hubspot/local-dev-lib/config';
|
|
1
|
+
import { getConfigFilePath, setConfigAccountAsDefault, getConfigAccountIfExists, getConfigAccountByName, getConfigAccountById, globalConfigFileExists, getAllConfigAccounts, } from '@hubspot/local-dev-lib/config';
|
|
2
2
|
import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
|
|
3
|
+
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
3
4
|
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
4
5
|
import { commands } from '../../lang/en.js';
|
|
5
6
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
6
|
-
import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt.js';
|
|
7
|
+
import { selectAccountFromConfig, AUTHENTICATE_NEW_ACCOUNT_VALUE, } from '../../lib/prompts/accountsPrompt.js';
|
|
7
8
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
9
|
+
import { authenticateNewAccount } from '../../lib/accountAuth.js';
|
|
10
|
+
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
8
11
|
const command = 'use [account]';
|
|
9
12
|
const describe = commands.account.subcommands.use.describe;
|
|
10
13
|
async function handler(args) {
|
|
11
14
|
let newDefaultAccount = args.account;
|
|
15
|
+
const usingGlobalConfig = globalConfigFileExists();
|
|
12
16
|
if (!newDefaultAccount) {
|
|
13
|
-
newDefaultAccount = await selectAccountFromConfig();
|
|
17
|
+
newDefaultAccount = await selectAccountFromConfig('', usingGlobalConfig);
|
|
14
18
|
}
|
|
15
19
|
else {
|
|
16
20
|
const account = getConfigAccountIfExists(newDefaultAccount);
|
|
17
21
|
if (!account) {
|
|
18
22
|
uiLogger.error(commands.account.subcommands.use.errors.accountNotFound(newDefaultAccount, getConfigFilePath()));
|
|
19
|
-
newDefaultAccount = await selectAccountFromConfig();
|
|
23
|
+
newDefaultAccount = await selectAccountFromConfig('', usingGlobalConfig);
|
|
20
24
|
}
|
|
21
25
|
}
|
|
26
|
+
if (newDefaultAccount === AUTHENTICATE_NEW_ACCOUNT_VALUE) {
|
|
27
|
+
const updatedConfig = await authenticateNewAccount({
|
|
28
|
+
env: args.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD,
|
|
29
|
+
setAsDefaultAccount: true,
|
|
30
|
+
});
|
|
31
|
+
if (!updatedConfig) {
|
|
32
|
+
process.exit(EXIT_CODES.ERROR);
|
|
33
|
+
}
|
|
34
|
+
trackCommandUsage('accounts-use', undefined, updatedConfig.accountId);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
22
37
|
let account;
|
|
23
38
|
if (!isNaN(Number(newDefaultAccount))) {
|
|
24
39
|
account = getConfigAccountById(Number(newDefaultAccount));
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import SpinniesManager from '../../../lib/ui/SpinniesManager.js';
|
|
2
2
|
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
3
|
-
import { kickOffValidation, pollForValidationFinish, fetchValidationResults,
|
|
3
|
+
import { kickOffValidation, pollForValidationFinish, fetchValidationResults, hasProcessValidationErrors, displayValidationResults, } from '../../../lib/marketplaceValidate.js';
|
|
4
4
|
import { commands } from '../../../lang/en.js';
|
|
5
5
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
6
6
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
7
|
+
import { logError } from '../../../lib/errorHandlers/index.js';
|
|
7
8
|
const command = 'marketplace-validate <src>';
|
|
8
9
|
const describe = commands.cms.subcommands.module.subcommands.marketplaceValidate.describe;
|
|
9
10
|
async function handler(args) {
|
|
@@ -13,12 +14,29 @@ async function handler(args) {
|
|
|
13
14
|
text: commands.cms.subcommands.module.subcommands.marketplaceValidate.logs.validatingModule(src),
|
|
14
15
|
});
|
|
15
16
|
const assetType = 'MODULE';
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
let validationId;
|
|
18
|
+
try {
|
|
19
|
+
validationId = await kickOffValidation(derivedAccountId, assetType, src);
|
|
20
|
+
await pollForValidationFinish(derivedAccountId, validationId);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
logError(e);
|
|
24
|
+
process.exit(EXIT_CODES.ERROR);
|
|
25
|
+
}
|
|
18
26
|
SpinniesManager.remove('marketplaceValidation');
|
|
19
|
-
|
|
20
|
-
|
|
27
|
+
let validationResults;
|
|
28
|
+
try {
|
|
29
|
+
validationResults = await fetchValidationResults(derivedAccountId, validationId);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
logError(e);
|
|
33
|
+
process.exit(EXIT_CODES.ERROR);
|
|
34
|
+
}
|
|
35
|
+
const hasErrors = hasProcessValidationErrors(commands.cms.subcommands.module.subcommands.marketplaceValidate.errors
|
|
21
36
|
.invalidPath, validationResults);
|
|
37
|
+
if (hasErrors) {
|
|
38
|
+
process.exit(EXIT_CODES.ERROR);
|
|
39
|
+
}
|
|
22
40
|
displayValidationResults(commands.cms.subcommands.module.subcommands.marketplaceValidate.results, validationResults);
|
|
23
41
|
process.exit(EXIT_CODES.SUCCESS);
|
|
24
42
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import SpinniesManager from '../../../lib/ui/SpinniesManager.js';
|
|
2
2
|
import { trackCommandUsage } from '../../../lib/usageTracking.js';
|
|
3
|
-
import { kickOffValidation, pollForValidationFinish, fetchValidationResults,
|
|
3
|
+
import { kickOffValidation, pollForValidationFinish, fetchValidationResults, hasProcessValidationErrors, displayValidationResults, } from '../../../lib/marketplaceValidate.js';
|
|
4
4
|
import { commands } from '../../../lang/en.js';
|
|
5
5
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
6
|
+
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
7
|
+
import { logError } from '../../../lib/errorHandlers/index.js';
|
|
6
8
|
const command = 'marketplace-validate <path>';
|
|
7
9
|
const describe = commands.cms.subcommands.theme.subcommands.marketplaceValidate.describe;
|
|
8
10
|
async function handler(args) {
|
|
@@ -12,14 +14,31 @@ async function handler(args) {
|
|
|
12
14
|
text: commands.cms.subcommands.theme.subcommands.marketplaceValidate.logs.validatingTheme(path),
|
|
13
15
|
});
|
|
14
16
|
const assetType = 'THEME';
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
let validationId;
|
|
18
|
+
try {
|
|
19
|
+
validationId = await kickOffValidation(derivedAccountId, assetType, path);
|
|
20
|
+
await pollForValidationFinish(derivedAccountId, validationId);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
logError(e);
|
|
24
|
+
process.exit(EXIT_CODES.ERROR);
|
|
25
|
+
}
|
|
17
26
|
SpinniesManager.remove('marketplaceValidation');
|
|
18
|
-
|
|
19
|
-
|
|
27
|
+
let validationResults;
|
|
28
|
+
try {
|
|
29
|
+
validationResults = await fetchValidationResults(derivedAccountId, validationId);
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
logError(e);
|
|
33
|
+
process.exit(EXIT_CODES.ERROR);
|
|
34
|
+
}
|
|
35
|
+
const hasErrors = hasProcessValidationErrors(commands.cms.subcommands.theme.subcommands.marketplaceValidate.errors
|
|
20
36
|
.invalidPath, validationResults);
|
|
37
|
+
if (hasErrors) {
|
|
38
|
+
process.exit(EXIT_CODES.ERROR);
|
|
39
|
+
}
|
|
21
40
|
displayValidationResults(commands.cms.subcommands.theme.subcommands.marketplaceValidate.results, validationResults);
|
|
22
|
-
process.exit();
|
|
41
|
+
process.exit(EXIT_CODES.SUCCESS);
|
|
23
42
|
}
|
|
24
43
|
function themeValidateBuilder(yargs) {
|
|
25
44
|
yargs.positional('path', {
|
package/commands/mcp/setup.js
CHANGED
|
@@ -6,9 +6,8 @@ import { addMcpServerToConfig, supportedTools } from '../../lib/mcp/setup.js';
|
|
|
6
6
|
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
7
7
|
import { hasFeature } from '../../lib/hasFeature.js';
|
|
8
8
|
import { FEATURES } from '../../lib/constants.js';
|
|
9
|
-
import { uiBetaTag } from '../../lib/ui/index.js';
|
|
10
9
|
const command = ['setup'];
|
|
11
|
-
const describe =
|
|
10
|
+
const describe = commands.mcp.setup.describe;
|
|
12
11
|
async function handler(args) {
|
|
13
12
|
const { derivedAccountId } = args;
|
|
14
13
|
const hasMcpAccess = await hasFeature(derivedAccountId, FEATURES.MCP_ACCESS);
|
package/commands/mcp.js
CHANGED
|
@@ -2,9 +2,8 @@ import startCommand from './mcp/start.js';
|
|
|
2
2
|
import setupCommand from './mcp/setup.js';
|
|
3
3
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
4
4
|
import { commands } from '../lang/en.js';
|
|
5
|
-
import { uiBetaTag } from '../lib/ui/index.js';
|
|
6
5
|
const command = 'mcp';
|
|
7
|
-
const describe =
|
|
6
|
+
const describe = commands.mcp.describe;
|
|
8
7
|
function mcpBuilder(yargs) {
|
|
9
8
|
yargs.command(startCommand).command(setupCommand).demandCommand(1, '');
|
|
10
9
|
return yargs;
|
package/commands/project.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { pkg } from '../lib/jsonLoader.js';
|
|
2
|
+
import { commands, lib } from '../lang/en.js';
|
|
2
3
|
import deploy from './project/deploy.js';
|
|
3
4
|
import create from './project/create.js';
|
|
4
5
|
import upload from './project/upload.js';
|
|
@@ -17,9 +18,29 @@ import profile from './project/profile.js';
|
|
|
17
18
|
import projectValidate from './project/validate.js';
|
|
18
19
|
import list from './project/list.js';
|
|
19
20
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
21
|
+
import { getProjectConfig } from '../lib/projects/config.js';
|
|
22
|
+
import { isUnsupportedPlatformVersion, LATEST_SUPPORTED_PLATFORM_VERSION, } from '../lib/projects/platformVersion.js';
|
|
23
|
+
import { uiLogger } from '../lib/ui/logger.js';
|
|
24
|
+
import { debugError } from '../lib/errorHandlers/index.js';
|
|
20
25
|
const command = ['project', 'projects'];
|
|
21
26
|
const describe = commands.project.describe;
|
|
27
|
+
// Warn users when they are interacting with a version of projects that this version of
|
|
28
|
+
// the CLI is not officially compatible with
|
|
29
|
+
async function validatePlatformVersion() {
|
|
30
|
+
try {
|
|
31
|
+
const { projectConfig } = await getProjectConfig();
|
|
32
|
+
if (isUnsupportedPlatformVersion(projectConfig?.platformVersion)) {
|
|
33
|
+
uiLogger.warn(lib.projects.platformVersion.unsupported(pkg.version, LATEST_SUPPORTED_PLATFORM_VERSION, projectConfig?.platformVersion));
|
|
34
|
+
uiLogger.log('');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
// Silently fail. We don't want this to interrupt command execution
|
|
39
|
+
debugError(error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
22
42
|
function projectBuilder(yargs) {
|
|
43
|
+
yargs.middleware([validatePlatformVersion]);
|
|
23
44
|
yargs
|
|
24
45
|
.command(create)
|
|
25
46
|
.command(add)
|
package/lang/en.d.ts
CHANGED
|
@@ -34,6 +34,15 @@ export declare const commands: {
|
|
|
34
34
|
installingDependenciesIn: (installPath: string) => string;
|
|
35
35
|
createdProjectSuccess: (projectName: string, projectDest: string) => string;
|
|
36
36
|
pressEnterToContinueDeploy: (accountName: string) => string;
|
|
37
|
+
uploadingProject: string;
|
|
38
|
+
uploadSuccess: string;
|
|
39
|
+
appDeployedReady: string;
|
|
40
|
+
appConfigDetails: string;
|
|
41
|
+
distribution: string;
|
|
42
|
+
authType: string;
|
|
43
|
+
checkOutConfig: (configPath: string) => string;
|
|
44
|
+
pressEnterToInstall: (accountName: string) => string;
|
|
45
|
+
pressKeyToExit: string;
|
|
37
46
|
prompts: {
|
|
38
47
|
selectOptionV2: string;
|
|
39
48
|
options: {
|
|
@@ -75,10 +84,15 @@ export declare const commands: {
|
|
|
75
84
|
uploadingProject: string;
|
|
76
85
|
uploadSuccess: string;
|
|
77
86
|
developerOverviewLink: string;
|
|
87
|
+
initialUploadMessage: string;
|
|
78
88
|
};
|
|
79
89
|
errors: {
|
|
80
90
|
uploadFailed: string;
|
|
81
91
|
configFileNotFound: string;
|
|
92
|
+
noAppsFound: string;
|
|
93
|
+
uploadActionFailed: string;
|
|
94
|
+
buildOrDeployFailed: string;
|
|
95
|
+
failedToUploadAndDeploy: string;
|
|
82
96
|
};
|
|
83
97
|
};
|
|
84
98
|
completion: {
|
|
@@ -154,6 +168,7 @@ export declare const commands: {
|
|
|
154
168
|
};
|
|
155
169
|
};
|
|
156
170
|
promptMessage: string;
|
|
171
|
+
authenticateNewAccount: string;
|
|
157
172
|
success: {
|
|
158
173
|
defaultAccountUpdated: (accountName: string) => string;
|
|
159
174
|
};
|
|
@@ -1255,6 +1270,7 @@ export declare const commands: {
|
|
|
1255
1270
|
codexNotFound: string;
|
|
1256
1271
|
codexInstallFailed: string;
|
|
1257
1272
|
configuringCursor: string;
|
|
1273
|
+
cursorNotFound: string;
|
|
1258
1274
|
failedToConfigureCursor: string;
|
|
1259
1275
|
configuredCursor: string;
|
|
1260
1276
|
configuringGemini: string;
|
|
@@ -1263,6 +1279,7 @@ export declare const commands: {
|
|
|
1263
1279
|
geminiInstallFailed: string;
|
|
1264
1280
|
alreadyInstalled: string;
|
|
1265
1281
|
configuringWindsurf: string;
|
|
1282
|
+
windsurfNotFound: string;
|
|
1266
1283
|
failedToConfigureWindsurf: string;
|
|
1267
1284
|
configuredWindsurf: string;
|
|
1268
1285
|
configuringVsCode: string;
|
|
@@ -1642,6 +1659,7 @@ export declare const commands: {
|
|
|
1642
1659
|
noFunctionWithName: (name: string) => string;
|
|
1643
1660
|
functionNotDeployed: (name: string) => string;
|
|
1644
1661
|
projectLogsManagerNotInitialized: string;
|
|
1662
|
+
noDeployedBuild: string;
|
|
1645
1663
|
generic: string;
|
|
1646
1664
|
};
|
|
1647
1665
|
logs: {
|
|
@@ -3093,13 +3111,16 @@ export declare const lib: {
|
|
|
3093
3111
|
};
|
|
3094
3112
|
validateProjectConfig: {
|
|
3095
3113
|
configNotFound: string;
|
|
3096
|
-
configMissingFields: string;
|
|
3114
|
+
configMissingFields: (missingFields: string[]) => string;
|
|
3097
3115
|
srcDirNotFound: (srcDir: string, projectDir: string) => string;
|
|
3098
3116
|
srcOutsideProjectDir: (projectConfig: string, srcDir: string) => string;
|
|
3099
3117
|
};
|
|
3100
3118
|
getProjectConfig: {
|
|
3101
3119
|
error: string;
|
|
3102
3120
|
};
|
|
3121
|
+
platformVersion: {
|
|
3122
|
+
unsupported: (currentCliVersion: string, latestSupported: string, platformVersion?: string) => string;
|
|
3123
|
+
};
|
|
3103
3124
|
ensureProjectExists: {
|
|
3104
3125
|
createPrompt: (projectName: string, accountIdentifier: string) => string;
|
|
3105
3126
|
createPromptUpload: (projectName: string, accountIdentifier: string) => string;
|
package/lang/en.js
CHANGED
|
@@ -42,6 +42,15 @@ export const commands = {
|
|
|
42
42
|
installingDependenciesIn: (installPath) => `Installing dependencies in ${installPath}`,
|
|
43
43
|
createdProjectSuccess: (projectName, projectDest) => `[SUCCESS] Project ${chalk.bold(projectName)} was successfully created in ${projectDest}`,
|
|
44
44
|
pressEnterToContinueDeploy: (accountName) => `Press ${chalk.bold('<enter>')} to deploy this project to ${chalk.bold(accountName)} ...`,
|
|
45
|
+
uploadingProject: `Running \`${uiCommandReference('hs project upload', false)}\` to upload and deploy your project...`,
|
|
46
|
+
uploadSuccess: '✓ Upload and deploy complete!',
|
|
47
|
+
appDeployedReady: '🚀 Your new app is now deployed on HubSpot and ready to install!',
|
|
48
|
+
appConfigDetails: 'App configuration details:',
|
|
49
|
+
distribution: 'distribution',
|
|
50
|
+
authType: 'auth type',
|
|
51
|
+
checkOutConfig: (configPath) => `Check out ${chalk.cyan(configPath)} for the full configuration.`,
|
|
52
|
+
pressEnterToInstall: (accountName) => `? Press ${chalk.bold('<enter>')} to continue installing and previewing this app in ${chalk.bold(accountName)}`,
|
|
53
|
+
pressKeyToExit: `Press any key to exit...`,
|
|
45
54
|
prompts: {
|
|
46
55
|
selectOptionV2: 'Choose a component type to get started',
|
|
47
56
|
options: {
|
|
@@ -83,10 +92,15 @@ export const commands = {
|
|
|
83
92
|
uploadingProject: 'Uploading your project to HubSpot...',
|
|
84
93
|
uploadSuccess: 'Project uploaded successfully!',
|
|
85
94
|
developerOverviewLink: 'Open this link to navigate to your HubSpot developer portal',
|
|
95
|
+
initialUploadMessage: 'Initial upload from get-started command',
|
|
86
96
|
},
|
|
87
97
|
errors: {
|
|
88
98
|
uploadFailed: 'Failed to upload project to HubSpot.',
|
|
89
99
|
configFileNotFound: 'Could not find project configuration for upload.',
|
|
100
|
+
noAppsFound: 'No apps found after deployment.',
|
|
101
|
+
uploadActionFailed: 'Upload failed',
|
|
102
|
+
buildOrDeployFailed: 'Build or deploy failed',
|
|
103
|
+
failedToUploadAndDeploy: 'Failed to upload and deploy project',
|
|
90
104
|
},
|
|
91
105
|
},
|
|
92
106
|
completion: {
|
|
@@ -162,6 +176,7 @@ export const commands = {
|
|
|
162
176
|
},
|
|
163
177
|
},
|
|
164
178
|
promptMessage: 'Select an account to use as the default',
|
|
179
|
+
authenticateNewAccount: '<Authenticate a new account>',
|
|
165
180
|
success: {
|
|
166
181
|
defaultAccountUpdated: (accountName) => `Default account updated to "${accountName}"`,
|
|
167
182
|
},
|
|
@@ -1259,32 +1274,34 @@ export const commands = {
|
|
|
1259
1274
|
// Claude
|
|
1260
1275
|
configuringClaudeCode: 'Configuring Claude Code...',
|
|
1261
1276
|
configuredClaudeCode: 'Configured Claude Code',
|
|
1262
|
-
claudeCodeNotFound:
|
|
1277
|
+
claudeCodeNotFound: "Claude Code is not installed (missing 'claude' command). Install it and re-run hs mcp setup.",
|
|
1263
1278
|
claudeCodeInstallFailed: 'Claude Code CLI not working - skipping configuration',
|
|
1264
1279
|
// Codex
|
|
1265
1280
|
configuringCodex: 'Configuring Codex...',
|
|
1266
1281
|
configuredCodex: 'Configured Codex',
|
|
1267
|
-
codexNotFound:
|
|
1282
|
+
codexNotFound: "Codex CLI is not installed (missing 'codex' command). Install it and re-run hs mcp setup.",
|
|
1268
1283
|
codexInstallFailed: 'Failed to configure Codex',
|
|
1269
1284
|
// Cursor
|
|
1270
1285
|
configuringCursor: 'Configuring Cursor...',
|
|
1286
|
+
cursorNotFound: 'Cursor is not installed. Install it and re-run hs mcp setup.',
|
|
1271
1287
|
failedToConfigureCursor: 'Failed to configure Cursor',
|
|
1272
1288
|
configuredCursor: 'Configured Cursor',
|
|
1273
1289
|
// Gemini
|
|
1274
1290
|
configuringGemini: 'Configuring Gemini CLI...',
|
|
1275
1291
|
configuredGemini: 'Configured Gemini CLI',
|
|
1276
|
-
geminiNotFound:
|
|
1292
|
+
geminiNotFound: "Gemini CLI is not installed (missing 'gemini' command). Install it and re-run hs mcp setup.",
|
|
1277
1293
|
geminiInstallFailed: 'Failed to configure Gemini CLI',
|
|
1278
1294
|
alreadyInstalled: 'HubSpot CLI mcp server already installed, reinstalling',
|
|
1279
1295
|
// Windsurf
|
|
1280
1296
|
configuringWindsurf: 'Configuring Windsurf...',
|
|
1297
|
+
windsurfNotFound: 'Windsurf is not installed. Install it and re-run hs mcp setup.',
|
|
1281
1298
|
failedToConfigureWindsurf: 'Failed to configure Windsurf',
|
|
1282
1299
|
configuredWindsurf: 'Configured Windsurf',
|
|
1283
1300
|
// VS Code
|
|
1284
1301
|
configuringVsCode: 'Configuring VSCode...',
|
|
1285
1302
|
failedToConfigureVsCode: 'Failed to configure VSCode',
|
|
1286
1303
|
configuredVsCode: 'Configured VSCode',
|
|
1287
|
-
vsCodeNotFound:
|
|
1304
|
+
vsCodeNotFound: "VSCode CLI is not installed (missing 'code' command). Install it and re-run hs mcp setup.",
|
|
1288
1305
|
},
|
|
1289
1306
|
prompts: {
|
|
1290
1307
|
targets: '[--client] Which tools would you like to add the HubSpot CLI MCP server to?',
|
|
@@ -1658,6 +1675,7 @@ export const commands = {
|
|
|
1658
1675
|
noFunctionWithName: (name) => `No function with name "${name}"`,
|
|
1659
1676
|
functionNotDeployed: (name) => `The function with name "${name}" is not deployed`,
|
|
1660
1677
|
projectLogsManagerNotInitialized: 'Function called on ProjectLogsManager before initialization',
|
|
1678
|
+
noDeployedBuild: 'This project has not been deployed yet. Deploy the project first, then try again.',
|
|
1661
1679
|
generic: 'Error fetching logs',
|
|
1662
1680
|
},
|
|
1663
1681
|
logs: {
|
|
@@ -3116,13 +3134,16 @@ export const lib = {
|
|
|
3116
3134
|
},
|
|
3117
3135
|
validateProjectConfig: {
|
|
3118
3136
|
configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${uiCommandReference('hs project create')} to create a new project.`,
|
|
3119
|
-
configMissingFields:
|
|
3137
|
+
configMissingFields: (missingFields) => `The project configuration file is missing required field${missingFields.length > 1 ? 's' : ''}: ${missingFields.map(f => chalk.bold(f)).join(', ')}`,
|
|
3120
3138
|
srcDirNotFound: (srcDir, projectDir) => `Project source directory ${chalk.bold(srcDir)} could not be found in ${chalk.bold(projectDir)}.`,
|
|
3121
3139
|
srcOutsideProjectDir: (projectConfig, srcDir) => `Invalid value for 'srcDir' in ${projectConfig}: ${chalk.bold(`srcDir: "${srcDir}"`)}\n\t'srcDir' must be a relative path to a folder under the project root, such as "." or "./src"`,
|
|
3122
3140
|
},
|
|
3123
3141
|
getProjectConfig: {
|
|
3124
3142
|
error: 'Could not read from project config',
|
|
3125
3143
|
},
|
|
3144
|
+
platformVersion: {
|
|
3145
|
+
unsupported: (currentCliVersion, latestSupported, platformVersion) => `Platform version${platformVersion ? ' ' + chalk.bold(platformVersion) : ''} is not officially supported by this version of the CLI (${chalk.bold(currentCliVersion)}).\n\nUpdate your CLI to the latest version with ${uiCommandReference('hs upgrade')} or use a compatible platform version (${chalk.bold(latestSupported)} or earlier).`,
|
|
3146
|
+
},
|
|
3126
3147
|
ensureProjectExists: {
|
|
3127
3148
|
createPrompt: (projectName, accountIdentifier) => `The project ${projectName} does not exist in ${accountIdentifier}. Would you like to create it?`,
|
|
3128
3149
|
createPromptUpload: (projectName, accountIdentifier) => `[--forceCreate] The project ${projectName} does not exist in ${accountIdentifier}. Would you like to create it?`,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|