@hubspot/cli 8.2.0-experimental.1 → 8.2.0-experimental.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/commands/account/auth.js +2 -0
  2. package/commands/app/logs.js +4 -0
  3. package/commands/getStarted.js +2 -0
  4. package/commands/init.js +2 -0
  5. package/commands/mcp/setup.js +2 -2
  6. package/commands/project/create.js +2 -0
  7. package/commands/project/installApp.d.ts +7 -0
  8. package/commands/project/installApp.js +181 -0
  9. package/commands/project/installDeps.js +2 -0
  10. package/commands/project/upload.js +4 -0
  11. package/commands/project.js +2 -0
  12. package/commands/upgrade.js +2 -0
  13. package/lang/en.d.ts +58 -0
  14. package/lang/en.js +71 -2
  15. package/lib/accountTargetDiscovery.d.ts +15 -0
  16. package/lib/accountTargetDiscovery.js +175 -0
  17. package/lib/app/install.d.ts +22 -0
  18. package/lib/app/install.js +42 -0
  19. package/lib/app/logs.js +1 -1
  20. package/lib/auth/awaitPersonalAccessKeyOverWebsocket.js +3 -2
  21. package/lib/doctor/Doctor.d.ts +1 -0
  22. package/lib/doctor/Doctor.js +26 -0
  23. package/lib/mcp/clients.d.ts +13 -0
  24. package/lib/mcp/clients.js +55 -0
  25. package/lib/mcp/promotion.d.ts +3 -0
  26. package/lib/mcp/promotion.js +109 -0
  27. package/lib/mcp/setup.d.ts +3 -2
  28. package/lib/mcp/setup.js +17 -12
  29. package/lib/projects/installApp.d.ts +58 -0
  30. package/lib/projects/installApp.js +278 -0
  31. package/lib/projects/localDev/AppDevModeInterface.d.ts +0 -3
  32. package/lib/projects/localDev/AppDevModeInterface.js +22 -44
  33. package/lib/projects/localDev/helpers/project.d.ts +4 -3
  34. package/lib/projects/localDev/helpers/project.js +46 -12
  35. package/lib/prompts/projectDevTargetAccountPrompt.js +3 -2
  36. package/lib/theme/cmsDevServerProcess.js +1 -1
  37. package/lib/usageTracking.d.ts +1 -0
  38. package/lib/usageTracking.js +9 -0
  39. package/mcp-server/tools/project/CreateTestAccountTool.js +1 -1
  40. package/package.json +4 -4
  41. package/types/AccountTargets.d.ts +37 -0
  42. package/types/AccountTargets.js +12 -0
  43. package/types/LocalDev.d.ts +3 -2
  44. package/types/ProjectComponents.d.ts +2 -1
  45. package/types/Projects.d.ts +5 -0
@@ -11,6 +11,7 @@ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
11
11
  import { commands } from '../../lang/en.js';
12
12
  import { uiLogger } from '../../lib/ui/logger.js';
13
13
  import { authenticateNewAccount } from '../../lib/accountAuth.js';
14
+ import { showMcpPromotionNudge } from '../../lib/mcp/promotion.js';
14
15
  const TRACKING_STATUS = {
15
16
  STARTED: 'started',
16
17
  ERROR: 'error',
@@ -56,6 +57,7 @@ async function handler(args) {
56
57
  'accountAuthCommand',
57
58
  'accountsListCommand',
58
59
  ]);
60
+ await showMcpPromotionNudge(args._.join(' '));
59
61
  if (!disableTracking) {
60
62
  await trackAuthAction('account-auth', authType, TRACKING_STATUS.COMPLETE, accountId);
61
63
  }
@@ -6,6 +6,7 @@ import { selectAppPrompt } from '../../lib/prompts/selectAppPrompt.js';
6
6
  import { listPrompt } from '../../lib/prompts/promptUtils.js';
7
7
  import { getTypeChoices, handleLogsRequest, SYSTEM_TYPE_CHOICES, tailAppLogs, toSystemType, } from '../../lib/app/logs.js';
8
8
  import { logError } from '../../lib/errorHandlers/index.js';
9
+ import { showMcpPromotionNudge } from '../../lib/mcp/promotion.js';
9
10
  const command = 'logs';
10
11
  const describe = commands.app.subcommands.logs.describe;
11
12
  const handler = async (options) => {
@@ -37,6 +38,9 @@ const handler = async (options) => {
37
38
  }
38
39
  else {
39
40
  await handleLogsRequest(derivedAccountId, appId, systemType, options);
41
+ if (!options.json) {
42
+ await showMcpPromotionNudge(options._.join(' '));
43
+ }
40
44
  }
41
45
  return exit(EXIT_CODES.SUCCESS);
42
46
  }
