@hubspot/cli 8.0.10-experimental.3 → 8.0.10-experimental.5

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/api/migrate.js CHANGED
@@ -23,7 +23,11 @@ function mapPlatformVersionToEnum(platformVersion) {
23
23
  if (platformVersion === PLATFORM_VERSIONS.unstable) {
24
24
  return PLATFORM_VERSIONS.unstable.toUpperCase();
25
25
  }
26
- return `V${platformVersion.replace('.', '_')}`;
26
+ const reformattedPlatformVersion = platformVersion
27
+ .replaceAll('.', '_')
28
+ .replaceAll('-', '_')
29
+ .toUpperCase();
30
+ return `V${reformattedPlatformVersion}`;
27
31
  }
28
32
  export async function initializeAppMigration(accountId, applicationId, platformVersion) {
29
33
  return http.post(accountId, {
@@ -89,7 +89,7 @@ describe('commands/app/migrate', () => {
89
89
  }),
90
90
  'platform-version': expect.objectContaining({
91
91
  type: 'string',
92
- default: '2025.2',
92
+ default: '2026.03',
93
93
  }),
94
94
  }));
95
95
  });
@@ -97,7 +97,7 @@ describe('commands/app/migrate', () => {
97
97
  await migrateCommand.builder(mockYargs);
98
98
  expect(optionsSpy).toHaveBeenCalledWith(expect.objectContaining({
99
99
  'platform-version': expect.objectContaining({
100
- default: '2025.2',
100
+ default: '2026.03',
101
101
  }),
102
102
  }));
103
103
  });
@@ -8,7 +8,7 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
8
8
  import { migrateApp } from '../../lib/app/migrate.js';
9
9
  import { getIsInProject } from '../../lib/projects/config.js';
10
10
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
11
- const { v2025_2 } = PLATFORM_VERSIONS;
11
+ const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
12
12
  const command = 'migrate';
13
13
  const describe = commands.project.migrateApp.describe;
