@hubspot/cli 7.8.0-experimental.0 → 7.8.2-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/bin/cli.js +0 -2
- package/commands/__tests__/getStarted.test.js +2 -2
- package/commands/__tests__/mcp.test.js +1 -1
- package/commands/__tests__/project.test.js +0 -3
- package/commands/app/__tests__/migrate.test.js +0 -1
- package/commands/app/migrate.js +4 -5
- package/commands/app/secret/add.js +2 -1
- package/commands/app/secret/delete.js +2 -1
- package/commands/app/secret/list.js +2 -1
- package/commands/app/secret/update.js +2 -1
- package/commands/app/secret.js +2 -1
- package/commands/app.js +2 -2
- package/commands/config/set.js +0 -1
- package/commands/feedback.js +1 -1
- package/commands/getStarted.d.ts +1 -3
- package/commands/getStarted.js +66 -18
- package/commands/mcp/__tests__/setup.test.js +2 -2
- package/commands/mcp/setup.js +11 -2
- package/commands/mcp.js +3 -3
- package/commands/project/__tests__/create.test.js +6 -6
- package/commands/project/__tests__/deploy.test.js +0 -3
- package/commands/project/__tests__/devUnifiedFlow.test.js +2 -4
- package/commands/project/__tests__/logs.test.js +0 -3
- package/commands/project/__tests__/migrate.test.js +1 -2
- package/commands/project/__tests__/migrateApp.test.js +1 -2
- package/commands/project/__tests__/profile.test.js +1 -1
- package/commands/project/add.js +1 -5
- package/commands/project/create.js +3 -9
- package/commands/project/deploy.js +2 -2
- package/commands/project/dev/index.js +4 -3
- package/commands/project/dev/unifiedFlow.js +6 -4
- package/commands/project/download.js +1 -2
- package/commands/project/installDeps.js +1 -2
- package/commands/project/listBuilds.js +2 -2
- package/commands/project/logs.js +2 -2
- package/commands/project/migrate.js +28 -10
- package/commands/project/migrateApp.js +1 -2
- package/commands/project/open.js +1 -2
- package/commands/project/profile/add.js +3 -3
- package/commands/project/profile/delete.js +1 -2
- package/commands/project/profile.js +2 -3
- package/commands/project/upload.js +2 -2
- package/commands/project/validate.js +1 -1
- package/commands/project/watch.js +2 -2
- package/commands/project.js +1 -2
- package/commands/sandbox/delete.js +1 -1
- package/commands/testAccount/importData.d.ts +1 -1
- package/commands/testAccount/importData.js +1 -1
- package/commands/testAccount.js +1 -1
- package/lang/en.d.ts +15 -4
- package/lang/en.js +18 -6
- package/lib/__tests__/hasFeature.test.js +145 -7
- package/lib/app/__tests__/migrate.test.js +14 -51
- package/lib/app/migrate.d.ts +2 -8
- package/lib/app/migrate.js +5 -80
- package/lib/constants.d.ts +8 -0
- package/lib/constants.js +8 -0
- package/lib/dependencyManagement.d.ts +0 -5
- package/lib/dependencyManagement.js +0 -9
- package/lib/hasFeature.js +6 -0
- package/lib/links.d.ts +1 -0
- package/lib/links.js +10 -3
- package/lib/mcp/setup.js +1 -1
- package/lib/middleware/fireAlarmMiddleware.js +15 -5
- package/lib/projects/__tests__/LocalDevProcess.test.js +227 -16
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +16 -21
- package/lib/projects/__tests__/deploy.test.js +71 -6
- package/lib/projects/__tests__/localDevProjectHelpers.test.js +4 -2
- package/lib/projects/create/__tests__/v3.test.js +79 -4
- package/lib/projects/create/v3.js +11 -8
- package/lib/projects/localDev/AppDevModeInterface.js +5 -5
- package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
- package/lib/projects/localDev/LocalDevLogger.js +22 -0
- package/lib/projects/localDev/LocalDevProcess.d.ts +7 -5
- package/lib/projects/localDev/LocalDevProcess.js +90 -19
- package/lib/projects/localDev/LocalDevState.d.ts +9 -8
- package/lib/projects/localDev/LocalDevState.js +18 -17
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.js +55 -23
- package/lib/projects/localDev/helpers/project.d.ts +2 -2
- package/lib/projects/localDev/helpers/project.js +10 -7
- package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +4 -0
- package/lib/projects/localDev/localDevWebsocketServerUtils.js +10 -0
- package/lib/projects/pollProjectBuildAndDeploy.js +4 -4
- package/lib/prompts/projectAddPrompt.js +2 -1
- package/lib/prompts/promptUtils.js +3 -0
- package/lib/prompts/selectProjectTemplatePrompt.js +2 -0
- package/lib/theme/__tests__/migrate.test.d.ts +1 -0
- package/lib/theme/__tests__/migrate.test.js +233 -0
- package/lib/theme/migrate.d.ts +13 -0
- package/lib/theme/migrate.js +90 -0
- package/lib/ui/SpinniesManager.js +105 -8
- package/lib/usageTracking.js +2 -2
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +1 -1
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
- package/mcp-server/tools/cms/HsListTool.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +1 -1
- 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 +2 -2
- package/mcp-server/tools/project/DocsSearchTool.d.ts +4 -1
- package/mcp-server/tools/project/DocsSearchTool.js +7 -7
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -1
- package/mcp-server/tools/project/GetConfigValuesTool.js +11 -5
- 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 +2 -2
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +14 -12
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +9 -8
- 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 +9 -3
- package/mcp-server/utils/__tests__/cliConfig.test.d.ts +1 -0
- package/mcp-server/utils/__tests__/cliConfig.test.js +110 -0
- package/mcp-server/utils/cliConfig.d.ts +1 -0
- package/mcp-server/utils/cliConfig.js +12 -0
- package/package.json +4 -9
- package/types/LocalDev.d.ts +19 -3
- package/ui/components/HorizontalSelectPrompt.js +1 -1
- package/ui/index.js +1 -1
- package/commands/getStartedV2.d.ts +0 -9
- package/commands/getStartedV2.js +0 -39
- package/ui/components/Ascii.d.ts +0 -10
- package/ui/components/Ascii.js +0 -11
- package/ui/views/GetStarted.d.ts +0 -7
- package/ui/views/GetStarted.js +0 -157
package/bin/cli.js
CHANGED
|
@@ -42,7 +42,6 @@ import appCommand from '../commands/app.js';
|
|
|
42
42
|
import testAccountCommands from '../commands/testAccount.js';
|
|
43
43
|
import getStartedCommand from '../commands/getStarted.js';
|
|
44
44
|
import mcpCommand from '../commands/mcp.js';
|
|
45
|
-
import getStartedV2Command from '../commands/getStartedV2.js';
|
|
46
45
|
function getTerminalWidth() {
|
|
47
46
|
const width = yargs().terminalWidth();
|
|
48
47
|
if (width >= 100)
|
|
@@ -93,7 +92,6 @@ const argv = yargs(process.argv.slice(2))
|
|
|
93
92
|
type: 'boolean',
|
|
94
93
|
})
|
|
95
94
|
.check(performChecks)
|
|
96
|
-
.command(getStartedV2Command)
|
|
97
95
|
.command(authCommand)
|
|
98
96
|
.command(initCommand)
|
|
99
97
|
.command(logsCommand)
|
|
@@ -34,8 +34,8 @@ describe('commands/get-started', () => {
|
|
|
34
34
|
});
|
|
35
35
|
});
|
|
36
36
|
describe('describe', () => {
|
|
37
|
-
it('should have
|
|
38
|
-
expect(getStartedCommand.describe).
|
|
37
|
+
it('should have a defined describe property', () => {
|
|
38
|
+
expect(getStartedCommand.describe).toBeDefined();
|
|
39
39
|
});
|
|
40
40
|
});
|
|
41
41
|
describe('command structure', () => {
|
|
@@ -51,9 +51,6 @@ describe('commands/project', () => {
|
|
|
51
51
|
});
|
|
52
52
|
});
|
|
53
53
|
describe('describe', () => {
|
|
54
|
-
it('should contain the beta tag', () => {
|
|
55
|
-
expect(projectCommand.describe).toContain('[BETA]');
|
|
56
|
-
});
|
|
57
54
|
it('should provide a description', () => {
|
|
58
55
|
expect(projectCommand.describe).toBeDefined();
|
|
59
56
|
});
|
package/commands/app/migrate.js
CHANGED
|
@@ -6,13 +6,13 @@ import { i18n } from '../../lib/lang.js';
|
|
|
6
6
|
import { ApiErrorContext, logError } from '../../lib/errorHandlers/index.js';
|
|
7
7
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
8
8
|
import { migrateApp2025_2 } from '../../lib/app/migrate.js';
|
|
9
|
-
import {
|
|
9
|
+
import { uiCommandReference, uiLink } from '../../lib/ui/index.js';
|
|
10
10
|
import { migrateApp2023_2 } from '../../lib/app/migrate_legacy.js';
|
|
11
11
|
import { getIsInProject } from '../../lib/projects/config.js';
|
|
12
12
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
13
13
|
const { v2023_2, v2025_2 } = PLATFORM_VERSIONS;
|
|
14
14
|
const command = 'migrate';
|
|
15
|
-
const describe =
|
|
15
|
+
const describe = i18n(`commands.project.subcommands.migrateApp.describe`);
|
|
16
16
|
export function handlerGenerator(commandTrackingName) {
|
|
17
17
|
return async function handler(args) {
|
|
18
18
|
const { derivedAccountId, platformVersion, unstable } = args;
|
|
@@ -23,7 +23,7 @@ export function handlerGenerator(commandTrackingName) {
|
|
|
23
23
|
return process.exit(EXIT_CODES.ERROR);
|
|
24
24
|
}
|
|
25
25
|
logger.log('');
|
|
26
|
-
logger.log(
|
|
26
|
+
logger.log(i18n(`commands.project.subcommands.migrateApp.header.text`));
|
|
27
27
|
logger.log(uiLink(i18n(`commands.project.subcommands.migrateApp.header.link`), 'https://developers.hubspot.com/docs/platform/migrate-a-public-app-to-projects'));
|
|
28
28
|
logger.log('');
|
|
29
29
|
try {
|
|
@@ -76,7 +76,6 @@ function appMigrateBuilder(yargs) {
|
|
|
76
76
|
'platform-version': {
|
|
77
77
|
type: 'string',
|
|
78
78
|
choices: [v2023_2, v2025_2],
|
|
79
|
-
hidden: true,
|
|
80
79
|
default: v2025_2,
|
|
81
80
|
},
|
|
82
81
|
unstable: {
|
|
@@ -93,7 +92,7 @@ function appMigrateBuilder(yargs) {
|
|
|
93
92
|
]);
|
|
94
93
|
return yargs;
|
|
95
94
|
}
|
|
96
|
-
const builder = makeYargsBuilder(appMigrateBuilder, command,
|
|
95
|
+
const builder = makeYargsBuilder(appMigrateBuilder, command, i18n(`commands.project.subcommands.migrateApp.describe`), {
|
|
97
96
|
useGlobalOptions: true,
|
|
98
97
|
useConfigOptions: true,
|
|
99
98
|
useAccountOptions: true,
|
|
@@ -7,8 +7,9 @@ import { commands } from '../../../lang/en.js';
|
|
|
7
7
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
8
8
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
9
9
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
10
|
+
import { uiBetaTag } from '../../../lib/ui/index.js';
|
|
10
11
|
const command = 'add [name]';
|
|
11
|
-
const describe = commands.app.subcommands.secret.subcommands.add.describe;
|
|
12
|
+
const describe = uiBetaTag(commands.app.subcommands.secret.subcommands.add.describe, false);
|
|
12
13
|
async function handler(args) {
|
|
13
14
|
const { derivedAccountId } = args;
|
|
14
15
|
trackCommandUsage('app-secret-add', {}, derivedAccountId);
|
|
@@ -7,8 +7,9 @@ import { commands } from '../../../lang/en.js';
|
|
|
7
7
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
8
8
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
9
9
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
10
|
+
import { uiBetaTag } from '../../../lib/ui/index.js';
|
|
10
11
|
const command = 'delete [name]';
|
|
11
|
-
const describe = commands.app.subcommands.secret.subcommands.delete.describe;
|
|
12
|
+
const describe = uiBetaTag(commands.app.subcommands.secret.subcommands.delete.describe, false);
|
|
12
13
|
async function handler(args) {
|
|
13
14
|
const { derivedAccountId, force } = args;
|
|
14
15
|
trackCommandUsage('app-secret-delete', {}, derivedAccountId);
|
|
@@ -6,8 +6,9 @@ import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
|
6
6
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
7
7
|
import { selectAppPrompt } from '../../../lib/prompts/selectAppPrompt.js';
|
|
8
8
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
9
|
+
import { uiBetaTag } from '../../../lib/ui/index.js';
|
|
9
10
|
const command = 'list';
|
|
10
|
-
const describe = commands.app.subcommands.secret.subcommands.list.describe;
|
|
11
|
+
const describe = uiBetaTag(commands.app.subcommands.secret.subcommands.list.describe, false);
|
|
11
12
|
async function handler(args) {
|
|
12
13
|
const { derivedAccountId } = args;
|
|
13
14
|
trackCommandUsage('app-secret-list', {}, derivedAccountId);
|
|
@@ -8,8 +8,9 @@ import { commands } from '../../../lang/en.js';
|
|
|
8
8
|
import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
|
|
9
9
|
import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
|
|
10
10
|
import { uiLogger } from '../../../lib/ui/logger.js';
|
|
11
|
+
import { uiBetaTag } from '../../../lib/ui/index.js';
|
|
11
12
|
const command = 'update [name]';
|
|
12
|
-
const describe = commands.app.subcommands.secret.subcommands.update.describe;
|
|
13
|
+
const describe = uiBetaTag(commands.app.subcommands.secret.subcommands.update.describe, false);
|
|
13
14
|
async function handler(args) {
|
|
14
15
|
const { derivedAccountId } = args;
|
|
15
16
|
trackCommandUsage('app-secret-update', {}, derivedAccountId);
|
package/commands/app/secret.js
CHANGED
|
@@ -4,8 +4,9 @@ import addAppSecretCommand from './secret/add.js';
|
|
|
4
4
|
import deleteAppSecretCommand from './secret/delete.js';
|
|
5
5
|
import listAppSecretsCommand from './secret/list.js';
|
|
6
6
|
import updateAppSecretCommand from './secret/update.js';
|
|
7
|
+
import { uiBetaTag } from '../../lib/ui/index.js';
|
|
7
8
|
const command = ['secret', 'secrets'];
|
|
8
|
-
const describe =
|
|
9
|
+
const describe = uiBetaTag(commands.app.subcommands.secret.describe, false);
|
|
9
10
|
function appSecretBuilder(yargs) {
|
|
10
11
|
yargs
|
|
11
12
|
.command(addAppSecretCommand)
|
package/commands/app.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import migrateCommand from './app/migrate.js';
|
|
2
2
|
import appSecretCommand from './app/secret.js';
|
|
3
3
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
4
|
+
import { commands } from '../lang/en.js';
|
|
4
5
|
const command = ['app', 'apps'];
|
|
5
|
-
|
|
6
|
-
const describe = undefined;
|
|
6
|
+
const describe = commands.app.describe;
|
|
7
7
|
function appBuilder(yargs) {
|
|
8
8
|
yargs.command(migrateCommand).command(appSecretCommand).demandCommand(1, '');
|
|
9
9
|
return yargs;
|
package/commands/config/set.js
CHANGED
package/commands/feedback.js
CHANGED
|
@@ -5,7 +5,7 @@ import { confirmPrompt } from '../lib/prompts/promptUtils.js';
|
|
|
5
5
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
6
6
|
import { EXIT_CODES } from '../lib/enums/exitCodes.js';
|
|
7
7
|
import { uiLink } from '../lib/ui/index.js';
|
|
8
|
-
const FEEDBACK_URL = 'https://developers.hubspot.com/feedback
|
|
8
|
+
const FEEDBACK_URL = 'https://developers.hubspot.com/feedback';
|
|
9
9
|
const command = 'feedback';
|
|
10
10
|
const describe = i18n(`commands.project.subcommands.feedback.describe`);
|
|
11
11
|
async function handler() {
|
package/commands/getStarted.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { AccountArgs, YargsCommandModule, CommonArgs, ConfigArgs, EnvironmentArgs } from '../types/Yargs.js';
|
|
2
|
-
|
|
3
|
-
export declare const describe: undefined;
|
|
4
|
-
export type GetStartedArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
2
|
+
type GetStartedArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
|
|
5
3
|
name?: string;
|
|
6
4
|
dest?: string;
|
|
7
5
|
};
|
package/commands/getStarted.js
CHANGED
|
@@ -4,6 +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 { trackCommandMetadataUsage, trackCommandUsage, } from '../lib/usageTracking.js';
|
|
7
8
|
import { EXIT_CODES } from '../lib/enums/exitCodes.js';
|
|
8
9
|
import { makeYargsBuilder } from '../lib/yargsUtils.js';
|
|
9
10
|
import { promptUser } from '../lib/prompts/promptUtils.js';
|
|
@@ -22,14 +23,13 @@ import { getStaticAuthAppInstallUrl } from '../lib/app/urls.js';
|
|
|
22
23
|
import { getEnv } from '@hubspot/local-dev-lib/config';
|
|
23
24
|
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
24
25
|
import { fetchPublicAppsForPortal } from '@hubspot/local-dev-lib/api/appsDev';
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
const command = 'get-started';
|
|
27
|
+
const describe = commands.getStarted.describe;
|
|
27
28
|
async function handler(args) {
|
|
28
29
|
const { derivedAccountId } = args;
|
|
29
30
|
const env = getEnv(derivedAccountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD;
|
|
31
|
+
await trackCommandUsage('get-started', {}, derivedAccountId);
|
|
30
32
|
const accountName = uiAccountDescription(derivedAccountId);
|
|
31
|
-
// TODO: Put this in constants.ts once we have a defined place for the template before INBOUND
|
|
32
|
-
const templateSource = 'robrown-hubspot/hubspot-project-components-ua-app-objects-beta';
|
|
33
33
|
uiInfoSection(commands.getStarted.startTitle, () => {
|
|
34
34
|
uiLogger.log(commands.getStarted.startDescription);
|
|
35
35
|
uiLogger.log(commands.getStarted.guideOverview(accountName));
|
|
@@ -52,6 +52,8 @@ async function handler(args) {
|
|
|
52
52
|
default: GET_STARTED_OPTIONS.APP,
|
|
53
53
|
},
|
|
54
54
|
]);
|
|
55
|
+
// Track user's initial choice
|
|
56
|
+
await trackCommandMetadataUsage('get-started', { step: 'select-option', type: selectedOption }, derivedAccountId);
|
|
55
57
|
if (selectedOption === GET_STARTED_OPTIONS.CMS) {
|
|
56
58
|
uiLogger.log(' ');
|
|
57
59
|
uiLogger.log(commands.getStarted.designManager);
|
|
@@ -64,6 +66,11 @@ async function handler(args) {
|
|
|
64
66
|
message: commands.getStarted.openDesignManagerPrompt,
|
|
65
67
|
},
|
|
66
68
|
]);
|
|
69
|
+
// Track Design Manager browser action
|
|
70
|
+
await trackCommandMetadataUsage('get-started', {
|
|
71
|
+
step: 'open-design-manager',
|
|
72
|
+
type: shouldOpen ? 'opened' : 'declined',
|
|
73
|
+
}, derivedAccountId);
|
|
67
74
|
if (shouldOpen) {
|
|
68
75
|
uiLogger.log('');
|
|
69
76
|
openLink(derivedAccountId, 'design-manager');
|
|
@@ -74,36 +81,37 @@ async function handler(args) {
|
|
|
74
81
|
else {
|
|
75
82
|
uiLogger.log(' ');
|
|
76
83
|
uiLogger.log(commands.getStarted.logs.appSelected);
|
|
77
|
-
// 1. Fetch project templates
|
|
78
|
-
let latestRepoReleaseTag;
|
|
79
84
|
const { dest, name } = await projectNameAndDestPrompt(args);
|
|
80
|
-
// Specific template for get-started command
|
|
81
|
-
const projectTemplate = {
|
|
82
|
-
name: 'private-app-get-started-template',
|
|
83
|
-
label: 'CRM getting started project with private apps',
|
|
84
|
-
path: 'projects/private-app-get-started-template',
|
|
85
|
-
};
|
|
86
|
-
// 3. Create the project files
|
|
87
85
|
const projectDest = path.resolve(getCwd(), dest);
|
|
88
86
|
const { projectConfig: existingProjectConfig, projectDir: existingProjectDir, } = await getProjectConfig(projectDest);
|
|
89
87
|
if (existingProjectConfig &&
|
|
90
88
|
existingProjectDir &&
|
|
91
89
|
projectDest.startsWith(existingProjectDir)) {
|
|
90
|
+
// Track nested project error
|
|
91
|
+
await trackCommandMetadataUsage('get-started', {
|
|
92
|
+
successful: false,
|
|
93
|
+
step: 'project-creation',
|
|
94
|
+
}, derivedAccountId);
|
|
92
95
|
uiLogger.log(' ');
|
|
93
96
|
uiLogger.error(commands.project.create.errors.cannotNestProjects(existingProjectDir));
|
|
94
97
|
process.exit(EXIT_CODES.ERROR);
|
|
95
98
|
}
|
|
96
|
-
const repo = templateSource || HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
|
|
97
99
|
// 4. Clone the project template from GitHub
|
|
98
|
-
// This is temporary until we have the UA template in the main repo
|
|
99
100
|
try {
|
|
100
|
-
await cloneGithubRepo(
|
|
101
|
-
sourceDir:
|
|
102
|
-
tag: latestRepoReleaseTag,
|
|
101
|
+
await cloneGithubRepo(HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDest, {
|
|
102
|
+
sourceDir: '2025.2/private-app-get-started-template',
|
|
103
103
|
hideLogs: true,
|
|
104
104
|
});
|
|
105
|
+
await trackCommandMetadataUsage('get-started', {
|
|
106
|
+
successful: true,
|
|
107
|
+
step: 'github-clone',
|
|
108
|
+
}, derivedAccountId);
|
|
105
109
|
}
|
|
106
110
|
catch (err) {
|
|
111
|
+
await trackCommandMetadataUsage('get-started', {
|
|
112
|
+
successful: false,
|
|
113
|
+
step: 'github-clone',
|
|
114
|
+
}, derivedAccountId);
|
|
107
115
|
debugError(err);
|
|
108
116
|
uiLogger.log(' ');
|
|
109
117
|
uiLogger.error(commands.project.create.errors.failedToDownloadProject);
|
|
@@ -122,6 +130,11 @@ async function handler(args) {
|
|
|
122
130
|
uiLogger.log(' ');
|
|
123
131
|
uiLogger.log(commands.getStarted.prompts.projectCreated.description);
|
|
124
132
|
uiLogger.log(' ');
|
|
133
|
+
// Track successful project creation
|
|
134
|
+
await trackCommandMetadataUsage('get-started', {
|
|
135
|
+
successful: true,
|
|
136
|
+
step: 'project-creation',
|
|
137
|
+
}, derivedAccountId);
|
|
125
138
|
// 5. Install dependencies
|
|
126
139
|
const installLocations = await getProjectPackageJsonLocations(projectDest);
|
|
127
140
|
try {
|
|
@@ -147,11 +160,21 @@ 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);
|
|
@@ -172,11 +195,21 @@ async function handler(args) {
|
|
|
172
195
|
skipValidation: false,
|
|
173
196
|
});
|
|
174
197
|
if (uploadError) {
|
|
198
|
+
// Track upload failure
|
|
199
|
+
await trackCommandMetadataUsage('get-started', {
|
|
200
|
+
successful: false,
|
|
201
|
+
step: 'upload',
|
|
202
|
+
}, derivedAccountId);
|
|
175
203
|
uiLogger.log(' ');
|
|
176
204
|
uiLogger.error(commands.getStarted.errors.uploadFailed);
|
|
177
205
|
debugError(uploadError);
|
|
178
206
|
}
|
|
179
207
|
else if (result) {
|
|
208
|
+
// Track successful upload completion
|
|
209
|
+
await trackCommandMetadataUsage('get-started', {
|
|
210
|
+
successful: true,
|
|
211
|
+
step: 'upload',
|
|
212
|
+
}, derivedAccountId);
|
|
180
213
|
uiLogger.log(' ');
|
|
181
214
|
uiLogger.success(commands.getStarted.logs.uploadSuccess);
|
|
182
215
|
const { data: { results }, } = await fetchPublicAppsForPortal(derivedAccountId);
|
|
@@ -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) {
|
|
@@ -3,12 +3,12 @@ vi.mock('../../../lib/commonOpts');
|
|
|
3
3
|
describe('commands/mcp/setup', () => {
|
|
4
4
|
describe('command', () => {
|
|
5
5
|
it('should have the correct command structure', () => {
|
|
6
|
-
expect(setupCommand.command).toEqual(['setup'
|
|
6
|
+
expect(setupCommand.command).toEqual(['setup']);
|
|
7
7
|
});
|
|
8
8
|
});
|
|
9
9
|
describe('describe', () => {
|
|
10
10
|
it('should be undefined to keep the command hidden', () => {
|
|
11
|
-
expect(setupCommand.describe).
|
|
11
|
+
expect(setupCommand.describe).toBeDefined();
|
|
12
12
|
});
|
|
13
13
|
});
|
|
14
14
|
describe('builder', () => {
|
package/commands/mcp/setup.js
CHANGED
|
@@ -4,9 +4,18 @@ import { commands } from '../../lang/en.js';
|
|
|
4
4
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
5
5
|
import { addMcpServerToConfig, supportedTools } from '../../lib/mcp/setup.js';
|
|
6
6
|
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { hasFeature } from '../../lib/hasFeature.js';
|
|
8
|
+
import { FEATURES } from '../../lib/constants.js';
|
|
9
|
+
import { uiBetaTag } from '../../lib/ui/index.js';
|
|
10
|
+
const command = ['setup'];
|
|
11
|
+
const describe = uiBetaTag(commands.mcp.setup.describe, false);
|
|
9
12
|
async function handler(args) {
|
|
13
|
+
const { derivedAccountId } = args;
|
|
14
|
+
const hasMcpAccess = await hasFeature(derivedAccountId, FEATURES.MCP_ACCESS);
|
|
15
|
+
if (!hasMcpAccess) {
|
|
16
|
+
uiLogger.error(commands.mcp.setup.errors.needsMcpAccess(derivedAccountId));
|
|
17
|
+
process.exit(EXIT_CODES.ERROR);
|
|
18
|
+
}
|
|
10
19
|
try {
|
|
11
20
|
await import('@modelcontextprotocol/sdk/server/mcp.js');
|
|
12
21
|
}
|
package/commands/mcp.js
CHANGED
|
@@ -2,14 +2,14 @@ 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';
|
|
5
6
|
const command = 'mcp';
|
|
6
|
-
|
|
7
|
-
const describe = undefined;
|
|
7
|
+
const describe = uiBetaTag(commands.mcp.describe, false);
|
|
8
8
|
function mcpBuilder(yargs) {
|
|
9
9
|
yargs.command(startCommand).command(setupCommand).demandCommand(1, '');
|
|
10
10
|
return yargs;
|
|
11
11
|
}
|
|
12
|
-
const builder = makeYargsBuilder(mcpBuilder, command,
|
|
12
|
+
const builder = makeYargsBuilder(mcpBuilder, command, describe, {
|
|
13
13
|
useGlobalOptions: true,
|
|
14
14
|
});
|
|
15
15
|
const mcpCommand = {
|
|
@@ -48,10 +48,10 @@ describe('commands/project/create', () => {
|
|
|
48
48
|
projectCreateCommand.builder(yargsMock);
|
|
49
49
|
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
50
50
|
expect(optionsCall['platform-version']).toEqual(expect.objectContaining({
|
|
51
|
-
|
|
51
|
+
describe: 'The target platform version for the new project.',
|
|
52
52
|
type: 'string',
|
|
53
53
|
choices: ['2023.2', '2025.1', '2025.2'],
|
|
54
|
-
default: '
|
|
54
|
+
default: '2025.2',
|
|
55
55
|
}));
|
|
56
56
|
});
|
|
57
57
|
it('should define project base option with correct choices', () => {
|
|
@@ -59,7 +59,7 @@ describe('commands/project/create', () => {
|
|
|
59
59
|
projectCreateCommand.builder(yargsMock);
|
|
60
60
|
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
61
61
|
expect(optionsCall['project-base']).toEqual(expect.objectContaining({
|
|
62
|
-
|
|
62
|
+
describe: 'The top level component to include in the project.',
|
|
63
63
|
type: 'string',
|
|
64
64
|
choices: ['empty', 'app'],
|
|
65
65
|
}));
|
|
@@ -69,7 +69,7 @@ describe('commands/project/create', () => {
|
|
|
69
69
|
projectCreateCommand.builder(yargsMock);
|
|
70
70
|
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
71
71
|
expect(optionsCall.distribution).toEqual(expect.objectContaining({
|
|
72
|
-
|
|
72
|
+
describe: 'How the app will be distributed.',
|
|
73
73
|
type: 'string',
|
|
74
74
|
choices: ['private', 'marketplace'],
|
|
75
75
|
}));
|
|
@@ -79,7 +79,7 @@ describe('commands/project/create', () => {
|
|
|
79
79
|
projectCreateCommand.builder(yargsMock);
|
|
80
80
|
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
81
81
|
expect(optionsCall.auth).toEqual(expect.objectContaining({
|
|
82
|
-
|
|
82
|
+
describe: 'Authentication model for the application.',
|
|
83
83
|
type: 'string',
|
|
84
84
|
choices: ['oauth', 'static'],
|
|
85
85
|
}));
|
|
@@ -89,7 +89,7 @@ describe('commands/project/create', () => {
|
|
|
89
89
|
projectCreateCommand.builder(yargsMock);
|
|
90
90
|
const optionsCall = optionsSpy.mock.calls[0][0];
|
|
91
91
|
expect(optionsCall.features).toEqual(expect.objectContaining({
|
|
92
|
-
|
|
92
|
+
describe: 'Features to include in the project. Only valid if project-base is app',
|
|
93
93
|
type: 'array',
|
|
94
94
|
}));
|
|
95
95
|
});
|
|
@@ -62,9 +62,6 @@ describe('commands/project/deploy', () => {
|
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
describe('describe', () => {
|
|
65
|
-
it('should contain the beta tag', () => {
|
|
66
|
-
expect(projectDeployCommand.describe).toContain('[BETA]');
|
|
67
|
-
});
|
|
68
65
|
it('should provide a description', () => {
|
|
69
66
|
expect(projectDeployCommand.describe).toBeDefined();
|
|
70
67
|
});
|
|
@@ -324,8 +324,7 @@ describe('unifiedProjectDevFlow', () => {
|
|
|
324
324
|
});
|
|
325
325
|
expect(createNewProjectForLocalDev).not.toHaveBeenCalled();
|
|
326
326
|
expect(LocalDevProcess).toHaveBeenCalledWith(expect.objectContaining({
|
|
327
|
-
|
|
328
|
-
projectName: mockProject.name,
|
|
327
|
+
projectData: mockProject,
|
|
329
328
|
}));
|
|
330
329
|
});
|
|
331
330
|
});
|
|
@@ -346,8 +345,7 @@ describe('unifiedProjectDevFlow', () => {
|
|
|
346
345
|
targetTestingAccountId: mockProvidedTargetTestingAccountId,
|
|
347
346
|
projectConfig: mockProjectConfig,
|
|
348
347
|
projectDir: mockProjectDir,
|
|
349
|
-
|
|
350
|
-
projectId: mockProject.id,
|
|
348
|
+
projectData: mockProject,
|
|
351
349
|
env: ENVIRONMENTS.PROD,
|
|
352
350
|
});
|
|
353
351
|
});
|
|
@@ -45,9 +45,6 @@ describe('commands/project/logs', () => {
|
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
describe('describe', () => {
|
|
48
|
-
it('should contain the beta tag', () => {
|
|
49
|
-
expect(projectLogsCommand.describe).toContain('[BETA]');
|
|
50
|
-
});
|
|
51
48
|
it('should provide a description', () => {
|
|
52
49
|
expect(projectLogsCommand.describe).toBeDefined();
|
|
53
50
|
});
|
|
@@ -44,7 +44,7 @@ describe('commands/project/migrate', () => {
|
|
|
44
44
|
});
|
|
45
45
|
describe('describe', () => {
|
|
46
46
|
it('should provide a description', () => {
|
|
47
|
-
expect(migrateCommand.describe).
|
|
47
|
+
expect(migrateCommand.describe).toBeDefined();
|
|
48
48
|
});
|
|
49
49
|
});
|
|
50
50
|
describe('builder', () => {
|
|
@@ -54,7 +54,6 @@ describe('commands/project/migrate', () => {
|
|
|
54
54
|
type: 'string',
|
|
55
55
|
choices: [v2025_2],
|
|
56
56
|
default: v2025_2,
|
|
57
|
-
hidden: true,
|
|
58
57
|
});
|
|
59
58
|
expect(optionsSpy).toHaveBeenCalledWith('unstable', {
|
|
60
59
|
type: 'boolean',
|
|
@@ -57,8 +57,7 @@ describe('commands/project/migrateApp', () => {
|
|
|
57
57
|
'platform-version': expect.objectContaining({
|
|
58
58
|
type: 'string',
|
|
59
59
|
choices: [v2023_2, v2025_2],
|
|
60
|
-
|
|
61
|
-
default: v2023_2,
|
|
60
|
+
default: v2025_2,
|
|
62
61
|
}),
|
|
63
62
|
});
|
|
64
63
|
expect(exampleSpy).toHaveBeenCalled();
|
|
@@ -19,7 +19,7 @@ describe('commands/project', () => {
|
|
|
19
19
|
});
|
|
20
20
|
describe('describe', () => {
|
|
21
21
|
it('should not provide a description', () => {
|
|
22
|
-
expect(profileCommand.describe).
|
|
22
|
+
expect(profileCommand.describe).toBeDefined();
|
|
23
23
|
});
|
|
24
24
|
});
|
|
25
25
|
describe('builder', () => {
|
package/commands/project/add.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
2
2
|
import { getProjectConfig } from '../../lib/projects/config.js';
|
|
3
|
-
import { uiBetaTag } from '../../lib/ui/index.js';
|
|
4
3
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
5
4
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
6
5
|
import { commands } from '../../lang/en.js';
|
|
@@ -10,7 +9,7 @@ import { v3AddComponent } from '../../lib/projects/add/v3AddComponent.js';
|
|
|
10
9
|
import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../lib/constants.js';
|
|
11
10
|
import { uiLogger } from '../../lib/ui/logger.js';
|
|
12
11
|
const command = 'add';
|
|
13
|
-
const describe =
|
|
12
|
+
const describe = commands.project.add.describe;
|
|
14
13
|
async function handler(args) {
|
|
15
14
|
try {
|
|
16
15
|
const { derivedAccountId } = args;
|
|
@@ -45,19 +44,16 @@ function projectAddBuilder(yargs) {
|
|
|
45
44
|
},
|
|
46
45
|
distribution: {
|
|
47
46
|
describe: commands.project.add.options.distribution.describe,
|
|
48
|
-
hidden: true,
|
|
49
47
|
type: 'string',
|
|
50
48
|
choices: [privateDistribution, marketplaceDistribution],
|
|
51
49
|
},
|
|
52
50
|
auth: {
|
|
53
51
|
describe: commands.project.add.options.auth.describe,
|
|
54
|
-
hidden: true,
|
|
55
52
|
type: 'string',
|
|
56
53
|
choices: [oAuth, staticAuth],
|
|
57
54
|
},
|
|
58
55
|
features: {
|
|
59
56
|
describe: commands.project.add.options.features.describe,
|
|
60
|
-
hidden: true,
|
|
61
57
|
type: 'array',
|
|
62
58
|
},
|
|
63
59
|
});
|