@hubspot/cli 8.0.11-experimental.1 → 8.0.12-experimental.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/api/migrate.js +3 -3
  2. package/bin/cli.js +3 -0
  3. package/commands/account/link.d.ts +4 -0
  4. package/commands/account/link.js +88 -0
  5. package/commands/account/unlink.d.ts +4 -0
  6. package/commands/account/unlink.js +69 -0
  7. package/commands/account.js +4 -0
  8. package/commands/app/migrate.js +4 -4
  9. package/commands/getStarted.js +2 -2
  10. package/commands/project/add.js +3 -3
  11. package/commands/project/appInstallStatus.d.ts +4 -0
  12. package/commands/project/appInstallStatus.js +132 -0
  13. package/commands/project/create.js +18 -7
  14. package/commands/project/delete.js +2 -2
  15. package/commands/project/deploy.js +4 -3
  16. package/commands/project/dev/index.js +5 -4
  17. package/commands/project/info.js +2 -2
  18. package/commands/project/lint.js +2 -1
  19. package/commands/project/migrate.js +5 -5
  20. package/commands/project/profile/add.js +2 -2
  21. package/commands/project/profile/delete.js +2 -2
  22. package/commands/project/upload.d.ts +2 -0
  23. package/commands/project/upload.js +38 -6
  24. package/commands/project/validate.js +2 -2
  25. package/commands/project/watch.js +2 -2
  26. package/commands/project.js +8 -3
  27. package/commands/testAccount/create.js +4 -4
  28. package/lang/en.d.ts +95 -0
  29. package/lang/en.js +108 -8
  30. package/lib/app/migrate.js +8 -0
  31. package/lib/doctor/Doctor.js +2 -2
  32. package/lib/getStartedV2Actions.js +2 -2
  33. package/lib/link/accountTableUtils.d.ts +10 -0
  34. package/lib/link/accountTableUtils.js +39 -0
  35. package/lib/link/index.d.ts +14 -0
  36. package/lib/link/index.js +154 -0
  37. package/lib/link/linkUtils.d.ts +4 -0
  38. package/lib/link/linkUtils.js +24 -0
  39. package/lib/link/prompts.d.ts +7 -0
  40. package/lib/link/prompts.js +126 -0
  41. package/lib/link/renderLinkedAccountsTable.d.ts +2 -0
  42. package/lib/link/renderLinkedAccountsTable.js +14 -0
  43. package/lib/projects/ProjectLogsManager.js +6 -3
  44. package/lib/projects/create/index.js +2 -2
  45. package/lib/projects/create/legacy.js +2 -2
  46. package/lib/projects/create/v2.js +2 -2
  47. package/lib/projects/delete.js +2 -2
  48. package/lib/projects/deploy.d.ts +1 -1
  49. package/lib/projects/deploy.js +2 -2
  50. package/lib/projects/preview.d.ts +7 -0
  51. package/lib/projects/preview.js +71 -0
  52. package/lib/projects/uieLinting.d.ts +8 -3
  53. package/lib/projects/uieLinting.js +48 -27
  54. package/lib/projects/upload.d.ts +1 -0
  55. package/lib/projects/upload.js +8 -7
  56. package/lib/prompts/projectsLogsPrompt.js +3 -0
  57. package/lib/prompts/promptUtils.js +1 -0
  58. package/lib/theme/cmsDevServerProcess.js +1 -1
  59. package/mcp-server/Tool.d.ts +15 -0
  60. package/mcp-server/Tool.js +53 -0
  61. package/mcp-server/server.js +39 -3
  62. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +4 -2
  63. package/mcp-server/tools/cms/HsCreateFunctionTool.js +8 -6
  64. package/mcp-server/tools/cms/HsCreateModuleTool.d.ts +4 -2
  65. package/mcp-server/tools/cms/HsCreateModuleTool.js +8 -6
  66. package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +4 -2
  67. package/mcp-server/tools/cms/HsCreateTemplateTool.js +8 -6
  68. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +4 -2
  69. package/mcp-server/tools/cms/HsFunctionLogsTool.js +8 -6
  70. package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +4 -2
  71. package/mcp-server/tools/cms/HsListFunctionsTool.js +8 -6
  72. package/mcp-server/tools/cms/HsListTool.d.ts +4 -2
  73. package/mcp-server/tools/cms/HsListTool.js +8 -6
  74. package/mcp-server/tools/index.d.ts +3 -2
  75. package/mcp-server/tools/index.js +22 -22
  76. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +6 -4
  77. package/mcp-server/tools/project/AddFeatureToProjectTool.js +8 -6
  78. package/mcp-server/tools/project/CreateProjectTool.d.ts +6 -4
  79. package/mcp-server/tools/project/CreateProjectTool.js +9 -7
  80. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +4 -2
  81. package/mcp-server/tools/project/CreateTestAccountTool.js +20 -8
  82. package/mcp-server/tools/project/DeployProjectTool.d.ts +4 -2
  83. package/mcp-server/tools/project/DeployProjectTool.js +4 -6
  84. package/mcp-server/tools/project/DocFetchTool.d.ts +4 -2
  85. package/mcp-server/tools/project/DocFetchTool.js +8 -6
  86. package/mcp-server/tools/project/DocsSearchTool.d.ts +9 -3
  87. package/mcp-server/tools/project/DocsSearchTool.js +32 -9
  88. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +4 -2
  89. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +8 -6
  90. package/mcp-server/tools/project/GetApplicationInfoTool.d.ts +4 -2
  91. package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
  92. package/mcp-server/tools/project/GetBuildLogsTool.d.ts +4 -2
  93. package/mcp-server/tools/project/GetBuildLogsTool.js +8 -6
  94. package/mcp-server/tools/project/GetBuildStatusTool.d.ts +4 -2
  95. package/mcp-server/tools/project/GetBuildStatusTool.js +8 -6
  96. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +4 -2
  97. package/mcp-server/tools/project/GetConfigValuesTool.js +12 -7
  98. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +4 -2
  99. package/mcp-server/tools/project/GuidedWalkthroughTool.js +4 -6
  100. package/mcp-server/tools/project/UploadProjectTools.d.ts +4 -2
  101. package/mcp-server/tools/project/UploadProjectTools.js +9 -7
  102. package/mcp-server/tools/project/ValidateProjectTool.d.ts +4 -2
  103. package/mcp-server/tools/project/ValidateProjectTool.js +8 -6
  104. package/mcp-server/tools/project/constants.d.ts +2 -2
  105. package/mcp-server/types.d.ts +0 -7
  106. package/mcp-server/types.js +1 -13
  107. package/mcp-server/utils/logger.d.ts +10 -0
  108. package/mcp-server/utils/logger.js +29 -0
  109. package/mcp-server/utils/toolUsageTracking.js +0 -2
  110. package/package.json +10 -10
  111. package/types/Link.d.ts +27 -0
  112. package/types/Link.js +1 -0
  113. package/types/Prompts.d.ts +1 -0
  114. package/lib/projects/platformVersion.d.ts +0 -9
  115. package/lib/projects/platformVersion.js +0 -39