14
14
  export function handlerGenerator(commandTrackingName) {
@@ -67,8 +67,8 @@ function appMigrateBuilder(yargs) {
67
67
  },
68
68
  'platform-version': {
69
69
  type: 'string',
70
- choices: [v2025_2],
71
- default: v2025_2,
70
+ choices: [v2025_2, v2026_03_beta, v2026_03],
71
+ default: v2026_03,
72
72
  },
73
73
  unstable: {
74
74
  type: 'boolean',
@@ -8,6 +8,7 @@ import * as modulesLib from '@hubspot/local-dev-lib/cms/modules';
8
8
  import * as ignoreRulesLib from '@hubspot/local-dev-lib/ignoreRules';
9
9
  import * as themesLib from '@hubspot/local-dev-lib/cms/themes';
10
10
  import * as configLib from '@hubspot/local-dev-lib/config';
11
+ import * as handleFieldsJSLib from '@hubspot/local-dev-lib/cms/handleFieldsJS';
11
12
  import { uiLogger } from '../../../lib/ui/logger.js';
12
13
  import * as errorHandlers from '../../../lib/errorHandlers/index.js';
13
14
  import * as commonOpts from '../../../lib/commonOpts.js';
@@ -26,6 +27,7 @@ vi.mock('@hubspot/local-dev-lib/cms/modules');
26
27
  vi.mock('@hubspot/local-dev-lib/ignoreRules');
27
28
  vi.mock('@hubspot/local-dev-lib/cms/themes');
28
29
  vi.mock('@hubspot/local-dev-lib/config');
30
+ vi.mock('@hubspot/local-dev-lib/cms/handleFieldsJS');
29
31
  vi.mock('../../../lib/errorHandlers/index.js');
30
32
  vi.mock('../../../lib/commonOpts.js');
31
33
  vi.mock('../../../lib/prompts/uploadPrompt.js');
@@ -53,6 +55,7 @@ const hasUploadErrorsSpy = vi.spyOn(uploadFolderLib, 'hasUploadErrors');
53
55
  const processExitSpy = vi.spyOn(process, 'exit');
54
56
  const logErrorSpy = vi.spyOn(errorHandlers, 'logError');
55
57
  const getConfigAccountIfExistsSpy = vi.spyOn(configLib, 'getConfigAccountIfExists');
58
+ const isConvertableFieldJsSpy = vi.spyOn(handleFieldsJSLib, 'isConvertableFieldJs');
56
59
  describe('commands/cms/upload', () => {
57
60
  beforeEach(() => {
58
61
  // @ts-expect-error Mock implementation
@@ -67,6 +70,7 @@ describe('commands/cms/upload', () => {
67
70
  getThemePreviewUrlSpy.mockReturnValue(undefined);
68
71
  // Mock config to prevent reading actual config file in CI
69
72
  getConfigAccountIfExistsSpy.mockReturnValue(undefined);
73
+ isConvertableFieldJsSpy.mockReturnValue(false);
70
74
  });
71
75
  describe('command', () => {
72
76
  it('should have the correct command structure', () => {
@@ -50,8 +50,8 @@ describe('commands/project/create', () => {
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
- choices: ['2025.1', '2025.2', '2026.03-beta'],
54
- default: '2025.2',
53
+ choices: ['2025.1', '2025.2', '2026.03-beta', '2026.03'],
54
+ default: '2026.03',
55
55
  }));
56
56
  });
57
57
  it('should define project base option with correct choices', () => {
@@ -9,7 +9,7 @@ import { uiBetaTag, uiCommandReference } from '../../../lib/ui/index.js';
9
9
  vi.mock('../../../lib/app/migrate');
10
10
  vi.mock('../../../lib/projects/config');
11
11
  vi.mock('../../../lib/ui');
12
- const { v2025_2 } = PLATFORM_VERSIONS;
12
+ const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
13
13
  describe('commands/project/migrate', () => {
14
14
  const yargsMock = yargs;
15
15
  const optionsSpy = vi.spyOn(yargsMock, 'option').mockReturnValue(yargsMock);
@@ -48,8 +48,8 @@ describe('commands/project/migrate', () => {
48
48
  migrateCommand.builder(yargsMock);
49
49
  expect(optionsSpy).toHaveBeenCalledWith('platform-version', {
50
50
  type: 'string',
51
- choices: [v2025_2],
52
- default: v2025_2,
51
+ choices: [v2025_2, v2026_03_beta, v2026_03],
52
+ default: v2026_03,
53
53
  });
54
54
  expect(optionsSpy).toHaveBeenCalledWith('unstable', {
55
55
  type: 'boolean',
@@ -20,7 +20,7 @@ import { updateHsMetaFilesWithAutoGeneratedFields } from '../../lib/projects/com
20
20
  import SpinniesManager from '../../lib/ui/SpinniesManager.js';
21
21
  const command = ['create', 'init'];
22
22
  const describe = commands.project.create.describe;
23
- const { v2025_1, v2025_2, v2026_03_beta } = PLATFORM_VERSIONS;
23
+ const { v2025_1, v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
24
24
  async function handler(args) {
25
25
  const { derivedAccountId, platformVersion, templateSource } = args;
26
26
  if (templateSource && !templateSource.includes('/')) {
@@ -125,8 +125,8 @@ function projectCreateBuilder(yargs) {
125
125
  'platform-version': {
126
126
  describe: commands.project.create.options.platformVersion.describe,
127
127
  type: 'string',
128
- choices: [v2025_1, v2025_2, v2026_03_beta],
129
- default: v2025_2,
128
+ choices: [v2025_1, v2025_2, v2026_03_beta, v2026_03],
129
+ default: v2026_03,
130
130
  },
131
131
  'project-base': {
132
132
  describe: commands.project.create.options.projectBase.describe,
@@ -9,11 +9,11 @@ import { commands, lib } from '../../lang/en.js';
9
9
  import { uiLogger } from '../../lib/ui/logger.js';
10
10
  import { renderInline } from '../../ui/render.js';
11
11
  import { getWarningBox } from '../../ui/components/StatusMessageBoxes.js';
12
- import { getHasMigratableThemes, migrateThemes2025_2, } from '../../lib/theme/migrate.js';
12
+ import { getHasMigratableThemes, migrateThemesV2, } from '../../lib/theme/migrate.js';
13
13
  import { hasFeature } from '../../lib/hasFeature.js';
14
14
  import { FEATURES } from '../../lib/constants.js';
15
15
  import { trackCommandMetadataUsage, trackCommandUsage, } from '../../lib/usageTracking.js';
16
- const { v2025_2 } = PLATFORM_VERSIONS;
16
+ const { v2025_2, v2026_03_beta, v2026_03 } = PLATFORM_VERSIONS;
17
17
  const command = 'migrate';
18
18
  const describe = commands.project.migrate.describe;
19
19
  async function handler(args) {
@@ -26,8 +26,8 @@ async function handler(args) {
26
26
  }
27
27
  if (projectConfig?.projectConfig) {
28
28
  await renderInline(getWarningBox({
29
- title: lib.migrate.projectMigrationWarningTitle,
30
- message: lib.migrate.projectMigrationWarning,
29
+ title: lib.migrate.projectMigrationWarningTitle(platformVersion),
30
+ message: lib.migrate.projectMigrationWarning(platformVersion),
31
31
  }));
32
32
  }
33
33
  try {
@@ -38,7 +38,7 @@ async function handler(args) {
38
38
  uiLogger.error(commands.project.migrate.errors.noThemeMigrationAccess(derivedAccountId));
39
39
  return process.exit(EXIT_CODES.ERROR);
40
40
  }
41
- await migrateThemes2025_2(derivedAccountId, {
41
+ await migrateThemesV2(derivedAccountId, {
42
42
  ...args,
43
43
  platformVersion: unstable
44
44
  ? PLATFORM_VERSIONS.unstable
@@ -67,8 +67,8 @@ function projectMigrateBuilder(yargs) {
67
67
  yargs
68
68
  .option('platform-version', {
69
69
  type: 'string',
70
- choices: [v2025_2],
71
- default: v2025_2,
70
+ choices: [v2025_2, v2026_03_beta, v2026_03],
71
+ default: v2026_03,
72
72
  })
73
73
  .option('unstable', {
74
74
  type: 'boolean',
package/lang/en.d.ts CHANGED
@@ -1494,7 +1494,6 @@ export declare const commands: {
1494
1494
  };
1495
1495
  };
1496
1496
  header: string;
1497
- deprecationWarning: (platformVersion: string) => string;
1498
1497
  migrationStatus: {
1499
1498
  inProgress: () => string;
1500
1499
  success: () => string;
@@ -3920,8 +3919,8 @@ export declare const lib: {
3920
3919
  componentsToBeMigrated: (components: string) => string;
3921
3920
  componentsThatWillNotBeMigrated: (components: string) => string;
3922
3921
  sourceContentsMoved: (newLocation: string) => string;
3923
- projectMigrationWarningTitle: string;
3924
- projectMigrationWarning: string;
3922
+ projectMigrationWarningTitle: (platformVersion: string) => string;
3923
+ projectMigrationWarning: (platformVersion: string) => string;
3925
3924
  exitWithoutMigrating: string;
3926
3925
  success: {
3927
3926
  downloadedProject: (projectName: string, projectDest: string) => string;
package/lang/en.js CHANGED
@@ -1510,7 +1510,6 @@ export const commands = {
1510
1510
  },
1511
1511
  },
1512
1512
  header: `This command will migrate an app to the projects framework. It will walk you through the fields required to complete the migration and download the project source code into a directory of your choosing.\n${uiLink('Learn more about migrating apps to the projects framework', 'https://developers.hubspot.com/docs/platform/migrate-a-public-app-to-projects')}`,
1513
- deprecationWarning: (platformVersion) => `The ${uiCommandReference('hs project migrate-app')} command is deprecated and will be removed. Use ${uiCommandReference(`hs app migrate --platform-version=${platformVersion}`)} going forward.`,
1514
1513
  migrationStatus: {
1515
1514
  inProgress: () => `Converting app configuration to ${chalk.bold(LEGACY_PUBLIC_APP_FILE)} component definition ...`,
1516
1515
  success: () => `${chalk.bold('Your app was converted and build #1 is deployed')}`,
@@ -3943,8 +3942,8 @@ export const lib = {
3943
3942
  componentsToBeMigrated: (components) => `The following features will be migrated: ${components}`,
3944
3943
  componentsThatWillNotBeMigrated: (components) => `[NOTE] These features are not yet supported for migration but will be available later: ${components}`,
3945
3944
  sourceContentsMoved: (newLocation) => `The contents of your old source directory have been moved to ${newLocation}, move any required files to the new source directory.`,
3946
- projectMigrationWarningTitle: 'Important: Migrating to platformVersion 2025.2 is irreversible',
3947
- projectMigrationWarning: uiBetaTag(`Running the ${uiCommandReference('hs project migrate')} command will permanently upgrade your project to platformVersion 2025.2. This action cannot be undone. To ensure you have access to your original files, they will be copied to a new directory (archive) for safekeeping.\n\nThis command will guide you through the process, prompting you to enter the required fields and will download the new project source code into your project source directory.`, false),
3945
+ projectMigrationWarningTitle: (platformVersion) => `Important: Migrating to platformVersion ${platformVersion} is irreversible`,
3946
+ projectMigrationWarning: (platformVersion) => uiBetaTag(`Running the ${uiCommandReference('hs project migrate')} command will permanently upgrade your project to platformVersion ${platformVersion}. This action cannot be undone. To ensure you have access to your original files, they will be copied to a new directory (archive) for safekeeping.\n\nThis command will guide you through the process, prompting you to enter the required fields and will download the new project source code into your project source directory.`, false),
3948
3947
  exitWithoutMigrating: 'Exiting without migrating',
3949
3948
  success: {
3950
3949
  downloadedProject: (projectName, projectDest) => `Saved ${projectName} to ${projectDest}`,
@@ -424,7 +424,7 @@ describe('lib/app/migrate', () => {
424
424
  };
425
425
  mockedPoll.mockResolvedValue(mockStatus);
426
426
  const result = await pollMigrationStatus(ACCOUNT_ID, MIGRATION_ID);
427
- expect(mockedPoll).toHaveBeenCalledWith(expect.any(Function), expect.any(Object));
427
+ expect(mockedPoll).toHaveBeenCalledWith(expect.any(Function), expect.any(Object), 300_000);
428
428
  expect(result).toBe(mockStatus);
429
429
  });
430
430
  });
@@ -255,7 +255,7 @@ export async function pollMigrationStatus(derivedAccountId, migrationId, success
255
255
  return poll(() => checkMigrationStatusV2(derivedAccountId, migrationId), {
256
256
  successStates: [...successStates],
257
257
  errorStates: [...DEFAULT_POLLING_STATUS_LOOKUP.errorStates],
258
- });
258
+ }, 300_000);
259
259
  }
260
260
  export async function finalizeAppMigration(derivedAccountId, migrationId, uidMap, projectName) {
261
261
  let pollResponse;
@@ -3,15 +3,13 @@ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
3
3
  import { confirmPrompt } from '../../prompts/promptUtils.js';
4
4
  import { writeProjectConfig, } from '../../projects/config.js';
5
5
  import { ensureProjectExists } from '../../projects/ensureProjectExists.js';
6
- import { isV2Project } from '../../projects/platformVersion.js';
7
6
  import { fetchMigrationApps } from '../../app/migrate.js';
8
- import { getHasMigratableThemes, validateMigrationAppsAndThemes, handleThemesMigration, migrateThemes2025_2, } from '../migrate.js';
7
+ import { getHasMigratableThemes, validateMigrationAppsAndThemes, handleThemesMigration, migrateThemesV2, } from '../migrate.js';
9
8
  import { lib } from '../../../lang/en.js';
10
9
  vi.mock('@hubspot/project-parsing-lib/themes');
11
10
  vi.mock('../../prompts/promptUtils');
12
11
  vi.mock('../../projects/config');
13
12
  vi.mock('../../projects/ensureProjectExists');
14
- vi.mock('../../projects/platformVersion');
15
13
  vi.mock('../../app/migrate');
16
14
  vi.mock('@hubspot/local-dev-lib/config');
17
15
  vi.mock('../../ui/SpinniesManager', () => ({
@@ -28,7 +26,6 @@ const mockedMigrateThemes = migrateThemes;
28
26
  const mockedConfirmPrompt = confirmPrompt;
29
27
  const mockedWriteProjectConfig = writeProjectConfig;
30
28
  const mockedEnsureProjectExists = ensureProjectExists;
31
- const mockedUseV2Api = isV2Project;
32
29
  const mockedFetchMigrationApps = fetchMigrationApps;
33
30
  const mockedGetConfigAccountById = getConfigAccountById;
34
31
  const ACCOUNT_ID = 123;
@@ -41,7 +38,6 @@ const createLoadedProjectConfig = (name) => ({
41
38
  });
42
39
  describe('lib/theme/migrate', () => {
43
40
  beforeEach(() => {
44
- mockedUseV2Api.mockReturnValue(false);
45
41
  // Mock account config for the test account ID
46
42
  mockedGetConfigAccountById.mockReturnValue({
47
43
  accountId: ACCOUNT_ID,
@@ -144,11 +140,6 @@ describe('lib/theme/migrate', () => {
144
140
  });
145
141
  });
146
142
  describe('validateMigrationAppsAndThemes', () => {
147
- it('should throw an error when themes are already migrated (v2 API)', async () => {
148
- mockedUseV2Api.mockReturnValue(true);
149
- const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
150
- await expect(validateMigrationAppsAndThemes(0, projectConfig)).rejects.toThrow(lib.migrate.errors.project.themesAlreadyMigrated);
151
- });
152
143
  it('should throw an error when apps and themes are both present', async () => {
153
144
  const projectConfig = createLoadedProjectConfig(PROJECT_NAME);
154
145
  await expect(validateMigrationAppsAndThemes(1, projectConfig)).rejects.toThrow(lib.migrate.errors.project.themesAndAppsNotAllowed);
@@ -204,7 +195,7 @@ describe('lib/theme/migrate', () => {
204
195
  await expect(handleThemesMigration(projectConfig, PLATFORM_VERSION)).rejects.toThrow(lib.migrate.errors.project.failedToMigrateThemes);
205
196
  });
206
197
  });
207
- describe('migrateThemes2025_2', () => {
198
+ describe('migrateThemesV2', () => {
208
199
  const options = {
209
200
  platformVersion: PLATFORM_VERSION,
210
201
  };
@@ -230,25 +221,25 @@ describe('lib/theme/migrate', () => {
230
221
  projectConfig: undefined,
231
222
  projectDir: MOCK_PROJECT_DIR,
232
223
  };
233
- await expect(migrateThemes2025_2(ACCOUNT_ID, options, themeCount, invalidProjectConfig)).rejects.toThrow(lib.migrate.errors.project.invalidConfig);
224
+ await expect(migrateThemesV2(ACCOUNT_ID, options, themeCount, invalidProjectConfig)).rejects.toThrow(lib.migrate.errors.project.invalidConfig);
234
225
  });
235
226
  it('should throw an error when project does not exist', async () => {
236
227
  mockedEnsureProjectExists.mockResolvedValue({ projectExists: false });
237
- await expect(migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig)).rejects.toThrow(lib.migrate.errors.project.doesNotExist(ACCOUNT_ID));
228
+ await expect(migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig)).rejects.toThrow(lib.migrate.errors.project.doesNotExist(ACCOUNT_ID));
238
229
  });
239
230
  it('should proceed with migration when user confirms', async () => {
240
- await migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig);
231
+ await migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig);
241
232
  expect(mockedFetchMigrationApps).toHaveBeenCalledWith(ACCOUNT_ID, PLATFORM_VERSION, { projectConfig });
242
233
  expect(mockedConfirmPrompt).toHaveBeenCalledWith(lib.migrate.prompt.proceed, { defaultAnswer: false });
243
234
  expect(mockedMigrateThemes).toHaveBeenCalledWith(MOCK_PROJECT_DIR, `${MOCK_PROJECT_DIR}/src`);
244
235
  });
245
236
  it('should exit without migrating when user cancels', async () => {
246
237
  mockedConfirmPrompt.mockResolvedValue(false);
247
- await migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig);
238
+ await migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig);
248
239
  expect(mockedMigrateThemes).not.toHaveBeenCalled();
249
240
  });
250
241
  it('should validate migration apps and themes', async () => {
251
- await migrateThemes2025_2(ACCOUNT_ID, options, themeCount, projectConfig);
242
+ await migrateThemesV2(ACCOUNT_ID, options, themeCount, projectConfig);
252
243
  // The validation is called internally, so we verify it through the error handling
253
244
  expect(mockedFetchMigrationApps).toHaveBeenCalled();
254
245
  });
@@ -10,4 +10,4 @@ export declare function getHasMigratableThemes(projectConfig?: LoadedProjectConf
10
10
  }>;
11
11
  export declare function validateMigrationAppsAndThemes(hasApps: number, projectConfig?: LoadedProjectConfig): Promise<void>;
12
12
  export declare function handleThemesMigration(projectConfig: LoadedProjectConfig, platformVersion: string): Promise<void>;
13
- export declare function migrateThemes2025_2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateThemesArgs>, themeCount: number, projectConfig: LoadedProjectConfig): Promise<void>;
13
+ export declare function migrateThemesV2(derivedAccountId: number, options: ArgumentsCamelCase<MigrateThemesArgs>, themeCount: number, projectConfig: LoadedProjectConfig): Promise<void>;
@@ -7,7 +7,6 @@ import { lib } from '../../lang/en.js';
7
7
  import { PROJECT_CONFIG_FILE } from '../constants.js';
8
8
  import { uiLogger } from '../ui/logger.js';
9
9
  import { debugError } from '../errorHandlers/index.js';
10
- import { isV2Project } from '../projects/platformVersion.js';
11
10
  import { confirmPrompt } from '../prompts/promptUtils.js';
12
11
  import { fetchMigrationApps } from '../app/migrate.js';
13
12
  export async function getHasMigratableThemes(projectConfig) {
@@ -22,9 +21,6 @@ export async function getHasMigratableThemes(projectConfig) {
22
21
  };
23
22
  }
24
23
  export async function validateMigrationAppsAndThemes(hasApps, projectConfig) {
25
- if (isV2Project(projectConfig?.projectConfig?.platformVersion)) {
26
- throw new Error(lib.migrate.errors.project.themesAlreadyMigrated);
27
- }
28
24
  if (hasApps > 0 && projectConfig) {
29
25
  throw new Error(lib.migrate.errors.project.themesAndAppsNotAllowed);
30
26
  }
@@ -61,7 +57,7 @@ export async function handleThemesMigration(projectConfig, platformVersion) {
61
57
  uiLogger.log('');
62
58
  uiLogger.log(lib.migrate.success.themesMigrationSuccess(platformVersion));
63
59
  }
64
- export async function migrateThemes2025_2(derivedAccountId, options, themeCount, projectConfig) {
60
+ export async function migrateThemesV2(derivedAccountId, options, themeCount, projectConfig) {
65
61
  if (!projectConfig?.projectConfig || !projectConfig?.projectDir) {
66
62
  throw new Error(lib.migrate.errors.project.invalidConfig);
67
63
  }
@@ -22,6 +22,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
22
22
  webhooks: "webhooks";
23
23
  "workflow-action": "workflow-action";
24
24
  "app-function": "app-function";
25
+ "app-function-endpoint": "app-function-endpoint";
25
26
  "app-object": "app-object";
26
27
  scim: "scim";
27
28
  }>>>;
@@ -26,6 +26,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
26
26
  webhooks: "webhooks";
27
27
  "workflow-action": "workflow-action";
28
28
  "app-function": "app-function";
29
+ "app-function-endpoint": "app-function-endpoint";
29
30
  "app-object": "app-object";
30
31
  scim: "scim";
31
32
  }>>>;
@@ -8,6 +8,7 @@ import { formatTextContents, formatTextContent } from '../../utils/content.js';
8
8
  import { trackToolUsage } from '../../utils/toolUsageTracking.js';
9
9
  import { setupHubSpotConfig } from '../../utils/config.js';
10
10
  import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
11
+ import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
11
12
  const inputSchema = {
12
13
  absoluteCurrentWorkingDirectory,
13
14
  name: z
@@ -40,7 +41,7 @@ export class CreateProjectTool extends Tool {
40
41
  async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }) {
41
42
  setupHubSpotConfig(absoluteCurrentWorkingDirectory);
42
43
  await trackToolUsage(toolName);
43
- let command = addFlag('hs project create', 'platform-version', '2025.2');
44
+ let command = addFlag('hs project create', 'platform-version', PLATFORM_VERSIONS.v2026_03);
44
45
  const content = [];
45
46
  if (name) {
46
47
  command = addFlag(command, 'name', name);
@@ -55,7 +55,6 @@ describe('mcp-server/tools/project/CreateProjectTool', () => {
55
55
  stderr: '',
56
56
  });
57
57
  const result = await tool.handler(baseInput);
58
- expect(mockAddFlag).toHaveBeenCalledWith('hs project create', 'platform-version', '2025.2');
59
58
  expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'name', 'test-project');
60
59
  expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'dest', './test-dest');
61
60
  expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'project-base', EMPTY_PROJECT);
@@ -10,6 +10,7 @@ export declare const features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
10
10
  webhooks: "webhooks";
11
11
  "workflow-action": "workflow-action";
12
12
  "app-function": "app-function";
13
+ "app-function-endpoint": "app-function-endpoint";
13
14
  "app-object": "app-object";
14
15
  scim: "scim";
15
16
  }>>>;
@@ -10,6 +10,7 @@ export const features = z
10
10
  'card',
11
11
  'settings',
12
12
  'app-function',
13
+ 'app-function-endpoint',
13
14
  'webhooks',
14
15
  'workflow-action',
15
16
  'workflow-action-tool',
@@ -18,7 +19,7 @@ export const features = z
18
19
  'scim',
19
20
  'page',
20
21
  ]))
21
- .describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a public serverless function. "workflow-action" is also known as a custom workflow action. "workflow-action-tool" is also known as agent tools.')
22
+ .describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a private serverless function. "app-function-endpoint" is a serverless functions that is publicly accessible via endpoint. "workflow-action" is also known as a custom workflow action. "workflow-action-tool" is also known as agent tools.')
22
23
  .optional();
23
24
  export const docsSearchQuery = z
24
25
  .string()
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "8.0.10-experimental.3",
3
+ "version": "8.0.10-experimental.5",
4
4
  "description": "The official CLI for developing on HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/HubSpot/hubspot-cli",
7
7
  "type": "module",
8
8
  "dependencies": {
9
- "@hubspot/local-dev-lib": "5.1.2",
10
- "@hubspot/project-parsing-lib": "0.13.0-beta.0",
9
+ "@hubspot/local-dev-lib": "5.2.0",
10
+ "@hubspot/project-parsing-lib": "0.12.1",
11
11
  "@hubspot/serverless-dev-runtime": "7.0.7",
12
12
  "@hubspot/ui-extensions-dev-server": "2.0.0",
13
13
  "@inquirer/prompts": "7.1.0",