@hubspot/cli 7.7.23-experimental.0 → 7.7.24-experimental.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/account/auth.js +15 -4
- package/commands/auth.js +1 -1
- package/commands/mcp/start.d.ts +1 -0
- package/commands/mcp/start.js +12 -4
- package/commands/project/create.js +2 -2
- package/commands/project/validate.js +1 -0
- package/commands/sandbox/__tests__/create.test.js +207 -0
- package/commands/sandbox/create.d.ts +1 -1
- package/commands/sandbox/create.js +31 -16
- package/lang/en.d.ts +7 -3
- package/lang/en.js +12 -5
- package/lang/en.lyaml +4 -2
- package/lib/__tests__/buildAccount.test.js +62 -4
- package/lib/buildAccount.d.ts +4 -1
- package/lib/buildAccount.js +57 -2
- package/lib/commonOpts.js +25 -0
- package/lib/constants.d.ts +4 -0
- package/lib/constants.js +4 -0
- package/lib/errorHandlers/index.js +1 -3
- package/lib/errors/ProjectValidationError.d.ts +4 -0
- package/lib/errors/ProjectValidationError.js +9 -0
- package/lib/mcp/setup.d.ts +4 -0
- package/lib/mcp/setup.js +36 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +35 -0
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +170 -1
- package/lib/projects/add/v3AddComponent.js +2 -1
- package/lib/projects/create/index.js +2 -2
- package/lib/projects/create/v3.d.ts +0 -2
- package/lib/projects/create/v3.js +1 -3
- package/lib/projects/localDev/LocalDevProcess.d.ts +1 -0
- package/lib/projects/localDev/LocalDevProcess.js +3 -0
- package/lib/projects/localDev/LocalDevState.d.ts +1 -0
- package/lib/projects/localDev/LocalDevState.js +5 -0
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -2
- package/lib/projects/localDev/LocalDevWebsocketServer.js +35 -29
- package/lib/projects/upload.js +5 -12
- package/lib/sandboxes.d.ts +4 -0
- package/lib/sandboxes.js +4 -0
- package/lib/ui/index.d.ts +6 -0
- package/lib/ui/index.js +3 -5
- package/mcp-server/tools/index.js +6 -4
- package/mcp-server/tools/project/{AddFeatureToProject.d.ts → AddFeatureToProjectTool.d.ts} +4 -4
- package/mcp-server/tools/project/{AddFeatureToProject.js → AddFeatureToProjectTool.js} +6 -14
- package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
- package/mcp-server/tools/project/CreateProjectTool.js +4 -14
- package/mcp-server/tools/project/{DeployProject.d.ts → DeployProjectTool.d.ts} +1 -1
- package/mcp-server/tools/project/{DeployProject.js → DeployProjectTool.js} +2 -2
- package/mcp-server/tools/project/GetConfigValuesTool.d.ts +20 -0
- package/mcp-server/tools/project/GetConfigValuesTool.js +51 -0
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/{AddFeatureToProject.test.js → AddFeatureToProjectTool.test.js} +7 -7
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +3 -4
- package/mcp-server/tools/project/__tests__/{DeployProject.test.js → DeployProjectTool.test.js} +4 -4
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +198 -0
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +2 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/constants.d.ts +1 -0
- package/mcp-server/tools/project/constants.js +11 -0
- package/mcp-server/utils/__tests__/command.test.js +76 -3
- package/mcp-server/utils/command.d.ts +6 -0
- package/mcp-server/utils/command.js +19 -0
- package/package.json +2 -2
- package/mcp-server/utils/__tests__/project.test.js +0 -79
- package/mcp-server/utils/project.d.ts +0 -5
- package/mcp-server/utils/project.js +0 -14
- /package/mcp-server/tools/project/__tests__/{AddFeatureToProject.test.d.ts → AddFeatureToProjectTool.test.d.ts} +0 -0
- /package/mcp-server/tools/project/__tests__/{DeployProject.test.d.ts → DeployProjectTool.test.d.ts} +0 -0
- /package/mcp-server/{utils/__tests__/project.test.d.ts → tools/project/__tests__/GetConfigValuesTool.test.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getAccessToken, updateConfigWithAccessToken, } from '@hubspot/local-dev-lib/personalAccessKey';
|
|
2
2
|
import { accountNameExistsInConfig, updateAccountConfig, writeConfig, getAccountId, } from '@hubspot/local-dev-lib/config';
|
|
3
3
|
import { createDeveloperTestAccount, fetchDeveloperTestAccountGateSyncStatus, generateDeveloperTestAccountPersonalAccessKey, } from '@hubspot/local-dev-lib/api/developerTestAccounts';
|
|
4
|
-
import { createSandbox } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
4
|
+
import { createSandbox, createV2Sandbox, getSandboxPersonalAccessKey, } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
5
5
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
6
6
|
import { personalAccessKeyPrompt } from '../prompts/personalAccessKeyPrompt.js';
|
|
7
7
|
import { cliAccountNamePrompt } from '../prompts/accountNamePrompt.js';
|
|
@@ -33,6 +33,8 @@ const mockedCreateDeveloperTestAccount = createDeveloperTestAccount;
|
|
|
33
33
|
const mockedFetchDeveloperTestAccountGateSyncStatus = fetchDeveloperTestAccountGateSyncStatus;
|
|
34
34
|
const mockedGenerateDeveloperTestAccountPersonalAccessKey = generateDeveloperTestAccountPersonalAccessKey;
|
|
35
35
|
const mockedCreateSandbox = createSandbox;
|
|
36
|
+
const mockedCreateV2Sandbox = createV2Sandbox;
|
|
37
|
+
const mockedGetPersonalAccessKey = getSandboxPersonalAccessKey;
|
|
36
38
|
describe('lib/buildAccount', () => {
|
|
37
39
|
describe('saveAccountToConfig()', () => {
|
|
38
40
|
const mockAccountConfig = {
|
|
@@ -166,16 +168,17 @@ describe('lib/buildAccount', () => {
|
|
|
166
168
|
});
|
|
167
169
|
describe('buildSandbox()', () => {
|
|
168
170
|
const mockParentAccountConfig = {
|
|
169
|
-
name: '
|
|
171
|
+
name: 'Prod account',
|
|
170
172
|
accountId: 123456,
|
|
171
|
-
accountType: HUBSPOT_ACCOUNT_TYPES.
|
|
173
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.STANDARD,
|
|
172
174
|
env: 'prod',
|
|
173
175
|
};
|
|
174
176
|
const mockSandbox = {
|
|
175
177
|
sandboxHubId: 56789,
|
|
176
178
|
parentHubId: 123456,
|
|
177
179
|
createdAt: '2025-01-01',
|
|
178
|
-
type: '
|
|
180
|
+
type: 'STANDARD',
|
|
181
|
+
version: 'V1',
|
|
179
182
|
archived: false,
|
|
180
183
|
name: 'Test Sandbox',
|
|
181
184
|
domain: 'test-sandbox.hubspot.com',
|
|
@@ -221,4 +224,59 @@ describe('lib/buildAccount', () => {
|
|
|
221
224
|
await expect(buildAccount.buildSandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX, mockParentAccountConfig.env, false)).rejects.toThrow();
|
|
222
225
|
});
|
|
223
226
|
});
|
|
227
|
+
describe('buildV2Sandbox()', () => {
|
|
228
|
+
const mockParentAccountConfig = {
|
|
229
|
+
name: 'Prod account',
|
|
230
|
+
accountId: 123456,
|
|
231
|
+
accountType: HUBSPOT_ACCOUNT_TYPES.STANDARD,
|
|
232
|
+
env: 'prod',
|
|
233
|
+
};
|
|
234
|
+
const mockSandbox = {
|
|
235
|
+
sandboxHubId: 56789,
|
|
236
|
+
parentHubId: 123456,
|
|
237
|
+
createdAt: '2025-01-01',
|
|
238
|
+
type: 'STANDARD',
|
|
239
|
+
archived: false,
|
|
240
|
+
version: 'V2',
|
|
241
|
+
name: 'Test v2 Sandbox',
|
|
242
|
+
domain: 'test-v2-sandbox.hubspot.com',
|
|
243
|
+
createdByUser: {
|
|
244
|
+
id: 123456,
|
|
245
|
+
email: 'test@test.com',
|
|
246
|
+
firstName: 'Test',
|
|
247
|
+
lastName: 'User',
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
beforeEach(() => {
|
|
251
|
+
vi.spyOn(buildAccount, 'saveAccountToConfig').mockResolvedValue(mockParentAccountConfig.name);
|
|
252
|
+
mockedGetAccountId.mockReturnValue(mockParentAccountConfig.accountId);
|
|
253
|
+
mockedCreateV2Sandbox.mockResolvedValue({
|
|
254
|
+
data: mockSandbox,
|
|
255
|
+
});
|
|
256
|
+
mockedGetPersonalAccessKey.mockResolvedValue({
|
|
257
|
+
data: { personalAccessKey: { encodedOAuthRefreshToken: 'test-key' } },
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
afterEach(() => {
|
|
261
|
+
vi.clearAllMocks();
|
|
262
|
+
});
|
|
263
|
+
it('should create a v2 standard sandbox successfully and fetch a personal access key', async () => {
|
|
264
|
+
const result = await buildAccount.buildV2Sandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX, false, mockParentAccountConfig.env, false);
|
|
265
|
+
expect(result).toEqual({ sandbox: mockSandbox });
|
|
266
|
+
expect(mockedGetPersonalAccessKey).toHaveBeenCalledWith(mockParentAccountConfig.accountId, mockSandbox.sandboxHubId);
|
|
267
|
+
});
|
|
268
|
+
it('should create a development sandbox successfully and fetch a personal access key', async () => {
|
|
269
|
+
const result = await buildAccount.buildV2Sandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX, false, mockParentAccountConfig.env, false);
|
|
270
|
+
expect(result).toEqual({ sandbox: mockSandbox });
|
|
271
|
+
expect(mockedGetPersonalAccessKey).toHaveBeenCalledWith(mockParentAccountConfig.accountId, mockSandbox.sandboxHubId);
|
|
272
|
+
});
|
|
273
|
+
it('should throw error if account ID is not found', async () => {
|
|
274
|
+
mockedGetAccountId.mockReturnValue(null);
|
|
275
|
+
await expect(buildAccount.buildV2Sandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX, false, mockParentAccountConfig.env, false)).rejects.toThrow();
|
|
276
|
+
});
|
|
277
|
+
it('should handle API errors when creating sandbox', async () => {
|
|
278
|
+
mockedCreateV2Sandbox.mockRejectedValue(new Error('test-error'));
|
|
279
|
+
await expect(buildAccount.buildV2Sandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX, false, mockParentAccountConfig.env, false)).rejects.toThrow();
|
|
280
|
+
});
|
|
281
|
+
});
|
|
224
282
|
});
|
package/lib/buildAccount.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DeveloperTestAccountConfig } from '@hubspot/local-dev-lib/types/developerTestAccounts';
|
|
2
2
|
import { Environment } from '@hubspot/local-dev-lib/types/Config';
|
|
3
3
|
import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
|
|
4
|
-
import { SandboxResponse } from '@hubspot/local-dev-lib/types/Sandbox';
|
|
4
|
+
import { SandboxResponse, V2Sandbox } from '@hubspot/local-dev-lib/types/Sandbox';
|
|
5
5
|
import { SandboxAccountType } from '../types/Sandboxes.js';
|
|
6
6
|
export declare function saveAccountToConfig(accountId: number | undefined, accountName: string, env: Environment, personalAccessKey?: string, force?: boolean): Promise<string>;
|
|
7
7
|
export declare function createDeveloperTestAccountV3(parentAccountId: number, testAccountConfig: DeveloperTestAccountConfig): Promise<{
|
|
@@ -14,4 +14,7 @@ type SandboxAccount = SandboxResponse & {
|
|
|
14
14
|
name: string;
|
|
15
15
|
};
|
|
16
16
|
export declare function buildSandbox(sandboxName: string, parentAccountConfig: CLIAccount, sandboxType: SandboxAccountType, env: Environment, force?: boolean): Promise<SandboxAccount>;
|
|
17
|
+
export declare function buildV2Sandbox(sandboxName: string, parentAccountConfig: CLIAccount, sandboxType: SandboxAccountType, syncObjectRecords: boolean, env: Environment, force?: boolean): Promise<{
|
|
18
|
+
sandbox: V2Sandbox;
|
|
19
|
+
}>;
|
|
17
20
|
export {};
|
package/lib/buildAccount.js
CHANGED
|
@@ -4,14 +4,14 @@ import { getAccountIdentifier } from '@hubspot/local-dev-lib/config/getAccountId
|
|
|
4
4
|
import { logger } from '@hubspot/local-dev-lib/logger';
|
|
5
5
|
import { createDeveloperTestAccount, fetchDeveloperTestAccountGateSyncStatus, generateDeveloperTestAccountPersonalAccessKey, } from '@hubspot/local-dev-lib/api/developerTestAccounts';
|
|
6
6
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
7
|
-
import { createSandbox } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
7
|
+
import { createSandbox, createV2Sandbox, getSandboxPersonalAccessKey, } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
8
8
|
import { personalAccessKeyPrompt } from './prompts/personalAccessKeyPrompt.js';
|
|
9
9
|
import { createDeveloperTestAccountConfigPrompt } from './prompts/createDeveloperTestAccountConfigPrompt.js';
|
|
10
10
|
import { i18n } from './lang.js';
|
|
11
11
|
import { cliAccountNamePrompt } from './prompts/accountNamePrompt.js';
|
|
12
12
|
import SpinniesManager from './ui/SpinniesManager.js';
|
|
13
13
|
import { debugError, logError } from './errorHandlers/index.js';
|
|
14
|
-
import { SANDBOX_API_TYPE_MAP, handleSandboxCreateError } from './sandboxes.js';
|
|
14
|
+
import { SANDBOX_API_TYPE_MAP, SANDBOX_TYPE_MAP_V2, handleSandboxCreateError, } from './sandboxes.js';
|
|
15
15
|
import { handleDeveloperTestAccountCreateError } from './developerTestAccounts.js';
|
|
16
16
|
import { lib } from '../lang/en.js';
|
|
17
17
|
import { poll } from './polling.js';
|
|
@@ -199,3 +199,58 @@ export async function buildSandbox(sandboxName, parentAccountConfig, sandboxType
|
|
|
199
199
|
}
|
|
200
200
|
return sandbox;
|
|
201
201
|
}
|
|
202
|
+
export async function buildV2Sandbox(sandboxName, parentAccountConfig, sandboxType, syncObjectRecords, env, force = false) {
|
|
203
|
+
let i18nKey;
|
|
204
|
+
if (sandboxType === HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX) {
|
|
205
|
+
i18nKey = 'lib.sandbox.create.loading.standard';
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
i18nKey = 'lib.sandbox.create.loading.developer';
|
|
209
|
+
}
|
|
210
|
+
const id = getAccountIdentifier(parentAccountConfig);
|
|
211
|
+
const parentAccountId = getAccountId(id);
|
|
212
|
+
if (!parentAccountId) {
|
|
213
|
+
throw new Error(i18n(`${i18nKey}.fail`));
|
|
214
|
+
}
|
|
215
|
+
SpinniesManager.init({
|
|
216
|
+
succeedColor: 'white',
|
|
217
|
+
});
|
|
218
|
+
logger.log('');
|
|
219
|
+
SpinniesManager.add('buildV2Sandbox', {
|
|
220
|
+
text: i18n(`${i18nKey}.add`, {
|
|
221
|
+
accountName: sandboxName,
|
|
222
|
+
}),
|
|
223
|
+
});
|
|
224
|
+
let sandbox;
|
|
225
|
+
let pak;
|
|
226
|
+
try {
|
|
227
|
+
const sandboxTypeV2 = SANDBOX_TYPE_MAP_V2[sandboxType];
|
|
228
|
+
const { data } = await createV2Sandbox(parentAccountId, sandboxName, sandboxTypeV2, syncObjectRecords);
|
|
229
|
+
sandbox = { ...data };
|
|
230
|
+
const { data: { personalAccessKey }, } = await getSandboxPersonalAccessKey(parentAccountId, sandbox.sandboxHubId);
|
|
231
|
+
pak = personalAccessKey.encodedOAuthRefreshToken;
|
|
232
|
+
SpinniesManager.succeed('buildV2Sandbox', {
|
|
233
|
+
text: i18n(`${i18nKey}.succeed`, {
|
|
234
|
+
accountName: sandboxName,
|
|
235
|
+
accountId: sandbox.sandboxHubId,
|
|
236
|
+
}),
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
debugError(e);
|
|
241
|
+
SpinniesManager.fail('buildV2Sandbox', {
|
|
242
|
+
text: i18n(`${i18nKey}.fail`, {
|
|
243
|
+
accountName: sandboxName,
|
|
244
|
+
}),
|
|
245
|
+
});
|
|
246
|
+
handleSandboxCreateError(e, env, sandboxName, parentAccountId);
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
await saveAccountToConfig(sandbox.sandboxHubId, sandboxName, env, pak, force);
|
|
250
|
+
}
|
|
251
|
+
catch (err) {
|
|
252
|
+
logError(err);
|
|
253
|
+
throw err;
|
|
254
|
+
}
|
|
255
|
+
return { sandbox };
|
|
256
|
+
}
|
package/lib/commonOpts.js
CHANGED
|
@@ -7,6 +7,7 @@ import { debugError } from './errorHandlers/index.js';
|
|
|
7
7
|
import { EXIT_CODES } from './enums/exitCodes.js';
|
|
8
8
|
import { uiCommandReference } from './ui/index.js';
|
|
9
9
|
import { i18n } from './lang.js';
|
|
10
|
+
import { getTerminalUISupport, UI_COLORS } from './ui/index.js';
|
|
10
11
|
export function addGlobalOptions(yargs) {
|
|
11
12
|
yargs.version(false);
|
|
12
13
|
yargs.option('debug', {
|
|
@@ -76,8 +77,32 @@ export function addJSONOutputOptions(yargs) {
|
|
|
76
77
|
hidden: true,
|
|
77
78
|
});
|
|
78
79
|
}
|
|
80
|
+
// Remove this once we've upgraded to yargs 18.0.0
|
|
81
|
+
function uiBetaTagWithColor(message) {
|
|
82
|
+
const terminalUISupport = getTerminalUISupport();
|
|
83
|
+
const tag = i18n(`lib.ui.betaTagWithStyle`);
|
|
84
|
+
const result = `${terminalUISupport.color ? chalk.hex(UI_COLORS.SORBET)(tag) : tag} ${message}`;
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
// Remove this once we've upgraded to yargs 18.0.0
|
|
88
|
+
function uiDeprecatedTagWithColor(message) {
|
|
89
|
+
const terminalUISupport = getTerminalUISupport();
|
|
90
|
+
const tag = i18n(`lib.ui.deprecatedTagWithStyle`);
|
|
91
|
+
const result = `${terminalUISupport.color ? chalk.yellow(tag) : tag} ${message}`;
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
79
94
|
export async function addCustomHelpOutput(yargs, command, describe) {
|
|
80
95
|
try {
|
|
96
|
+
// Remove this once we've upgraded to yargs 18.0.0
|
|
97
|
+
if (describe && describe.includes(i18n(`lib.ui.betaTag`))) {
|
|
98
|
+
describe = describe.replace(i18n(`lib.ui.betaTag`) + ' ', '');
|
|
99
|
+
describe = uiBetaTagWithColor(describe);
|
|
100
|
+
}
|
|
101
|
+
// Remove this once we've upgraded to yargs 18.0.0
|
|
102
|
+
if (describe && describe.includes(i18n(`lib.ui.deprecatedTag`))) {
|
|
103
|
+
describe = describe.replace(i18n(`lib.ui.deprecatedTag`) + ' ', '');
|
|
104
|
+
describe = uiDeprecatedTagWithColor(describe);
|
|
105
|
+
}
|
|
81
106
|
const parsedArgv = yargsParser(process.argv.slice(2));
|
|
82
107
|
if (parsedArgv && parsedArgv.help) {
|
|
83
108
|
const commandBase = `hs ${parsedArgv._.slice(0, -1).join(' ')}`;
|
package/lib/constants.d.ts
CHANGED
|
@@ -78,6 +78,8 @@ export declare const APP_AUTH_TYPES: {
|
|
|
78
78
|
export declare const FEATURES: {
|
|
79
79
|
readonly UNIFIED_THEME_PREVIEW: "cms:react:unifiedThemePreview";
|
|
80
80
|
readonly UNIFIED_APPS: "Developers:UnifiedApps:PrivateBeta";
|
|
81
|
+
readonly SANDBOXES_V2: "sandboxes:v2:enabled";
|
|
82
|
+
readonly SANDBOXES_V2_CLI: "sandboxes:v2:cliEnabled";
|
|
81
83
|
};
|
|
82
84
|
export declare const LOCAL_DEV_UI_MESSAGE_SEND_TYPES: {
|
|
83
85
|
UPLOAD_SUCCESS: string;
|
|
@@ -111,3 +113,5 @@ export declare const LOCAL_DEV_SERVER_MESSAGE_TYPES: {
|
|
|
111
113
|
export declare const CONFIG_LOCAL_STATE_FLAGS: {
|
|
112
114
|
readonly LOCAL_DEV_UI_WELCOME: "LOCAL_DEV_UI_WELCOME";
|
|
113
115
|
};
|
|
116
|
+
export declare const EMPTY_PROJECT = "empty";
|
|
117
|
+
export declare const PROJECT_WITH_APP = "app";
|
package/lib/constants.js
CHANGED
|
@@ -70,6 +70,8 @@ export const APP_AUTH_TYPES = {
|
|
|
70
70
|
export const FEATURES = {
|
|
71
71
|
UNIFIED_THEME_PREVIEW: 'cms:react:unifiedThemePreview',
|
|
72
72
|
UNIFIED_APPS: 'Developers:UnifiedApps:PrivateBeta',
|
|
73
|
+
SANDBOXES_V2: 'sandboxes:v2:enabled',
|
|
74
|
+
SANDBOXES_V2_CLI: 'sandboxes:v2:cliEnabled',
|
|
73
75
|
};
|
|
74
76
|
export const LOCAL_DEV_UI_MESSAGE_SEND_TYPES = {
|
|
75
77
|
UPLOAD_SUCCESS: 'server:uploadSuccess',
|
|
@@ -103,3 +105,5 @@ export const LOCAL_DEV_SERVER_MESSAGE_TYPES = {
|
|
|
103
105
|
export const CONFIG_LOCAL_STATE_FLAGS = {
|
|
104
106
|
LOCAL_DEV_UI_WELCOME: 'LOCAL_DEV_UI_WELCOME',
|
|
105
107
|
};
|
|
108
|
+
export const EMPTY_PROJECT = 'empty';
|
|
109
|
+
export const PROJECT_WITH_APP = 'app';
|
|
@@ -5,6 +5,7 @@ import { shouldSuppressError } from './suppressError.js';
|
|
|
5
5
|
import { i18n } from '../lang.js';
|
|
6
6
|
import util from 'util';
|
|
7
7
|
import { uiCommandReference } from '../ui/index.js';
|
|
8
|
+
import { isProjectValidationError } from '../errors/ProjectValidationError.js';
|
|
8
9
|
export function logError(error, context) {
|
|
9
10
|
debugError(error, context);
|
|
10
11
|
if (isProjectValidationError(error)) {
|
|
@@ -84,9 +85,6 @@ export class ApiErrorContext {
|
|
|
84
85
|
this.projectName = props.projectName || '';
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
|
-
function isProjectValidationError(error) {
|
|
88
|
-
return error instanceof Error && error.name === 'ProjectValidationError';
|
|
89
|
-
}
|
|
90
88
|
function isErrorWithMessageOrReason(error) {
|
|
91
89
|
return (typeof error === 'object' &&
|
|
92
90
|
error !== null &&
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export default class ProjectValidationError extends Error {
|
|
2
|
+
constructor(message, options) {
|
|
3
|
+
super(message, options);
|
|
4
|
+
this.name = 'ProjectValidationError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
export function isProjectValidationError(err) {
|
|
8
|
+
return err instanceof ProjectValidationError;
|
|
9
|
+
}
|
package/lib/mcp/setup.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export declare const supportedTools: ({
|
|
|
7
7
|
} | {
|
|
8
8
|
name: "Windsurf";
|
|
9
9
|
value: string;
|
|
10
|
+
} | {
|
|
11
|
+
name: "VSCode";
|
|
12
|
+
value: string;
|
|
10
13
|
})[];
|
|
11
14
|
interface McpCommand {
|
|
12
15
|
command: string;
|
|
@@ -15,6 +18,7 @@ interface McpCommand {
|
|
|
15
18
|
export declare function addMintlifyMcpServer(installTargets: string[]): Promise<void>;
|
|
16
19
|
export declare function setupMintlify(derivedTargets?: string[]): Promise<boolean>;
|
|
17
20
|
export declare function addMcpServerToConfig(targets: string[] | undefined): Promise<string[]>;
|
|
21
|
+
export declare function setupVsCode(mcpCommand?: McpCommand): Promise<boolean>;
|
|
18
22
|
export declare function setupClaudeCode(mcpCommand?: McpCommand): Promise<boolean>;
|
|
19
23
|
export declare function setupCursor(mcpCommand?: McpCommand): boolean;
|
|
20
24
|
export declare function setupWindsurf(mcpCommand?: McpCommand): boolean;
|
package/lib/mcp/setup.js
CHANGED
|
@@ -13,11 +13,13 @@ const mcpServerName = 'hubspot-cli-mcp';
|
|
|
13
13
|
const claudeCode = 'claude';
|
|
14
14
|
const windsurf = 'windsurf';
|
|
15
15
|
const cursor = 'cursor';
|
|
16
|
+
const vscode = 'vscode';
|
|
16
17
|
const supportedMintlifyClients = [windsurf, cursor];
|
|
17
18
|
export const supportedTools = [
|
|
18
19
|
{ name: commands.mcp.setup.claudeCode, value: claudeCode },
|
|
19
20
|
{ name: commands.mcp.setup.cursor, value: cursor },
|
|
20
21
|
{ name: commands.mcp.setup.windsurf, value: windsurf },
|
|
22
|
+
{ name: commands.mcp.setup.vsCode, value: vscode },
|
|
21
23
|
];
|
|
22
24
|
const defaultMcpCommand = {
|
|
23
25
|
command: 'hs',
|
|
@@ -75,6 +77,9 @@ export async function addMcpServerToConfig(targets) {
|
|
|
75
77
|
if (derivedTargets.includes(windsurf)) {
|
|
76
78
|
await runSetupFunction(setupWindsurf);
|
|
77
79
|
}
|
|
80
|
+
if (derivedTargets.includes(vscode)) {
|
|
81
|
+
await runSetupFunction(setupVsCode);
|
|
82
|
+
}
|
|
78
83
|
uiLogger.info(commands.mcp.setup.success(derivedTargets));
|
|
79
84
|
return derivedTargets;
|
|
80
85
|
}
|
|
@@ -150,6 +155,37 @@ function setupMcpConfigFile(config) {
|
|
|
150
155
|
return false;
|
|
151
156
|
}
|
|
152
157
|
}
|
|
158
|
+
export async function setupVsCode(mcpCommand = defaultMcpCommand) {
|
|
159
|
+
try {
|
|
160
|
+
SpinniesManager.add('vsCode', {
|
|
161
|
+
text: commands.mcp.setup.spinners.configuringVsCode,
|
|
162
|
+
});
|
|
163
|
+
const mcpConfig = JSON.stringify({
|
|
164
|
+
name: mcpServerName,
|
|
165
|
+
...buildCommandWithAgentString(mcpCommand, vscode),
|
|
166
|
+
});
|
|
167
|
+
await execAsync(`code --add-mcp '${mcpConfig}'`);
|
|
168
|
+
SpinniesManager.succeed('vsCode', {
|
|
169
|
+
text: commands.mcp.setup.spinners.configuredVsCode,
|
|
170
|
+
});
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
if (error instanceof Error &&
|
|
175
|
+
error.message.includes('code: command not found')) {
|
|
176
|
+
SpinniesManager.fail('vsCode', {
|
|
177
|
+
text: commands.mcp.setup.spinners.vsCodeNotFound,
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
SpinniesManager.fail('vsCode', {
|
|
182
|
+
text: commands.mcp.setup.spinners.failedToConfigureVsCode,
|
|
183
|
+
});
|
|
184
|
+
logError(error);
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
153
189
|
export async function setupClaudeCode(mcpCommand = defaultMcpCommand) {
|
|
154
190
|
try {
|
|
155
191
|
SpinniesManager.add('claudeCode', {
|
|
@@ -16,6 +16,7 @@ vi.mock('@hubspot/ui-extensions-dev-server', () => ({
|
|
|
16
16
|
cleanup: vi.fn().mockResolvedValue(undefined),
|
|
17
17
|
},
|
|
18
18
|
}));
|
|
19
|
+
vi.mock('open');
|
|
19
20
|
vi.mock('@hubspot/project-parsing-lib');
|
|
20
21
|
vi.mock('../upload');
|
|
21
22
|
vi.mock('../config');
|
|
@@ -306,4 +307,38 @@ describe('LocalDevProcess', () => {
|
|
|
306
307
|
expect(listener).toHaveBeenCalledWith(process.projectNodes);
|
|
307
308
|
});
|
|
308
309
|
});
|
|
310
|
+
describe('removeStateListener()', () => {
|
|
311
|
+
it('should remove state listener', () => {
|
|
312
|
+
const listener = vi.fn();
|
|
313
|
+
const key = 'projectNodes';
|
|
314
|
+
// Add the listener first
|
|
315
|
+
process.addStateListener(key, listener);
|
|
316
|
+
// Trigger state change to verify listener is called
|
|
317
|
+
// @ts-expect-error
|
|
318
|
+
process.state.projectNodes = {};
|
|
319
|
+
expect(listener).toHaveBeenCalledTimes(1);
|
|
320
|
+
// Remove the listener
|
|
321
|
+
process.removeStateListener(key, listener);
|
|
322
|
+
// Trigger state change again to verify listener is no longer called
|
|
323
|
+
// @ts-expect-error
|
|
324
|
+
process.state.projectNodes = { newNode: { uid: 'newNode' } };
|
|
325
|
+
expect(listener).toHaveBeenCalledTimes(1); // Should still be 1, not 2
|
|
326
|
+
});
|
|
327
|
+
it('should not affect other listeners when removing one', () => {
|
|
328
|
+
const listener1 = vi.fn();
|
|
329
|
+
const listener2 = vi.fn();
|
|
330
|
+
const key = 'projectNodes';
|
|
331
|
+
// Add two listeners
|
|
332
|
+
process.addStateListener(key, listener1);
|
|
333
|
+
process.addStateListener(key, listener2);
|
|
334
|
+
// Remove only the first listener
|
|
335
|
+
process.removeStateListener(key, listener1);
|
|
336
|
+
// Trigger state change
|
|
337
|
+
// @ts-expect-error
|
|
338
|
+
process.state.projectNodes = {};
|
|
339
|
+
// Only listener2 should be called
|
|
340
|
+
expect(listener1).not.toHaveBeenCalled();
|
|
341
|
+
expect(listener2).toHaveBeenCalled();
|
|
342
|
+
});
|
|
343
|
+
});
|
|
309
344
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { WebSocketServer } from 'ws';
|
|
2
2
|
import { isPortManagerServerRunning, requestPorts, } from '@hubspot/local-dev-lib/portManager';
|
|
3
3
|
import { logger } from '@hubspot/local-dev-lib/logger';
|
|
4
|
-
import { LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES, LOCAL_DEV_SERVER_MESSAGE_TYPES, } from '../../constants.js';
|
|
4
|
+
import { LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES, LOCAL_DEV_UI_MESSAGE_SEND_TYPES, LOCAL_DEV_SERVER_MESSAGE_TYPES, } from '../../constants.js';
|
|
5
5
|
import LocalDevWebsocketServer from '../localDev/LocalDevWebsocketServer.js';
|
|
6
6
|
import { lib } from '../../../lang/en.js';
|
|
7
7
|
vi.mock('ws');
|
|
@@ -29,6 +29,7 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
29
29
|
// Setup mock LocalDevProcess
|
|
30
30
|
mockLocalDevProcess = {
|
|
31
31
|
addStateListener: vi.fn(),
|
|
32
|
+
removeStateListener: vi.fn(),
|
|
32
33
|
uploadProject: vi.fn(),
|
|
33
34
|
sendDevServerMessage: vi.fn(),
|
|
34
35
|
};
|
|
@@ -167,4 +168,172 @@ describe('LocalDevWebsocketServer', () => {
|
|
|
167
168
|
expect(mockWebSocketServer.close).toHaveBeenCalled();
|
|
168
169
|
});
|
|
169
170
|
});
|
|
171
|
+
describe('multiple connections', () => {
|
|
172
|
+
let mockWebSocket1;
|
|
173
|
+
let mockWebSocket2;
|
|
174
|
+
let mockWebSocket3;
|
|
175
|
+
let connectionCallback;
|
|
176
|
+
beforeEach(async () => {
|
|
177
|
+
// Setup multiple mock WebSockets
|
|
178
|
+
mockWebSocket1 = {
|
|
179
|
+
on: vi.fn(),
|
|
180
|
+
send: vi.fn(),
|
|
181
|
+
close: vi.fn(),
|
|
182
|
+
};
|
|
183
|
+
mockWebSocket2 = {
|
|
184
|
+
on: vi.fn(),
|
|
185
|
+
send: vi.fn(),
|
|
186
|
+
close: vi.fn(),
|
|
187
|
+
};
|
|
188
|
+
mockWebSocket3 = {
|
|
189
|
+
on: vi.fn(),
|
|
190
|
+
send: vi.fn(),
|
|
191
|
+
close: vi.fn(),
|
|
192
|
+
};
|
|
193
|
+
// Start the server
|
|
194
|
+
isPortManagerServerRunning.mockResolvedValue(true);
|
|
195
|
+
requestPorts.mockResolvedValue({
|
|
196
|
+
'local-dev-ui-websocket-server': 1234,
|
|
197
|
+
});
|
|
198
|
+
await server.start();
|
|
199
|
+
// Get the connection callback
|
|
200
|
+
connectionCallback = mockWebSocketServer.on.mock.calls[0][1];
|
|
201
|
+
});
|
|
202
|
+
it('should handle multiple valid connections simultaneously', () => {
|
|
203
|
+
// Establish three connections from valid origins
|
|
204
|
+
connectionCallback(mockWebSocket1, {
|
|
205
|
+
headers: { origin: 'https://app.hubspot.com' },
|
|
206
|
+
});
|
|
207
|
+
connectionCallback(mockWebSocket2, {
|
|
208
|
+
headers: { origin: 'https://app.hubspotqa.com' },
|
|
209
|
+
});
|
|
210
|
+
connectionCallback(mockWebSocket3, {
|
|
211
|
+
headers: { origin: 'https://local.hubspot.com' },
|
|
212
|
+
});
|
|
213
|
+
// All connections should be established with proper setup
|
|
214
|
+
expect(mockWebSocket1.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
215
|
+
expect(mockWebSocket2.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
216
|
+
expect(mockWebSocket3.on).toHaveBeenCalledWith('message', expect.any(Function));
|
|
217
|
+
// Each connection should trigger state listener setup
|
|
218
|
+
expect(mockLocalDevProcess.addStateListener).toHaveBeenCalledTimes(6); // 2 listeners per connection * 3 connections
|
|
219
|
+
// Each connection should trigger dev server message
|
|
220
|
+
expect(mockLocalDevProcess.sendDevServerMessage).toHaveBeenCalledTimes(3);
|
|
221
|
+
expect(mockLocalDevProcess.sendDevServerMessage).toHaveBeenCalledWith(LOCAL_DEV_SERVER_MESSAGE_TYPES.WEBSOCKET_SERVER_CONNECTED);
|
|
222
|
+
// No connections should be closed
|
|
223
|
+
expect(mockWebSocket1.close).not.toHaveBeenCalled();
|
|
224
|
+
expect(mockWebSocket2.close).not.toHaveBeenCalled();
|
|
225
|
+
expect(mockWebSocket3.close).not.toHaveBeenCalled();
|
|
226
|
+
});
|
|
227
|
+
it('should send project data to each connection independently', () => {
|
|
228
|
+
// Setup mock project data properties as getters
|
|
229
|
+
Object.defineProperty(mockLocalDevProcess, 'projectName', {
|
|
230
|
+
get: () => 'test-project',
|
|
231
|
+
configurable: true,
|
|
232
|
+
});
|
|
233
|
+
Object.defineProperty(mockLocalDevProcess, 'projectId', {
|
|
234
|
+
get: () => 123,
|
|
235
|
+
configurable: true,
|
|
236
|
+
});
|
|
237
|
+
Object.defineProperty(mockLocalDevProcess, 'targetProjectAccountId', {
|
|
238
|
+
get: () => 456,
|
|
239
|
+
configurable: true,
|
|
240
|
+
});
|
|
241
|
+
Object.defineProperty(mockLocalDevProcess, 'targetTestingAccountId', {
|
|
242
|
+
get: () => 789,
|
|
243
|
+
configurable: true,
|
|
244
|
+
});
|
|
245
|
+
// Establish multiple connections
|
|
246
|
+
connectionCallback(mockWebSocket1, {
|
|
247
|
+
headers: { origin: 'https://app.hubspot.com' },
|
|
248
|
+
});
|
|
249
|
+
connectionCallback(mockWebSocket2, {
|
|
250
|
+
headers: { origin: 'https://app.hubspotqa.com' },
|
|
251
|
+
});
|
|
252
|
+
// Each websocket should receive project data
|
|
253
|
+
expect(mockWebSocket1.send).toHaveBeenCalledWith(JSON.stringify({
|
|
254
|
+
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_PROJECT_DATA,
|
|
255
|
+
data: {
|
|
256
|
+
projectName: 'test-project',
|
|
257
|
+
projectId: 123,
|
|
258
|
+
targetProjectAccountId: 456,
|
|
259
|
+
targetTestingAccountId: 789,
|
|
260
|
+
},
|
|
261
|
+
}));
|
|
262
|
+
expect(mockWebSocket2.send).toHaveBeenCalledWith(JSON.stringify({
|
|
263
|
+
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_PROJECT_DATA,
|
|
264
|
+
data: {
|
|
265
|
+
projectName: 'test-project',
|
|
266
|
+
projectId: 123,
|
|
267
|
+
targetProjectAccountId: 456,
|
|
268
|
+
targetTestingAccountId: 789,
|
|
269
|
+
},
|
|
270
|
+
}));
|
|
271
|
+
});
|
|
272
|
+
it('should properly cleanup listeners when connections close', () => {
|
|
273
|
+
// Establish connections
|
|
274
|
+
connectionCallback(mockWebSocket1, {
|
|
275
|
+
headers: { origin: 'https://app.hubspot.com' },
|
|
276
|
+
});
|
|
277
|
+
connectionCallback(mockWebSocket2, {
|
|
278
|
+
headers: { origin: 'https://app.hubspotqa.com' },
|
|
279
|
+
});
|
|
280
|
+
// Get all the close callbacks for both connections (there should be 2 per connection)
|
|
281
|
+
const closeCallbacks1 = mockWebSocket1.on.mock.calls
|
|
282
|
+
.filter(call => call[0] === 'close')
|
|
283
|
+
.map(call => call[1]);
|
|
284
|
+
const closeCallbacks2 = mockWebSocket2.on.mock.calls
|
|
285
|
+
.filter(call => call[0] === 'close')
|
|
286
|
+
.map(call => call[1]);
|
|
287
|
+
expect(closeCallbacks1).toHaveLength(2); // projectNodes and appData listeners
|
|
288
|
+
expect(closeCallbacks2).toHaveLength(2); // projectNodes and appData listeners
|
|
289
|
+
// Simulate first connection closing (call all close callbacks)
|
|
290
|
+
closeCallbacks1.forEach(callback => callback());
|
|
291
|
+
// Should have removed listeners for first connection (2 listeners: projectNodes and appData)
|
|
292
|
+
expect(mockLocalDevProcess.removeStateListener).toHaveBeenCalledTimes(2);
|
|
293
|
+
// Simulate second connection closing
|
|
294
|
+
closeCallbacks2.forEach(callback => callback());
|
|
295
|
+
// Should have removed listeners for second connection as well
|
|
296
|
+
expect(mockLocalDevProcess.removeStateListener).toHaveBeenCalledTimes(4);
|
|
297
|
+
});
|
|
298
|
+
it('should broadcast state changes to all connected clients', () => {
|
|
299
|
+
// Establish connections
|
|
300
|
+
connectionCallback(mockWebSocket1, {
|
|
301
|
+
headers: { origin: 'https://app.hubspot.com' },
|
|
302
|
+
});
|
|
303
|
+
connectionCallback(mockWebSocket2, {
|
|
304
|
+
headers: { origin: 'https://app.hubspotqa.com' },
|
|
305
|
+
});
|
|
306
|
+
// Get the projectNodes listeners that were registered
|
|
307
|
+
const projectNodesListeners = mockLocalDevProcess.addStateListener.mock.calls
|
|
308
|
+
.filter(call => call[0] === 'projectNodes')
|
|
309
|
+
.map(call => call[1]);
|
|
310
|
+
expect(projectNodesListeners).toHaveLength(2);
|
|
311
|
+
// Simulate a project nodes update by calling the listeners
|
|
312
|
+
const mockProjectNodes = {
|
|
313
|
+
component1: {
|
|
314
|
+
uid: 'component1',
|
|
315
|
+
componentType: 'APP',
|
|
316
|
+
localDev: {
|
|
317
|
+
componentRoot: '/test/path',
|
|
318
|
+
componentConfigPath: '/test/path/config.json',
|
|
319
|
+
configUpdatedSinceLastUpload: false,
|
|
320
|
+
},
|
|
321
|
+
componentDeps: {},
|
|
322
|
+
metaFilePath: '/test/path',
|
|
323
|
+
config: {},
|
|
324
|
+
files: [],
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
projectNodesListeners.forEach(listener => listener(mockProjectNodes));
|
|
328
|
+
// Both websockets should receive the update
|
|
329
|
+
expect(mockWebSocket1.send).toHaveBeenCalledWith(JSON.stringify({
|
|
330
|
+
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_PROJECT_NODES,
|
|
331
|
+
data: mockProjectNodes,
|
|
332
|
+
}));
|
|
333
|
+
expect(mockWebSocket2.send).toHaveBeenCalledWith(JSON.stringify({
|
|
334
|
+
type: LOCAL_DEV_UI_MESSAGE_SEND_TYPES.UPDATE_PROJECT_NODES,
|
|
335
|
+
data: mockProjectNodes,
|
|
336
|
+
}));
|
|
337
|
+
});
|
|
338
|
+
});
|
|
170
339
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { commands, lib } from '../../../lang/en.js';
|
|
2
2
|
import { getConfigForPlatformVersion } from '../create/legacy.js';
|
|
3
|
-
import { calculateComponentTemplateChoices, createV3App,
|
|
3
|
+
import { calculateComponentTemplateChoices, createV3App, } from '../create/v3.js';
|
|
4
|
+
import { PROJECT_WITH_APP } from '../../constants.js';
|
|
4
5
|
import path from 'path';
|
|
5
6
|
import fs from 'fs';
|
|
6
7
|
import { projectAddPromptV3 } from '../../prompts/projectAddPrompt.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { selectProjectTemplatePrompt, } from '../../prompts/selectProjectTemplatePrompt.js';
|
|
2
2
|
import { projectNameAndDestPrompt } from '../../prompts/projectNameAndDestPrompt.js';
|
|
3
|
-
import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, } from '../../constants.js';
|
|
3
|
+
import { DEFAULT_PROJECT_TEMPLATE_BRANCH, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, EMPTY_PROJECT, } from '../../constants.js';
|
|
4
4
|
import { useV3Api } from '../buildAndDeploy.js';
|
|
5
|
-
import {
|
|
5
|
+
import { v3ComponentFlow } from './v3.js';
|
|
6
6
|
import { getProjectTemplateListFromRepo } from './legacy.js';
|
|
7
7
|
import { uiLogger } from '../../ui/logger.js';
|
|
8
8
|
import { commands } from '../../../lang/en.js';
|
|
@@ -2,8 +2,6 @@ import { Separator } from '@inquirer/prompts';
|
|
|
2
2
|
import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects.js';
|
|
3
3
|
import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project.js';
|
|
4
4
|
import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt.js';
|
|
5
|
-
export declare const EMPTY_PROJECT = "empty";
|
|
6
|
-
export declare const PROJECT_WITH_APP = "app";
|
|
7
5
|
export declare function createV3App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
|
|
8
6
|
authType: string;
|
|
9
7
|
distribution: string;
|