package/api/migrate.js CHANGED
@@ -1,4 +1,4 @@
1
- import { PLATFORM_VERSIONS, } from '@hubspot/local-dev-lib/constants/projects';
1
+ import { PLATFORM_VERSIONS } from '@hubspot/project-parsing-lib/constants';
2
2
  import { http } from '@hubspot/local-dev-lib/http';
3
3
  const MIGRATIONS_API_PATH_V2 = 'dfs/migrations/v2';
4
4
  export const CLI_UNMIGRATABLE_REASONS = {
@@ -20,8 +20,8 @@ export async function listAppsForMigration(accountId, platformVersion, appId) {
20
20
  });
21
21
  }
22
22
  function mapPlatformVersionToEnum(platformVersion) {
23
- if (platformVersion === PLATFORM_VERSIONS.unstable) {
24
- return PLATFORM_VERSIONS.unstable.toUpperCase();
23
+ if (platformVersion === PLATFORM_VERSIONS.UNSTABLE) {
24
+ return PLATFORM_VERSIONS.UNSTABLE.toUpperCase();
25
25
  }
26
26
  const reformattedPlatformVersion = platformVersion
27
27
  .replaceAll('.', '_')
package/bin/cli.js CHANGED
@@ -35,6 +35,7 @@ import apiCommand from '../commands/api.js';
35
35
  import { uiLogger } from '../lib/ui/logger.js';
36
36
  import { initializeSpinniesManager } from '../lib/middleware/spinniesMiddleware.js';
37
37
  import { addCommandSuggestions } from '../lib/commandSuggestion.js';
38
+ import { pkg } from '../lib/jsonLoader.js';
38
39
  function getTerminalWidth() {
39
40
  const width = yargs().terminalWidth();
40
41
  if (width >= 100)
@@ -121,6 +122,8 @@ const argv = yargs(process.argv.slice(2))
121
122
  const argvWithSuggestions = addCommandSuggestions(argv)
122
123
  .help()
123
124
  .alias('h', 'help')
125
+ .version(pkg.version)
126
+ .alias('v', 'version')
124
127
  .recommendCommands()
125
128
  .demandCommand(1, '')
126
129
  .wrap(getTerminalWidth())
@@ -0,0 +1,4 @@
1
+ import { YargsCommandModule } from '../../types/Yargs.js';
2
+ import { LinkArgs } from '../../types/Link.js';
3
+ declare const linkCommand: YargsCommandModule<unknown, LinkArgs>;
4
+ export default linkCommand;
@@ -0,0 +1,88 @@
1
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
2
+ import { uiLogger } from '../../lib/ui/logger.js';
3
+ import { getAllConfigAccounts } from '@hubspot/local-dev-lib/config';
4
+ import { getCwd } from '@hubspot/local-dev-lib/path';
5
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
7
+ import { getDefaultAccountOverrideAccountId } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
8
+ import { checkAndAddHsFolderToGitignore } from '@hubspot/local-dev-lib/gitignore';
9
+ import { DEFAULT_HS_SETTINGS_PATH, EMPTY_HS_SETTINGS_FILE, } from '@hubspot/local-dev-lib/constants/config';
10
+ import { handleLinkFlow } from '../../lib/link/index.js';
11
+ import { hasDeprecatedConfigConflict, writeLinkedSettings, } from '../../lib/link/linkUtils.js';
12
+ import { renderLinkedAccountsTable } from '../../lib/link/renderLinkedAccountsTable.js';
13
+ import { commands } from '../../lang/en.js';
14
+ import { debugError } from '../../lib/errorHandlers/index.js';
15
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
16
+ const command = 'link';
17
+ // Hide the command until we're done testing and ready to make linking GA
18
+ // const describe = commands.account.subcommands.link.describe;
19
+ const describe = undefined;
20
+ async function handler(args) {
21
+ const { exit } = args;
22
+ if (hasDeprecatedConfigConflict(args._)) {
23
+ return exit(EXIT_CODES.ERROR);
24
+ }
25
+ const existingSettings = getHsSettingsFileIfExists();
26
+ const isNewFile = existingSettings === null;
27
+ if (isNewFile) {
28
+ uiLogger.log(commands.account.subcommands.link.linkingDirectory(getCwd()));
29
+ }
30
+ else {
31
+ uiLogger.log(commands.account.subcommands.link.managingLinkedAccounts(getCwd()));
32
+ }
33
+ uiLogger.log('');
34
+ const settingsFilePath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
35
+ uiLogger.log(commands.account.subcommands.link.settingsInfo(settingsFilePath));
36
+ uiLogger.log('');
37
+ const settings = isNewFile ? EMPTY_HS_SETTINGS_FILE : existingSettings;
38
+ const accounts = getAllConfigAccounts();
39
+ const accountOverrideId = getDefaultAccountOverrideAccountId(accounts);
40
+ if (settings.accounts.length !== 0) {
41
+ await renderLinkedAccountsTable(settings);
42
+ uiLogger.log('');
43
+ }
44
+ const result = await handleLinkFlow({
45
+ settings,
46
+ accountOverrideId,
47
+ args,
48
+ });
49
+ if (result.status === 'error') {
50
+ uiLogger.error(result.reason);
51
+ return exit(EXIT_CODES.ERROR);
52
+ }
53
+ if (result.status === 'noop') {
54
+ return exit(EXIT_CODES.SUCCESS);
55
+ }
56
+ const settingsPath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
57
+ if (!writeLinkedSettings(result.settings, settingsPath)) {
58
+ return exit(EXIT_CODES.ERROR);
59
+ }
60
+ try {
61
+ checkAndAddHsFolderToGitignore(settingsPath);
62
+ }
63
+ catch (e) {
64
+ debugError(e);
65
+ }
66
+ if (isNewFile) {
67
+ uiLogger.success(commands.account.subcommands.link.success.created(settingsPath));
68
+ }
69
+ else {
70
+ uiLogger.success(commands.account.subcommands.link.shared.savedToSettings(settingsPath));
71
+ }
72
+ return exit(EXIT_CODES.SUCCESS);
73
+ }
74
+ function linkBuilder(yargs) {
75
+ yargs.example([['$0 link']]);
76
+ return yargs;
77
+ }
78
+ const builder = makeYargsBuilder(linkBuilder, command, commands.account.subcommands.link.verboseDescribe, {
79
+ useGlobalOptions: true,
80
+ useConfigOptions: true,
81
+ });
82
+ const linkCommand = {
83
+ command,
84
+ describe,
85
+ handler: makeYargsHandlerWithUsageTracking('account-link', handler),
86
+ builder,
87
+ };
88
+ export default linkCommand;
@@ -0,0 +1,4 @@
1
+ import { YargsCommandModule } from '../../types/Yargs.js';
2
+ import { LinkArgs } from '../../types/Link.js';
3
+ declare const unlinkCommand: YargsCommandModule<unknown, LinkArgs>;
4
+ export default unlinkCommand;
@@ -0,0 +1,69 @@
1
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
2
+ import { uiLogger } from '../../lib/ui/logger.js';
3
+ import { getAllConfigAccounts } from '@hubspot/local-dev-lib/config';
4
+ import { getCwd } from '@hubspot/local-dev-lib/path';
5
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
+ import { getHsSettingsFileIfExists, getHsSettingsFilePath, } from '@hubspot/local-dev-lib/config/hsSettings';
7
+ import { ActionHandlers } from '../../lib/link/index.js';
8
+ import { hasDeprecatedConfigConflict, isDirectoryLinked, writeLinkedSettings, } from '../../lib/link/linkUtils.js';
9
+ import { commands } from '../../lang/en.js';
10
+ import { DEFAULT_HS_SETTINGS_PATH } from '@hubspot/local-dev-lib/constants/config';
11
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
12
+ const command = 'unlink';
13
+ // Hide the command until we're done testing and ready to make linking GA
14
+ // const describe = commands.account.subcommands.link.describe;
15
+ const describe = undefined;
16
+ async function handler(args) {
17
+ const { exit } = args;
18
+ if (hasDeprecatedConfigConflict(args._)) {
19
+ return exit(EXIT_CODES.ERROR);
20
+ }
21
+ const existingSettings = getHsSettingsFileIfExists();
22
+ if (!isDirectoryLinked(existingSettings)) {
23
+ const globalAccounts = getAllConfigAccounts();
24
+ uiLogger.log(commands.account.subcommands.link.shared.noLinkedAccounts);
25
+ uiLogger.log(commands.account.subcommands.link.shared.globalAccountsAvailable(globalAccounts.length));
26
+ uiLogger.log('');
27
+ uiLogger.log(commands.account.subcommands.link.shared.configurePrompt);
28
+ return exit(EXIT_CODES.SUCCESS);
29
+ }
30
+ uiLogger.log(commands.account.subcommands.link.managingLinkedAccounts(getCwd()));
31
+ uiLogger.log('');
32
+ const result = await ActionHandlers.unlink({
33
+ state: existingSettings,
34
+ context: {
35
+ globalAccountsList: getAllConfigAccounts(),
36
+ globalDefaultAccount: undefined,
37
+ accountOverrideId: null,
38
+ },
39
+ args,
40
+ });
41
+ if (result.status === 'error') {
42
+ uiLogger.error(result.reason);
43
+ return exit(EXIT_CODES.ERROR);
44
+ }
45
+ if (result.status === 'noop') {
46
+ return exit(EXIT_CODES.SUCCESS);
47
+ }
48
+ const settingsPath = getHsSettingsFilePath() || DEFAULT_HS_SETTINGS_PATH;
49
+ if (!writeLinkedSettings(result.settings, settingsPath)) {
50
+ return exit(EXIT_CODES.ERROR);
51
+ }
52
+ uiLogger.success(commands.account.subcommands.link.shared.savedToSettings(settingsPath));
53
+ return exit(EXIT_CODES.SUCCESS);
54
+ }
55
+ function unlinkBuilder(yargs) {
56
+ yargs.example([['$0 account unlink']]);
57
+ return yargs;
58
+ }
59
+ const builder = makeYargsBuilder(unlinkBuilder, command, commands.account.subcommands.unlink.verboseDescribe, {
60
+ useGlobalOptions: true,
61
+ useConfigOptions: true,
62
+ });
63
+ const unlinkCommand = {
64
+ command,
65
+ describe,
66
+ handler: makeYargsHandlerWithUsageTracking('account-unlink', handler),
67
+ builder,
68
+ };
69
+ export default unlinkCommand;
@@ -8,12 +8,16 @@ import remove from './account/remove.js';
8
8
  import clean from './account/clean.js';
9
9
  import createOverride from './account/createOverride.js';
10
10
  import removeOverride from './account/removeOverride.js';
11
+ import link from './account/link.js';
12
+ import unlink from './account/unlink.js';
11
13
  import { makeYargsBuilder } from '../lib/yargsUtils.js';
12
14
  const command = ['account', 'accounts'];
13
15
  const describe = commands.account.describe;
14
16
  function accountBuilder(yargs) {
15
17
  yargs
16
18
  .command(auth)
19
+ .command(link)
20
+ .command(unlink)
17
21
  .command(list)
18
22
  .command(rename)
19
23
  .command(use)
@@ -1,5 +1,5 @@
1
1
  import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
2
- import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
2
+ import { PLATFORM_VERSIONS } from '@hubspot/project-parsing-lib/constants';
3
3
  import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
4
4
  import { trackCommandMetadataUsage } from '../../lib/usageTracking.js';
5
5
  import { commands } from '../../lang/en.js';
@@ -9,7 +9,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
9
9
  import { migrateApp } from '../../lib/app/migrate.js';
10
10
  import { getIsInProject } from '../../lib/projects/config.js';
11
11
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
12
- const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
12
+ const { v2025_2, v2026_03_BETA, v2026_03 } = PLATFORM_VERSIONS;
13
13
  const command = 'migrate';
14
14
  const describe = commands.project.migrateApp.describe;
15
15
  export function handlerGenerator(commandTrackingName) {
@@ -29,7 +29,7 @@ export function handlerGenerator(commandTrackingName) {
29
29
  return exit(EXIT_CODES.ERROR);
30
30
  }
31
31
  args.platformVersion = unstable
32
- ? PLATFORM_VERSIONS.unstable
32
+ ? PLATFORM_VERSIONS.UNSTABLE
33
33
  : platformVersion;
34
34
  await migrateApp(derivedAccountId, args);
35
35
  }
@@ -67,7 +67,7 @@ function appMigrateBuilder(yargs) {
67
67
  },
68
68
  'platform-version': {
69
69
  type: 'string',
70
- choices: [v2025_2, v2026_03_beta, v2026_03],
70
+ choices: [v2025_2, v2026_03_BETA, v2026_03],
71
71
  default: v2026_03,
72
72
  },
73
73
  unstable: {
@@ -16,7 +16,6 @@ import { uiLogger } from '../lib/ui/logger.js';
16
16
  import { trackCommandMetadataUsage } from '../lib/usageTracking.js';
17
17
  import { makeYargsBuilder } from '../lib/yargsUtils.js';
18
18
  import { makeYargsHandlerWithUsageTracking } from '../lib/yargs/makeYargsHandlerWithUsageTracking.js';
19
- import { isV2Project } from '../lib/projects/platformVersion.js';
20
19
  import { pollProjectBuildAndDeploy } from '../lib/projects/pollProjectBuildAndDeploy.js';
21
20
  import { fetchPublicAppsForPortal } from '@hubspot/local-dev-lib/api/appsDev';
22
21
  import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
@@ -24,6 +23,7 @@ import { getStaticAuthAppInstallUrl } from '../lib/app/urls.js';
24
23
  import ProjectValidationError from '../lib/errors/ProjectValidationError.js';
25
24
  import { openLink } from '../lib/links.js';
26
25
  import { runGetStartedV2 } from '../lib/getStarted/getStartedV2.js';
26
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
27
27
  const command = 'get-started';
28
28
  const describe = commands.getStarted.describe;
29
29
  async function handler(args) {
@@ -204,7 +204,7 @@ async function handler(args) {
204
204
  uploadMessage: 'Initial upload from get-started command',
205
205
  forceCreate: true, // Auto-create project on HubSpot
206
206
  isUploadCommand: false,
207
- sendIR: isV2Project(newProjectConfig.platformVersion),
207
+ sendIR: !isLegacyProject(newProjectConfig.platformVersion),
208
208
  skipValidation: false,
209
209
  });
210
210
  if (uploadError) {
@@ -5,7 +5,7 @@ import { isPromptExitError } from '../../lib/errors/PromptExitError.js';
5
5
  import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
6
6
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
7
7
  import { commands } from '../../lang/en.js';
8
- import { isV2Project } from '../../lib/projects/platformVersion.js';
8
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
9
9
  import { legacyAddComponent } from '../../lib/projects/add/legacyAddComponent.js';
10
10
  import { v2AddComponent } from '../../lib/projects/add/v2AddComponent.js';
11
11
  import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../lib/constants.js';
@@ -20,8 +20,8 @@ async function handler(args) {
20
20
  uiLogger.error(commands.project.add.error.locationInProject);
21
21
  return exit(EXIT_CODES.ERROR);
22
22
  }
23
- const isV2ProjectCreate = isV2Project(projectConfig.platformVersion);
24
- if (isV2ProjectCreate) {
23
+ const isLegacyProjectCreate = isLegacyProject(projectConfig.platformVersion);
24
+ if (!isLegacyProjectCreate) {
25
25
  await v2AddComponent(args, projectDir, projectConfig, derivedAccountId);
26
26
  }
27
27
  else {
@@ -0,0 +1,4 @@
1
+ import { AccountArgs, CommonArgs, ConfigArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
+ type ProjectInstallStatusArgs = CommonArgs & ConfigArgs & AccountArgs & JSONOutputArgs;
3
+ declare const projectInstallStatusCommand: YargsCommandModule<unknown, ProjectInstallStatusArgs>;
4
+ export default projectInstallStatusCommand;
@@ -0,0 +1,132 @@
1
+ import path from 'path';
2
+ import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
3
+ import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
4
+ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
5
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
6
+ import { translateForLocalDev } from '@hubspot/project-parsing-lib/translate';
7
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
8
+ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
+ import { uiLogger } from '../../lib/ui/logger.js';
10
+ import { ApiErrorContext, debugError, logError, } from '../../lib/errorHandlers/index.js';
11
+ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
12
+ import { commands } from '../../lang/en.js';
13
+ import { getProjectConfig } from '../../lib/projects/config.js';
14
+ import { isAppIRNode } from '../../lib/projects/structure.js';
15
+ import { APP_AUTH_TYPES } from '../../lib/constants.js';
16
+ const command = 'app-install-status';
17
+ const describe = commands.project.installStatus.describe;
18
+ async function handler(args) {
19
+ const { derivedAccountId, formatOutputAsJson, exit } = args;
20
+ const { projectConfig, projectDir } = await getProjectConfig();
21
+ if (!projectConfig || !projectDir) {
22
+ uiLogger.error(commands.project.installStatus.errors.noProjectConfig);
23
+ return exit(EXIT_CODES.ERROR);
24
+ }
25
+ if (isLegacyProject(projectConfig.platformVersion)) {
26
+ uiLogger.error(commands.project.installStatus.errors.unsupportedPlatformVersion(projectConfig.platformVersion));
27
+ return exit(EXIT_CODES.ERROR);
28
+ }
29
+ let appNode;
30
+ try {
31
+ const { intermediateNodesIndexedByUid } = await translateForLocalDev({
32
+ projectSourceDir: path.join(projectDir, projectConfig.srcDir),
33
+ platformVersion: projectConfig.platformVersion,
34
+ accountId: derivedAccountId,
35
+ }, { skipValidation: true });
36
+ appNode = Object.values(intermediateNodesIndexedByUid).find(isAppIRNode);
37
+ }
38
+ catch (error) {
39
+ debugError(error);
40
+ uiLogger.error(commands.project.installStatus.errors.failedToParseProject);
41
+ return exit(EXIT_CODES.ERROR);
42
+ }
43
+ if (!appNode) {
44
+ uiLogger.error(commands.project.installStatus.errors.noAppInProject);
45
+ return exit(EXIT_CODES.ERROR);
46
+ }
47
+ if (appNode.config.auth.type.toLowerCase() !== APP_AUTH_TYPES.STATIC) {
48
+ uiLogger.error(commands.project.installStatus.errors.unsupportedAuthType(appNode.config.auth.type));
49
+ return exit(EXIT_CODES.ERROR);
50
+ }
51
+ let projectId;
52
+ try {
53
+ const response = await fetchProject(derivedAccountId, projectConfig.name);
54
+ projectId = response.data.id;
55
+ }
56
+ catch (error) {
57
+ logError(error, new ApiErrorContext({
58
+ accountId: derivedAccountId,
59
+ projectName: projectConfig.name,
60
+ }));
61
+ return exit(EXIT_CODES.ERROR);
62
+ }
63
+ let isInstalledWithScopeGroups = false;
64
+ let previouslyAuthorizedScopeGroups = [];
65
+ let appId;
66
+ try {
67
+ const response = await fetchAppInstallationData(derivedAccountId, projectId, appNode.uid, appNode.config.auth.requiredScopes, appNode.config.auth.optionalScopes);
68
+ isInstalledWithScopeGroups = response.data.isInstalledWithScopeGroups;
69
+ previouslyAuthorizedScopeGroups =
70
+ response.data.previouslyAuthorizedScopeGroups;
71
+ appId = response.data.appId;
72
+ }
73
+ catch (error) {
74
+ if (!isHubSpotHttpError(error) || error.status !== 404) {
75
+ logError(error, new ApiErrorContext({
76
+ accountId: derivedAccountId,
77
+ projectName: projectConfig.name,
78
+ }));
79
+ return exit(EXIT_CODES.ERROR);
80
+ }
81
+ }
82
+ const isInstalled = isInstalledWithScopeGroups || previouslyAuthorizedScopeGroups.length > 0;
83
+ if (formatOutputAsJson) {
84
+ uiLogger.json({
85
+ appId,
86
+ appUid: appNode.uid,
87
+ accountId: derivedAccountId,
88
+ projectId,
89
+ isInstalled,
90
+ isInstalledWithCurrentScopes: isInstalledWithScopeGroups,
91
+ previouslyAuthorizedScopeGroups,
92
+ });
93
+ return exit(isInstalled ? EXIT_CODES.SUCCESS : EXIT_CODES.WARNING);
94
+ }
95
+ if (isInstalled) {
96
+ if (isInstalledWithScopeGroups) {
97
+ uiLogger.success(commands.project.installStatus.success.installed(appNode.config.name, derivedAccountId));
98
+ }
99
+ else {
100
+ uiLogger.success(commands.project.installStatus.success.installedWithOutdatedScopes(appNode.config.name, derivedAccountId));
101
+ }
102
+ return exit(EXIT_CODES.SUCCESS);
103
+ }
104
+ uiLogger.log(commands.project.installStatus.notInstalled(appNode.config.name, derivedAccountId));
105
+ return exit(EXIT_CODES.WARNING);
106
+ }
107
+ function projectInstallStatusBuilder(yargs) {
108
+ yargs.example([
109
+ [
110
+ '$0 project app-install-status',
111
+ commands.project.installStatus.examples.default,
112
+ ],
113
+ [
114
+ '$0 project app-install-status --json',
115
+ commands.project.installStatus.examples.json,
116
+ ],
117
+ ]);
118
+ return yargs;
119
+ }
120
+ const builder = makeYargsBuilder(projectInstallStatusBuilder, command, describe, {
121
+ useGlobalOptions: true,
122
+ useConfigOptions: true,
123
+ useAccountOptions: true,
124
+ useJSONOutputOptions: true,
125
+ });
126
+ const projectInstallStatusCommand = {
127
+ command,
128
+ describe,
129
+ handler: makeYargsHandlerWithUsageTracking('project-app-install-status', handler),
130
+ builder,
131
+ };
132
+ export default projectInstallStatusCommand;
@@ -2,27 +2,32 @@ import path from 'path';
2
2
  import fs from 'fs-extra';
3
3
  import { cloneGithubRepo } from '@hubspot/local-dev-lib/github';
4
4
  import { getCwd } from '@hubspot/local-dev-lib/path';
5
+ import { getProjectMetadata, } from '@hubspot/project-parsing-lib/projects';
6
+ import { PLATFORM_VERSIONS } from '@hubspot/project-parsing-lib/constants';
5
7
  import { writeProjectConfig, getProjectConfig, } from '../../lib/projects/config.js';
6
8
  import { EMPTY_PROJECT_TEMPLATE_NAME } from '../../lib/projects/create/legacy.js';
7
9
  import { generateComponentPaths } from '../../lib/projects/create/v2.js';
8
- import { PROJECT_WITH_APP, EMPTY_PROJECT } from '../../lib/constants.js';
9
10
  import { debugError, logError } from '../../lib/errorHandlers/index.js';
10
11
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
11
- import { PROJECT_CONFIG_FILE, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, marketplaceDistribution, privateDistribution, oAuth, staticAuth, DEFAULT_PROJECT_TEMPLATE_BRANCH, } from '../../lib/constants.js';
12
+ import { PROJECT_CONFIG_FILE, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, marketplaceDistribution, privateDistribution, oAuth, staticAuth, DEFAULT_PROJECT_TEMPLATE_BRANCH, PROJECT_WITH_APP, EMPTY_PROJECT, } from '../../lib/constants.js';
12
13
  import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
13
14
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
14
- import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
15
15
  import { commands } from '../../lang/en.js';
16
16
  import { uiLogger } from '../../lib/ui/logger.js';
17
17
  import { handleProjectCreationFlow, } from '../../lib/projects/create/index.js';
18
- import { getProjectMetadata, } from '@hubspot/project-parsing-lib/projects';
19
18
  import { updateHsMetaFilesWithAutoGeneratedFields } from '../../lib/projects/components.js';
20
19
  import SpinniesManager from '../../lib/ui/SpinniesManager.js';
21
20
  const command = ['create', 'init'];
22
21
  const describe = commands.project.create.describe;
23
- const { v2025_1, v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
22
+ const BETA_VERSIONS = [
23
+ PLATFORM_VERSIONS.v2026_09_BETA,
24
+ PLATFORM_VERSIONS.v2026_03_BETA,
25
+ ];
24
26
  async function handler(args) {
25
27
  const { platformVersion, templateSource, exit, addUsageMetadata } = args;
28
+ if (BETA_VERSIONS.includes(platformVersion)) {
29
+ uiLogger.warn(commands.project.create.warnings.betaPlatformVersion(platformVersion));
30
+ }
26
31
  if (templateSource && !templateSource.includes('/')) {
27
32
  uiLogger.error(commands.project.create.errors.invalidTemplateSource);
28
33
  return exit(EXIT_CODES.ERROR);
@@ -125,8 +130,14 @@ function projectCreateBuilder(yargs) {
125
130
  'platform-version': {
126
131
  describe: commands.project.create.options.platformVersion.describe,
127
132
  type: 'string',
128
- choices: [v2025_1, v2025_2, v2026_03_beta, v2026_03],
129
- default: v2026_03,
133
+ choices: [
134
+ PLATFORM_VERSIONS.v2025_1,
135
+ PLATFORM_VERSIONS.v2025_2,
136
+ PLATFORM_VERSIONS.v2026_03_BETA,
137
+ PLATFORM_VERSIONS.v2026_03,
138
+ PLATFORM_VERSIONS.v2026_09_BETA,
139
+ ],
140
+ default: PLATFORM_VERSIONS.v2026_03,
130
141
  },
131
142
  'project-base': {
132
143
  describe: commands.project.create.options.projectBase.describe,
@@ -5,7 +5,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
5
5
  import { renderInline } from '../../ui/render.js';
6
6
  import { getWarningBox } from '../../ui/components/StatusMessageBoxes.js';
7
7
  import { commands } from '../../lang/en.js';
8
- import { isV2Project } from '../../lib/projects/platformVersion.js';
8
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
9
9
  import { isPromptExitError } from '../../lib/errors/PromptExitError.js';
10
10
  import { resolveProjectName, checkDeployedComponents, deleteDeployedComponents, confirmDeletion, handleProjectDeletion, } from '../../lib/projects/delete.js';
11
11
  const command = 'delete';
@@ -23,7 +23,7 @@ async function handler(args) {
23
23
  if (!force) {
24
24
  await confirmDeletion(projectName, derivedAccountId, projectId);
25
25
  }
26
- if (isV2Project(platformVersion) && hasUnifiedComponents) {
26
+ if (!isLegacyProject(platformVersion) && hasUnifiedComponents) {
27
27
  await deleteDeployedComponents(derivedAccountId, projectName);
28
28
  }
29
29
  await handleProjectDeletion(derivedAccountId, projectName);
@@ -1,7 +1,7 @@
1
1
  import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
2
2
  import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
3
3
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
4
- import { isV2Project } from '../../lib/projects/platformVersion.js';
4
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
5
5
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
6
6
  import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
7
7
  import { projectNamePrompt } from '../../lib/prompts/projectNamePrompt.js';
@@ -31,7 +31,8 @@ async function handler(args) {
31
31
  isInProjectDirectory = true;
32
32
  }
33
33
  catch (e) { }
34
- if (isInProjectDirectory && isV2Project(projectConfig?.platformVersion)) {
34
+ if (isInProjectDirectory &&
35
+ !isLegacyProject(projectConfig?.platformVersion)) {
35
36
  try {
36
37
  const profileName = await projectProfilePrompt(projectDir, projectConfig, profileOption, !!useEnvOption);
37
38
  if (profileName) {
@@ -97,7 +98,7 @@ async function handler(args) {
97
98
  uiLogger.error(commands.project.deploy.errors.noBuildId);
98
99
  return exit(EXIT_CODES.ERROR);
99
100
  }
100
- const deployResult = await handleProjectDeploy(targetAccountId, projectName, buildIdToDeploy, isV2Project(projectConfig?.platformVersion), forceOption);
101
+ const deployResult = await handleProjectDeploy(targetAccountId, projectName, buildIdToDeploy, isLegacyProject(projectConfig?.platformVersion), forceOption);
101
102
  if (!deployResult) {
102
103
  return exit(EXIT_CODES.ERROR);
103
104
  }
@@ -5,7 +5,7 @@ import { uiLine } from '../../../lib/ui/index.js';
5
5
  import { makeYargsHandlerWithUsageTracking } from '../../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
6
6
  import { deprecatedProjectDevFlow } from './deprecatedFlow.js';
7
7
  import { unifiedProjectDevFlow } from './unifiedFlow.js';
8
- import { isV2Project } from '../../../lib/projects/platformVersion.js';
8
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
9
9
  import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
10
10
  import { loadAndValidateProfile } from '../../../lib/projects/projectProfiles.js';
11
11
  import { commands } from '../../../lang/en.js';
@@ -34,7 +34,7 @@ async function handler(args) {
34
34
  logError(error);
35
35
  return exit(EXIT_CODES.ERROR);
36
36
  }
37
- const useV2Projects = isV2Project(projectConfig.platformVersion);
37
+ const useV2Projects = !isLegacyProject(projectConfig.platformVersion);
38
38
  if (!projectDir) {
39
39
  uiLogger.error(commands.project.dev.errors.noProjectConfig);
40
40
  return exit(EXIT_CODES.ERROR);
@@ -69,7 +69,8 @@ async function handler(args) {
69
69
  targetProjectAccountId = derivedAccountId;
70
70
  }
71
71
  // Determine profile name: from flag or prompt
72
- if (!targetProjectAccountId && isV2Project(projectConfig.platformVersion)) {
72
+ if (!targetProjectAccountId &&
73
+ !isLegacyProject(projectConfig.platformVersion)) {
73
74
  const profileName = await projectProfilePrompt(projectDir, projectConfig, profileOption);
74
75
  if (profileName) {
75
76
  try {
@@ -95,7 +96,7 @@ async function handler(args) {
95
96
  }
96
97
  addUsageMetadata({ accountId: targetProjectAccountId ?? undefined });
97
98
  try {
98
- if (isV2Project(projectConfig.platformVersion)) {
99
+ if (!isLegacyProject(projectConfig.platformVersion)) {
99
100
  const targetTestingAccountId = testingAccount
100
101
  ? getConfigAccountIfExists(testingAccount)?.accountId
101
102
  : undefined;
@@ -6,7 +6,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
6
  import { uiLogger } from '../../lib/ui/logger.js';
7
7
  import { commands } from '../../lang/en.js';
8
8
  import { getProjectConfig } from '../../lib/projects/config.js';
9
- import { isV2Project } from '../../lib/projects/platformVersion.js';
9
+ import { isLegacyProject } from '@hubspot/project-parsing-lib/projects';
10
10
  import { getProjectInfo, logProjectInfo, } from '../../lib/projects/projectInfo.js';
11
11
  const command = 'info';
12
12
  const describe = commands.project.info.describe;
@@ -18,7 +18,7 @@ async function handler(args) {
18
18
  uiLogger.error(commands.project.info.errors.noProjectConfig);
19
19
  return exit(EXIT_CODES.ERROR);
20
20
  }
21
- if (!isV2Project(projectConfig.platformVersion)) {
21
+ if (isLegacyProject(projectConfig.platformVersion)) {
22
22
  uiLogger.error(commands.project.info.errors.unsupportedPlatformVersion(projectConfig.platformVersion));
23
23
  return exit(EXIT_CODES.ERROR);
24
24
  }
@@ -117,9 +117,10 @@ async function handler(args) {
117
117
  SpinniesManager.add('lintConfigCreate', {
118
118
  text: commands.project.lint.loading.creatingConfig,
119
119
  });
120
+ const platformVersion = projectConfig.projectConfig?.platformVersion ?? null;
120
121
  const createdConfigs = [];
121
122
  for (const location of locationsNeedingConfig) {
122
- const configPath = createEslintConfig(location);
123
+ const configPath = await createEslintConfig(location, platformVersion);
123
124
  createdConfigs.push(configPath);
124
125
  }
125
126
  SpinniesManager.succeed('lintConfigCreate');