@@ -24,6 +24,7 @@ import ProjectValidationError from '../lib/errors/ProjectValidationError.js';
24
24
  import { openLink } from '../lib/links.js';
25
25
  import { runGetStartedV2 } from '../lib/getStarted/getStartedV2.js';
26
26
  import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
27
+ import { showMcpPromotionNudge } from '../lib/mcp/promotion.js';
27
28
  const command = 'get-started';
28
29
  const describe = commands.getStarted.describe;
29
30
  async function handler(args) {
@@ -275,6 +276,7 @@ async function handler(args) {
275
276
  return exit(EXIT_CODES.SUCCESS);
276
277
  }
277
278
  }
279
+ await showMcpPromotionNudge(args._.join(' '));
278
280
  // Track successful completion of get-started command
279
281
  await trackCommandMetadataUsage('get-started', {
280
282
  successful: true,
package/commands/init.js CHANGED
@@ -24,6 +24,7 @@ import { makeWrappedYargsHandler } from '../lib/yargs/makeWrappedYargsHandler.js
24
24
  import { uiLogger } from '../lib/ui/logger.js';
25
25
  import { commands } from '../lang/en.js';
26
26
  import { parseStringToNumber } from '../lib/parsing.js';
27
+ import { showMcpPromotionNudge } from '../lib/mcp/promotion.js';
27
28
  const TRACKING_STATUS = {
28
29
  STARTED: 'started',
29
30
  ERROR: 'error',
@@ -142,6 +143,7 @@ async function handler(args) {
142
143
  'authCommand',
143
144
  'accountsListCommand',
144
145
  ]);
146
+ await showMcpPromotionNudge(args._.join(' '));
145
147
  if (!disableTracking) {
146
148
  await trackAuthAction('init', authType, TRACKING_STATUS.COMPLETE, accountId);
147
149
  }
@@ -2,13 +2,13 @@ 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 { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
5
- import { addMcpServerToConfig, supportedTools } from '../../lib/mcp/setup.js';
5
+ import { configureMcpServer, supportedTools } from '../../lib/mcp/setup.js';
6
6
  const command = ['setup'];
7
7
  const describe = commands.mcp.setup.describe;
8
8
  async function handler(args) {
9
9
  const { exit } = args;
10
10
  try {
11
- await addMcpServerToConfig(args.client);
11
+ await configureMcpServer(args.client);
12
12
  }
13
13
  catch (e) {
14
14
  return exit(EXIT_CODES.ERROR);
@@ -17,6 +17,7 @@ import { uiLogger } from '../../lib/ui/logger.js';
17
17
  import { handleProjectCreationFlow, } from '../../lib/projects/create/index.js';
18
18
  import { updateHsMetaFilesWithAutoGeneratedFields } from '../../lib/projects/components.js';
19
19
  import SpinniesManager from '../../lib/ui/SpinniesManager.js';
20
+ import { showMcpPromotionNudge } from '../../lib/mcp/promotion.js';
20
21
  const command = ['create', 'init'];
21
22
  const describe = commands.project.create.describe;
22
23
  const BETA_VERSIONS = [
@@ -107,6 +108,7 @@ async function handler(args) {
107
108
  if (isProjectEmpty) {
108
109
  fs.ensureDirSync(path.join(projectDest, 'src'));
109
110
  }
111
+ await showMcpPromotionNudge(args._.join(' '));
110
112
  return exit(EXIT_CODES.SUCCESS);
111
113
  }
112
114
  function projectCreateBuilder(yargs) {
@@ -0,0 +1,7 @@
1
+ import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
+ type ProjectInstallAppArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & JSONOutputArgs & {
3
+ force: boolean;
4
+ profile?: string;
5
+ };
6
+ declare const projectInstallAppCommand: YargsCommandModule<unknown, ProjectInstallAppArgs>;
7
+ export default projectInstallAppCommand;
@@ -0,0 +1,181 @@
1
+ import { getConfigAccountIfExists } from '@hubspot/local-dev-lib/config';
2
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
3
+ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
4
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
5
+ import { uiLogger } from '../../lib/ui/logger.js';
6
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
7
+ import { commands } from '../../lang/en.js';
8
+ import { getProjectConfig } from '../../lib/projects/config.js';
9
+ import { APP_INSTALLATION_STATES } from '../../lib/constants.js';
10
+ import { getAppInstallationState } from '../../lib/app/install.js';
11
+ import { confirmInstallAppAction, fetchProjectAppInstallationData, installStaticAuthAppForAccount, loadInstallableAppNode, resolveAppMetadata, resolveProjectId, resolveProjectAccountId, resolveValidInstallAccount, } from '../../lib/projects/installApp.js';
12
+ const command = 'install-app';
13
+ const describe = commands.project.installApp.describe;
14
+ const verboseDescribe = commands.project.installApp.verboseDescribe;
15
+ async function handler(args) {
16
+ const { derivedAccountId, formatOutputAsJson, force, profile: profileOption, useEnv: useEnvOption, exit, } = args;
17
+ const { projectConfig, projectDir } = await getProjectConfig();
18
+ if (!projectConfig || !projectDir) {
19
+ uiLogger.error(commands.project.installApp.errors.noProjectConfig);
20
+ return exit(EXIT_CODES.ERROR);
21
+ }
22
+ if (isLegacyProject(projectConfig.platformVersion)) {
23
+ uiLogger.error(commands.project.installApp.errors.unsupportedPlatformVersion(projectConfig.platformVersion));
24
+ return exit(EXIT_CODES.ERROR);
25
+ }
26
+ const resolvedProjectAccount = await resolveProjectAccountId(derivedAccountId, projectConfig, projectDir, profileOption, !!useEnvOption);
27
+ if (resolvedProjectAccount === null) {
28
+ return exit(EXIT_CODES.ERROR);
29
+ }
30
+ const appNode = await loadInstallableAppNode(projectConfig, projectDir, resolvedProjectAccount.accountId);
31
+ if (!appNode) {
32
+ return exit(EXIT_CODES.ERROR);
33
+ }
34
+ const installAccountId = await resolveValidInstallAccount(resolvedProjectAccount.accountId, force, Boolean(formatOutputAsJson));
35
+ if (installAccountId === null) {
36
+ return exit(EXIT_CODES.ERROR);
37
+ }
38
+ const targetAccountConfig = getConfigAccountIfExists(installAccountId);
39
+ // A profile only applies if we didn't switch away from its account.
40
+ const uploadProfile = installAccountId === resolvedProjectAccount.accountId
41
+ ? resolvedProjectAccount.profileName
42
+ : undefined;
43
+ const projectId = await resolveProjectId({
44
+ accountId: installAccountId,
45
+ projectConfig,
46
+ projectDir,
47
+ profile: uploadProfile,
48
+ force,
49
+ formatOutputAsJson: Boolean(formatOutputAsJson),
50
+ });
51
+ if (projectId === null) {
52
+ return exit(EXIT_CODES.ERROR);
53
+ }
54
+ const installationData = await fetchProjectAppInstallationData(installAccountId, projectId, appNode, projectConfig);
55
+ if (installationData === null) {
56
+ return exit(EXIT_CODES.ERROR);
57
+ }
58
+ let appId = installationData.appId;
59
+ const { isInstalledWithScopeGroups, previouslyAuthorizedScopeGroups } = installationData;
60
+ const needsReinstall = !isInstalledWithScopeGroups && previouslyAuthorizedScopeGroups.length > 0;
61
+ const installationState = getAppInstallationState(isInstalledWithScopeGroups, previouslyAuthorizedScopeGroups);
62
+ if (isInstalledWithScopeGroups) {
63
+ if (formatOutputAsJson) {
64
+ uiLogger.json({
65
+ appId,
66
+ appUid: appNode.uid,
67
+ accountId: installAccountId,
68
+ projectId,
69
+ installationState,
70
+ installed: true,
71
+ reinstalled: false,
72
+ });
73
+ }
74
+ else {
75
+ uiLogger.success(commands.project.installApp.alreadyInstalled(appNode.config.name, installAccountId));
76
+ }
77
+ return exit(EXIT_CODES.SUCCESS);
78
+ }
79
+ const shouldInstall = await confirmInstallAppAction({
80
+ appName: appNode.config.name,
81
+ targetAccountId: installAccountId,
82
+ force,
83
+ needsReinstall,
84
+ });
85
+ if (!shouldInstall) {
86
+ return exit(EXIT_CODES.SUCCESS);
87
+ }
88
+ const metadata = await resolveAppMetadata({
89
+ appId,
90
+ projectId,
91
+ appUid: appNode.uid,
92
+ appName: appNode.config.name,
93
+ accountId: installAccountId,
94
+ projectConfig,
95
+ projectDir,
96
+ profile: uploadProfile,
97
+ force,
98
+ formatOutputAsJson: Boolean(formatOutputAsJson),
99
+ });
100
+ if (metadata === null) {
101
+ return exit(EXIT_CODES.ERROR);
102
+ }
103
+ appId = metadata.appId;
104
+ const installed = await installStaticAuthAppForAccount({
105
+ appId,
106
+ appNode,
107
+ appName: appNode.config.name,
108
+ targetAccountId: installAccountId,
109
+ targetAccountConfig,
110
+ projectId,
111
+ projectName: projectConfig.name,
112
+ scopeGroupIds: metadata.scopeGroupIds,
113
+ ownerPortalId: metadata.ownerPortalId,
114
+ installationState,
115
+ formatOutputAsJson: Boolean(formatOutputAsJson),
116
+ });
117
+ if (!installed) {
118
+ return exit(EXIT_CODES.ERROR);
119
+ }
120
+ if (formatOutputAsJson) {
121
+ uiLogger.json({
122
+ appId,
123
+ appUid: appNode.uid,
124
+ accountId: installAccountId,
125
+ projectId,
126
+ installationState: APP_INSTALLATION_STATES.INSTALLED,
127
+ installed: true,
128
+ reinstalled: needsReinstall,
129
+ });
130
+ }
131
+ else {
132
+ uiLogger.success(commands.project.installApp.success(appNode.config.name, installAccountId));
133
+ }
134
+ return exit(EXIT_CODES.SUCCESS);
135
+ }
136
+ function projectInstallAppBuilder(yargs) {
137
+ yargs.options({
138
+ force: {
139
+ alias: ['f'],
140
+ describe: commands.project.installApp.options.force,
141
+ default: false,
142
+ type: 'boolean',
143
+ },
144
+ profile: {
145
+ alias: 'p',
146
+ describe: commands.project.installApp.options.profile,
147
+ type: 'string',
148
+ },
149
+ });
150
+ yargs.conflicts('profile', 'account');
151
+ yargs.example([
152
+ ['$0 project install-app', commands.project.installApp.examples.default],
153
+ [
154
+ '$0 project install-app --account=12345678',
155
+ commands.project.installApp.examples.withAccount,
156
+ ],
157
+ [
158
+ '$0 project install-app --profile=qa',
159
+ commands.project.installApp.examples.withProfile,
160
+ ],
161
+ [
162
+ '$0 project install-app --json',
163
+ commands.project.installApp.examples.json,
164
+ ],
165
+ ]);
166
+ return yargs;
167
+ }
168
+ const builder = makeYargsBuilder(projectInstallAppBuilder, command, verboseDescribe, {
169
+ useGlobalOptions: true,
170
+ useConfigOptions: true,
171
+ useAccountOptions: true,
172
+ useEnvironmentOptions: true,
173
+ useJSONOutputOptions: true,
174
+ });
175
+ const projectInstallAppCommand = {
176
+ command,
177
+ describe,
178
+ handler: makeWrappedYargsHandler('project-install-app', handler),
179
+ builder,
180
+ };
181
+ export default projectInstallAppCommand;
@@ -9,6 +9,7 @@ import { uiLogger } from '../../lib/ui/logger.js';
9
9
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
10
10
  import { logError } from '../../lib/errorHandlers/index.js';
11
11
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
12
+ import { showMcpPromotionNudge } from '../../lib/mcp/promotion.js';
12
13
  const command = 'install-deps [packages..]';
13
14
  const describe = commands.project.installDeps.help.describe;
14
15
  async function handler(args) {
@@ -48,6 +49,7 @@ async function handler(args) {
48
49
  packages,
49
50
  installLocations,
50
51
  });
52
+ await showMcpPromotionNudge(args._.join(' '));
51
53
  }
52
54
  catch (e) {
53
55
  if (isPromptExitError(e)) {
@@ -16,6 +16,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
16
16
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
17
17
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
18
18
  import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
19
+ import { showMcpPromotionNudge } from '../../lib/mcp/promotion.js';
19
20
  const command = 'upload';
20
21
  const describe = commands.project.upload.describe;
21
22
  async function handlePreview(accountId, projectId, buildId, targetPortalId) {
@@ -144,6 +145,9 @@ async function handler(args) {
144
145
  if (formatOutputAsJson) {
145
146
  uiLogger.json(jsonOutput);
146
147
  }
148
+ else {
149
+ await showMcpPromotionNudge(args._.join(' '));
150
+ }
147
151
  return exit(EXIT_CODES.SUCCESS);
148
152
  }
149
153
  function projectUploadBuilder(yargs) {
@@ -21,6 +21,7 @@ import list from './project/list.js';
21
21
  import info from './project/info.js';
22
22
  import deleteProject from './project/delete.js';
23
23
  import appInstallStatus from './project/appInstallStatus.js';
24
+ import installApp from './project/installApp.js';
24
25
  import { makeYargsBuilder } from '../lib/yargsUtils.js';
25
26
  import { getProjectConfig } from '../lib/projects/config.js';
26
27
  import { isSupportedPlatformVersion, LATEST_SUPPORTED_PLATFORM_VERSION, } from '@hubspot/project-parsing-lib/projects';
@@ -70,6 +71,7 @@ function projectBuilder(yargs) {
70
71
  .command(release)
71
72
  .command(projectValidate)
72
73
  .command(appInstallStatus)
74
+ .command(installApp)
73
75
  .demandCommand(1, '');
74
76
  return yargs;
75
77
  }
@@ -11,6 +11,7 @@ import { getLatestCliVersion } from '../lib/cliUpgradeUtils.js';
11
11
  import { pkg } from '../lib/jsonLoader.js';
12
12
  import SpinniesManager from '../lib/ui/SpinniesManager.js';
13
13
  import { debugError } from '../lib/errorHandlers/index.js';
14
+ import { showMcpPromotionNudge } from '../lib/mcp/promotion.js';
14
15
  const command = ['upgrade [version]', 'update [version]'];
15
16
  const describe = commands.upgrade.describe;
16
17
  const handler = async (args) => {
@@ -84,6 +85,7 @@ const handler = async (args) => {
84
85
  uiLogger.log('');
85
86
  uiLogger.log(commands.upgrade.autoUpgradeMessage);
86
87
  }
88
+ await showMcpPromotionNudge(args._.join(' '));
87
89
  return exit(EXIT_CODES.SUCCESS);
88
90
  };
89
91
  function upgradeBuilder(yargs) {
package/lang/en.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
+ import { LocallyChangedComponents } from '../types/Projects.js';
2
3
  export declare const commands: {
3
4
  generalErrors: {
4
5
  srcIsProject: (src: string, command: string) => string;
@@ -1315,6 +1316,9 @@ export declare const commands: {
1315
1316
  };
1316
1317
  mcp: {
1317
1318
  describe: string;
1319
+ promotion: {
1320
+ activeNudge: string;
1321
+ };
1318
1322
  setup: {
1319
1323
  describe: string;
1320
1324
  installingDocSearch: string;
@@ -2167,6 +2171,47 @@ export declare const commands: {
2167
2171
  force: string;
2168
2172
  };
2169
2173
  };
2174
+ installApp: {
2175
+ describe: string;
2176
+ verboseDescribe: string;
2177
+ examples: {
2178
+ default: string;
2179
+ withAccount: string;
2180
+ withProfile: string;
2181
+ json: string;
2182
+ };
2183
+ options: {
2184
+ force: string;
2185
+ profile: string;
2186
+ };
2187
+ errors: {
2188
+ noProjectConfig: string;
2189
+ unsupportedPlatformVersion: (platformVersion: string) => string;
2190
+ failedToParseProject: string;
2191
+ noAppInProject: string;
2192
+ unsupportedAuthType: (authType: string) => string;
2193
+ unsupportedDistribution: (distribution: string) => string;
2194
+ invalidAppDeveloperAccount: (accountId: number) => string;
2195
+ projectNotFound: (accountId: number, projectName: string) => string;
2196
+ appNotDeployed: (appName: string, accountId: number) => string;
2197
+ automaticInstallUnavailable: (appName: string, accountId: number) => string;
2198
+ installFailed: (appName: string, accountId: number) => string;
2199
+ };
2200
+ jsonErrors: {
2201
+ automaticInstallUnavailable: string;
2202
+ installFailed: (appName: string, accountId: number) => string;
2203
+ };
2204
+ profileMessage: (profileName: string, accountId: number) => string;
2205
+ appDeveloperAccountNotice: (accountId: number) => string;
2206
+ selectInstallAccountPrompt: string;
2207
+ uploadAndDeployPrompt: (accountId: number) => string;
2208
+ alreadyInstalled: (appName: string, accountId: number) => string;
2209
+ outdatedScopes: (appName: string, accountId: number) => string;
2210
+ reinstallPrompt: string;
2211
+ installPrompt: (appName: string, accountId: number) => string;
2212
+ installFromBrowser: (installUrl: string) => string;
2213
+ success: (appName: string, accountId: number) => string;
2214
+ };
2170
2215
  installStatus: {
2171
2216
  describe: string;
2172
2217
  examples: {
@@ -3268,6 +3313,11 @@ export declare const lib: {
3268
3313
  configMiddleWare: {
3269
3314
  invalidAccountIdEnvironmentVariable: string;
3270
3315
  };
3316
+ accountTargetDiscovery: {
3317
+ errors: {
3318
+ explicitAccountNotFound: (account: string | number) => string;
3319
+ };
3320
+ };
3271
3321
  process: {
3272
3322
  exitDebug: (signal: string) => string;
3273
3323
  };
@@ -3394,7 +3444,9 @@ export declare const lib: {
3394
3444
  checking: string;
3395
3445
  upToDate: string;
3396
3446
  notUpToDate: string;
3447
+ changedFiles: (changed: LocallyChangedComponents) => string;
3397
3448
  notUpToDateExplanation: (profile?: string) => string;
3449
+ unableToCompare: string;
3398
3450
  };
3399
3451
  createNewProjectForLocalDev: {
3400
3452
  projectMustExistExplanation: (projectName: string, accountId: number) => string;
@@ -3834,6 +3886,7 @@ export declare const lib: {
3834
3886
  confirmUseExistingDeveloperTestAccount: (accountName: string) => string;
3835
3887
  confirmLinkExistingDeveloperTestAccount: (accountName: string) => string;
3836
3888
  noAccountId: string;
3889
+ fetchDeveloperTestAccountsError: string;
3837
3890
  };
3838
3891
  projectLogsPrompt: {
3839
3892
  functionName: (projectName: string) => string;
@@ -4238,6 +4291,11 @@ export declare const lib: {
4238
4291
  installed: (npmVersion: string) => string;
4239
4292
  unableToDetermine: string;
4240
4293
  };
4294
+ mcpChecks: {
4295
+ configured: (clients: string[]) => string;
4296
+ notConfigured: (clients: string[]) => string;
4297
+ notConfiguredSecondary: string;
4298
+ };
4241
4299
  hsChecks: {
4242
4300
  notLatest: (hsVersion: string) => string;
4243
4301
  notLatestSecondary: (command: string, hsVersion: string) => string;
package/lang/en.js CHANGED
@@ -1325,8 +1325,11 @@ export const commands = {
1325
1325
  },
1326
1326
  mcp: {
1327
1327
  describe: 'Commands for managing HubSpot MCP servers.',
1328
+ promotion: {
1329
+ activeNudge: `${chalk.bold('Tip:')} Work faster with AI coding tools. Run ${uiCommandReference('hs mcp setup')} to connect HubSpot developer context to supported clients.`,
1330
+ },
1328
1331
  setup: {
1329
- describe: 'Setup the HubSpot development MCP servers.',
1332
+ describe: `Run ${uiCommandReference('hs mcp setup')} to connect the HubSpot Dev MCP and work faster with your AI coding tools.`,
1330
1333
  installingDocSearch: 'Adding the docs-search mcp server',
1331
1334
  codex: 'Codex CLI',
1332
1335
  claudeCode: 'Claude Code',
@@ -2192,6 +2195,47 @@ export const commands = {
2192
2195
  force: 'skip confirmation prompt',
2193
2196
  },
2194
2197
  },
2198
+ installApp: {
2199
+ describe: 'Install a static auth app from the current project into the target account',
2200
+ verboseDescribe: `Install a static auth app from the current project into the target account.\n\nRun this command from within the project directory. The project must contain a privately distributed static auth app and must already be uploaded to the target account.`,
2201
+ examples: {
2202
+ default: 'Install the static auth app from the current project',
2203
+ withAccount: 'Install the app into a specific account',
2204
+ withProfile: 'Install the app into the account targeted by a profile',
2205
+ json: 'Output install result as JSON',
2206
+ },
2207
+ options: {
2208
+ force: 'Skip confirmation prompts',
2209
+ profile: 'The profile to target with this install',
2210
+ },
2211
+ errors: {
2212
+ noProjectConfig: `No project config found. Run this command from within a HubSpot project directory, or use ${uiCommandReference('hs project create')} to create a new one.`,
2213
+ unsupportedPlatformVersion: (platformVersion) => `This command is only supported for projects on platform version 2025.2 or later (detected: ${platformVersion}).`,
2214
+ failedToParseProject: 'Failed to parse the project. Check your project configuration is valid and try again.',
2215
+ noAppInProject: 'No app was found in the local project. This command requires a project that contains an app.',
2216
+ unsupportedAuthType: (authType) => `This command only supports static auth apps. Detected auth type: ${authType}.`,
2217
+ unsupportedDistribution: (distribution) => `This command only supports privately distributed apps. Detected distribution: ${distribution}.`,
2218
+ invalidAppDeveloperAccount: (accountId) => `Static auth apps can't be installed into the app developer account ${uiAccountDescription(accountId)}. Switch to a standard, sandbox, or developer test account with ${uiCommandReference('hs account use')}, or pass ${uiCommandReference('--account')}.`,
2219
+ projectNotFound: (accountId, projectName) => `The project ${chalk.bold(projectName)} does not exist in ${uiAccountDescription(accountId)}. Run ${uiCommandReference('hs project upload')} to upload your project files to HubSpot.`,
2220
+ appNotDeployed: (appName, accountId) => `The app ${chalk.bold(appName)} has not been deployed to ${uiAccountDescription(accountId)}. Upload the project with ${uiCommandReference('hs project upload')} and ensure the build succeeds, then try again.`,
2221
+ automaticInstallUnavailable: (appName, accountId) => `${chalk.bold(appName)} could not be installed automatically in ${uiAccountDescription(accountId)}.`,
2222
+ installFailed: (appName, accountId) => `Failed to install ${chalk.bold(appName)} in ${uiAccountDescription(accountId)}.`,
2223
+ },
2224
+ jsonErrors: {
2225
+ automaticInstallUnavailable: 'Automatic install is unavailable for this account.',
2226
+ installFailed: (appName, accountId) => `Failed to install ${appName} in account ${accountId}.`,
2227
+ },
2228
+ profileMessage: (profileName, accountId) => `Installing with ${chalk.bold(profileName)} profile: ${uiAccountDescription(accountId)}`,
2229
+ appDeveloperAccountNotice: (accountId) => `${uiAccountDescription(accountId)} is an app developer account, which can't have apps installed into it.`,
2230
+ selectInstallAccountPrompt: 'Select an account to install the app into',
2231
+ uploadAndDeployPrompt: (accountId) => `The app isn't deployed to ${uiAccountDescription(accountId)} yet. Upload and deploy the project now?`,
2232
+ alreadyInstalled: (appName, accountId) => `${chalk.bold(appName)} is already installed in ${uiAccountDescription(accountId)}.`,
2233
+ outdatedScopes: (appName, accountId) => `${chalk.bold(appName)} is installed in ${uiAccountDescription(accountId)} with outdated scopes.`,
2234
+ reinstallPrompt: 'Reinstall the app to grant the latest scopes?',
2235
+ installPrompt: (appName, accountId) => `Install ${chalk.bold(appName)} in ${uiAccountDescription(accountId)}?`,
2236
+ installFromBrowser: (installUrl) => `Install the app in HubSpot: ${uiLink('Open install page', installUrl)}`,
2237
+ success: (appName, accountId) => `${chalk.bold(appName)} installed in ${uiAccountDescription(accountId)}.`,
2238
+ },
2195
2239
  installStatus: {
2196
2240
  describe: 'Check whether a static auth app in the current project is installed in the target account. This command must be run from within a HubSpot project directory.',
2197
2241
  examples: {
@@ -2632,7 +2676,7 @@ export const commands = {
2632
2676
  serviceLevel: 'Service Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
2633
2677
  salesLevel: 'Sales Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
2634
2678
  contentLevel: 'Content Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
2635
- commerceLevel: 'Commerce Hub tier. Options: FREE, PROFESSIONAL, ENTERPRISE',
2679
+ commerceLevel: 'Revenue Hub tier. Options: FREE, PROFESSIONAL, ENTERPRISE',
2636
2680
  },
2637
2681
  example: (configPath) => `Create a test account from the config file at ${configPath}`,
2638
2682
  examples: {
@@ -3293,6 +3337,11 @@ export const lib = {
3293
3337
  configMiddleWare: {
3294
3338
  invalidAccountIdEnvironmentVariable: 'Unable to parse `HUBSPOT_ACCOUNT_ID` environment variable into a number',
3295
3339
  },
3340
+ accountTargetDiscovery: {
3341
+ errors: {
3342
+ explicitAccountNotFound: (account) => `Account ${chalk.bold(String(account))} was not found in your config. Run ${uiCommandReference('hs account list')} to see available accounts.`,
3343
+ },
3344
+ },
3296
3345
  process: {
3297
3346
  exitDebug: (signal) => `Attempting to gracefully exit. Triggered by ${signal}`,
3298
3347
  },
@@ -3419,7 +3468,21 @@ export const lib = {
3419
3468
  checking: 'Checking if your deployed build is up to date...',
3420
3469
  upToDate: 'Deployed build is up to date.',
3421
3470
  notUpToDate: `Your project contains undeployed local changes.`,
3471
+ changedFiles: (changed) => {
3472
+ const sections = [];
3473
+ if (changed.added.length > 0) {
3474
+ sections.push(`${chalk.bold('Features Added:')}\n${changed.added.map(f => ` - ${f}`).join('\n')}`);
3475
+ }
3476
+ if (changed.updated.length > 0) {
3477
+ sections.push(`${chalk.bold('Features Modified:')}\n${changed.updated.map(f => ` - ${f}`).join('\n')}`);
3478
+ }
3479
+ if (changed.removed.length > 0) {
3480
+ sections.push(`${chalk.bold('Features Removed:')}\n${changed.removed.map(f => ` - ${f}`).join('\n')}`);
3481
+ }
3482
+ return sections.join('\n\n');
3483
+ },
3422
3484
  notUpToDateExplanation: (profile) => `Run ${uiCommandReference(`hs project upload${profile ? ` --profile ${profile}` : ''}`)} to upload these changes to HubSpot, then re-run ${uiCommandReference(`hs project dev${profile ? ` --profile ${profile}` : ''}`)} to continue local development.`,
3485
+ unableToCompare: `Unable to check if local *-hsmeta.json files match the deployed build. Run ${uiCommandReference('hs project upload')} to upload any local changes before continuing.`,
3423
3486
  },
3424
3487
  createNewProjectForLocalDev: {
3425
3488
  projectMustExistExplanation: (projectName, accountId) => `The project ${projectName} does not exist in the target account ${uiAccountDescription(accountId)}. This command requires the project to exist in the target account.`,
@@ -3859,6 +3922,7 @@ export const lib = {
3859
3922
  confirmUseExistingDeveloperTestAccount: (accountName) => `Continue with ${accountName}? This account isn't currently connected to the HubSpot CLI. By continuing, you'll be prompted to generate a personal access key and connect it.`,
3860
3923
  confirmLinkExistingDeveloperTestAccount: (accountName) => `${accountName} is not linked to this directory. Would you like to link it?`,
3861
3924
  noAccountId: 'No account ID found for the selected account. Please try again.',
3925
+ fetchDeveloperTestAccountsError: 'Unable to fetch developer test accounts. Please try again.',
3862
3926
  },
3863
3927
  projectLogsPrompt: {
3864
3928
  functionName: (projectName) => `[--function] Select function in ${chalk.bold(projectName)} project`,
@@ -4263,6 +4327,11 @@ export const lib = {
4263
4327
  installed: (npmVersion) => `npm v${npmVersion} is installed`,
4264
4328
  unableToDetermine: 'Unable to determine if npm is installed',
4265
4329
  },
4330
+ mcpChecks: {
4331
+ configured: (clients) => `HubSpot MCP server configured in ${clients.join(', ')}`,
4332
+ notConfigured: (clients) => `HubSpot MCP server not configured in ${clients.join(', ')}`,
4333
+ notConfiguredSecondary: `Run ${uiCommandReference('hs mcp setup')} to connect AI coding tools to HubSpot developer context`,
4334
+ },
4266
4335
  hsChecks: {
4267
4336
  notLatest: (hsVersion) => `Version ${hsVersion} outdated`,
4268
4337
  notLatestSecondary: (command, hsVersion) => `Run ${uiCommandReference(command)} to upgrade to the latest version ${hsVersion}`,
@@ -0,0 +1,15 @@
1
+ import { DiscoverAccountTargetsOptions, DiscoverAccountTargetsResult } from '../types/AccountTargets.js';
2
+ /**
3
+ * Discovers the candidate target accounts for a command, plus the recommended
4
+ * one to use when a single account is the obvious choice.
5
+ *
6
+ * Profiles take precedence: when the project defines profiles, the candidates
7
+ * are the profile accounts only. Otherwise they are ranked explicit account,
8
+ * then env config, then linked directory, then global default.
9
+ *
10
+ * Takes plain options (not yargs argv) and never prompts or exits, so both the
11
+ * CLI and MCP can call it. `recommended` is omitted when no account is the
12
+ * obvious choice (for example, several profiles). Throws when an explicit
13
+ * account is provided but not found in the config.
14
+ */
15
+ export declare function discoverAccountTargets(options?: DiscoverAccountTargetsOptions): Promise<DiscoverAccountTargetsResult>;