@hubspot/cli 8.0.1-experimental.0 → 8.0.3-experimental.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +8 -5
- package/commands/__tests__/getStarted.test.js +12 -0
- package/commands/__tests__/project.test.js +30 -0
- package/commands/account/auth.js +8 -97
- package/commands/account/use.js +19 -4
- package/commands/cms/module/marketplace-validate.js +23 -5
- package/commands/cms/theme/marketplace-validate.js +25 -6
- package/commands/getStarted.d.ts +2 -1
- package/commands/getStarted.js +38 -15
- package/commands/mcp/__tests__/start.test.js +1 -67
- package/commands/mcp/setup.js +1 -2
- package/commands/mcp/start.js +1 -19
- package/commands/mcp.js +1 -2
- package/commands/project.js +22 -1
- package/lang/en.d.ts +53 -7
- package/lang/en.js +59 -13
- package/lib/CLIWebSocketServer.d.ts +28 -0
- package/lib/CLIWebSocketServer.js +91 -0
- package/lib/__tests__/CLIWebSocketServer.test.d.ts +1 -0
- package/lib/__tests__/CLIWebSocketServer.test.js +252 -0
- package/lib/__tests__/accountAuth.test.d.ts +1 -0
- package/lib/__tests__/accountAuth.test.js +258 -0
- package/lib/__tests__/commandSuggestion.test.d.ts +1 -0
- package/lib/__tests__/commandSuggestion.test.js +119 -0
- package/lib/accountAuth.d.ts +10 -0
- package/lib/accountAuth.js +105 -0
- package/lib/app/urls.d.ts +1 -0
- package/lib/app/urls.js +4 -0
- package/lib/commandSuggestion.d.ts +3 -0
- package/lib/commandSuggestion.js +45 -0
- package/lib/constants.d.ts +0 -1
- package/lib/constants.js +0 -1
- package/lib/errors/ProjectErrors.d.ts +15 -0
- package/lib/errors/ProjectErrors.js +30 -0
- package/lib/getStarted/getStartedV2.d.ts +7 -0
- package/lib/getStarted/getStartedV2.js +18 -0
- package/lib/getStartedV2Actions.d.ts +37 -0
- package/lib/getStartedV2Actions.js +146 -0
- package/lib/marketplaceValidate.d.ts +1 -1
- package/lib/marketplaceValidate.js +23 -41
- package/lib/mcp/__tests__/setup.test.js +0 -17
- package/lib/mcp/setup.d.ts +0 -1
- package/lib/mcp/setup.js +59 -103
- package/lib/projects/ProjectLogsManager.d.ts +12 -3
- package/lib/projects/ProjectLogsManager.js +70 -12
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +43 -175
- package/lib/projects/__tests__/ProjectLogsManager.test.js +131 -18
- package/lib/projects/__tests__/platformVersion.test.js +37 -1
- package/lib/projects/__tests__/projects.test.js +6 -2
- package/lib/projects/components.d.ts +6 -0
- package/lib/projects/components.js +1 -1
- package/lib/projects/config.js +9 -2
- package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -7
- package/lib/projects/localDev/LocalDevWebsocketServer.js +51 -98
- package/lib/projects/localDev/helpers/project.d.ts +4 -1
- package/lib/projects/localDev/helpers/project.js +13 -8
- package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +8 -7
- package/lib/projects/platformVersion.d.ts +8 -0
- package/lib/projects/platformVersion.js +31 -2
- package/lib/prompts/accountsPrompt.d.ts +2 -1
- package/lib/prompts/accountsPrompt.js +10 -2
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +20 -3
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +6 -10
- package/mcp-server/tools/project/CreateProjectTool.d.ts +24 -4
- package/mcp-server/tools/project/CreateProjectTool.js +5 -10
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +5 -8
- package/mcp-server/tools/project/GetBuildLogsTool.d.ts +2 -2
- package/mcp-server/tools/project/GetBuildLogsTool.js +3 -4
- package/mcp-server/tools/project/GetBuildStatusTool.d.ts +1 -1
- package/mcp-server/tools/project/GetBuildStatusTool.js +3 -4
- package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +6 -1
- package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -6
- package/mcp-server/tools/project/constants.d.ts +12 -1
- package/mcp-server/tools/project/constants.js +12 -16
- package/mcp-server/utils/__tests__/project.test.js +0 -125
- package/mcp-server/utils/project.js +0 -8
- package/package.json +10 -5
- package/types/LocalDev.d.ts +0 -4
- package/ui/components/ActionSection.d.ts +12 -0
- package/ui/components/ActionSection.js +25 -0
- package/ui/components/BoxWithTitle.d.ts +4 -2
- package/ui/components/BoxWithTitle.js +2 -2
- package/ui/components/FullScreen.d.ts +6 -0
- package/ui/components/FullScreen.js +13 -0
- package/ui/components/InputField.d.ts +10 -0
- package/ui/components/InputField.js +10 -0
- package/ui/components/SelectInput.d.ts +11 -0
- package/ui/components/SelectInput.js +59 -0
- package/ui/components/StatusIcon.d.ts +9 -0
- package/ui/components/StatusIcon.js +17 -0
- package/ui/components/getStarted/GetStartedFlow.d.ts +8 -0
- package/ui/components/getStarted/GetStartedFlow.js +136 -0
- package/ui/components/getStarted/reducer.d.ts +59 -0
- package/ui/components/getStarted/reducer.js +72 -0
- package/ui/components/getStarted/screens/ProjectSetupScreen.d.ts +16 -0
- package/ui/components/getStarted/screens/ProjectSetupScreen.js +39 -0
- package/ui/components/getStarted/screens/UploadScreen.d.ts +7 -0
- package/ui/components/getStarted/screens/UploadScreen.js +43 -0
- package/ui/components/getStarted/selectors.d.ts +2 -0
- package/ui/components/getStarted/selectors.js +1 -0
- package/ui/constants.d.ts +6 -0
- package/ui/constants.js +6 -0
- package/ui/lib/constants.d.ts +16 -0
- package/ui/lib/constants.js +16 -0
- package/ui/playground/fixtures.js +47 -0
- package/ui/render.d.ts +4 -0
- package/ui/render.js +31 -0
- package/ui/styles.d.ts +3 -0
- package/ui/styles.js +3 -0
|
@@ -19,9 +19,8 @@ const inputSchema = {
|
|
|
19
19
|
.describe('Optional: Specific build ID to inspect. If omitted, shows recent builds to help identify the latest build.'),
|
|
20
20
|
limit: z
|
|
21
21
|
.number()
|
|
22
|
-
.
|
|
23
|
-
.
|
|
24
|
-
.describe('Number of recent builds to fetch when buildId is not specified.'),
|
|
22
|
+
.describe('Number of recent builds to fetch when buildId is not specified. Defaults to 3 if not specified.')
|
|
23
|
+
.optional(),
|
|
25
24
|
};
|
|
26
25
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
27
26
|
const inputSchemaZodObject = z.object({ ...inputSchema });
|
|
@@ -127,7 +126,7 @@ export class GetBuildStatusTool extends Tool {
|
|
|
127
126
|
}
|
|
128
127
|
else {
|
|
129
128
|
const response = await fetchProjectBuilds(accountId, projectName, {
|
|
130
|
-
limit,
|
|
129
|
+
limit: limit || 3,
|
|
131
130
|
});
|
|
132
131
|
const { results } = response.data;
|
|
133
132
|
if (!results || results.length === 0) {
|
|
@@ -3,7 +3,12 @@ import { McpServer, RegisteredTool } from '@modelcontextprotocol/sdk/server/mcp.
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
declare const inputSchemaZodObject: z.ZodObject<{
|
|
5
5
|
absoluteCurrentWorkingDirectory: z.ZodString;
|
|
6
|
-
command: z.ZodOptional<z.
|
|
6
|
+
command: z.ZodOptional<z.ZodEnum<{
|
|
7
|
+
"hs auth": "hs auth";
|
|
8
|
+
"hs project create": "hs project create";
|
|
9
|
+
"hs project upload": "hs project upload";
|
|
10
|
+
"hs init": "hs init";
|
|
11
|
+
}>>;
|
|
7
12
|
}, z.core.$strip>;
|
|
8
13
|
type InputSchemaType = z.infer<typeof inputSchemaZodObject>;
|
|
9
14
|
export declare class GuidedWalkthroughTool extends Tool<InputSchemaType> {
|
|
@@ -14,12 +14,7 @@ const nextCommands = {
|
|
|
14
14
|
const inputSchema = {
|
|
15
15
|
absoluteCurrentWorkingDirectory,
|
|
16
16
|
command: z
|
|
17
|
-
.
|
|
18
|
-
z.literal('hs init'),
|
|
19
|
-
z.literal('hs auth'),
|
|
20
|
-
z.literal('hs project create'),
|
|
21
|
-
z.literal('hs project upload'),
|
|
22
|
-
])
|
|
17
|
+
.enum(['hs init', 'hs auth', 'hs project create', 'hs project upload'])
|
|
23
18
|
.describe('The command to learn more about. Start with `hs init`')
|
|
24
19
|
.optional(),
|
|
25
20
|
};
|
|
@@ -1,6 +1,17 @@
|
|
|
1
1
|
import z from 'zod';
|
|
2
2
|
export declare const absoluteProjectPath: z.ZodString;
|
|
3
3
|
export declare const absoluteCurrentWorkingDirectory: z.ZodString;
|
|
4
|
-
export declare const features: z.ZodOptional<z.ZodArray<z.
|
|
4
|
+
export declare const features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
5
|
+
card: "card";
|
|
6
|
+
settings: "settings";
|
|
7
|
+
"app-event": "app-event";
|
|
8
|
+
page: "page";
|
|
9
|
+
"workflow-action-tool": "workflow-action-tool";
|
|
10
|
+
webhooks: "webhooks";
|
|
11
|
+
"workflow-action": "workflow-action";
|
|
12
|
+
"app-function": "app-function";
|
|
13
|
+
"app-object": "app-object";
|
|
14
|
+
scim: "scim";
|
|
15
|
+
}>>>;
|
|
5
16
|
export declare const docsSearchQuery: z.ZodString;
|
|
6
17
|
export declare const docUrl: z.ZodString;
|
|
@@ -6,23 +6,19 @@ export const absoluteCurrentWorkingDirectory = z
|
|
|
6
6
|
.string()
|
|
7
7
|
.describe('The absolute path to the current working directory.');
|
|
8
8
|
export const features = z
|
|
9
|
-
.array(z.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
z.literal('app-object'),
|
|
21
|
-
z.literal('app-event'),
|
|
22
|
-
z.literal('scim'),
|
|
23
|
-
z.literal('page'),
|
|
9
|
+
.array(z.enum([
|
|
10
|
+
'card',
|
|
11
|
+
'settings',
|
|
12
|
+
'app-function',
|
|
13
|
+
'webhooks',
|
|
14
|
+
'workflow-action',
|
|
15
|
+
'workflow-action-tool',
|
|
16
|
+
'app-object',
|
|
17
|
+
'app-event',
|
|
18
|
+
'scim',
|
|
19
|
+
'page',
|
|
24
20
|
]))
|
|
25
|
-
.describe('The features to include in the project, multiple options can be selected')
|
|
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.')
|
|
26
22
|
.optional();
|
|
27
23
|
export const docsSearchQuery = z
|
|
28
24
|
.string()
|
|
@@ -136,130 +136,5 @@ describe('mcp-server/utils/project', () => {
|
|
|
136
136
|
env: expect.any(Object),
|
|
137
137
|
}));
|
|
138
138
|
});
|
|
139
|
-
it('should use npx -p @hubspot/cli when HUBSPOT_MCP_STANDALONE is true', async () => {
|
|
140
|
-
const originalEnv = process.env.HUBSPOT_MCP_STANDALONE;
|
|
141
|
-
process.env.HUBSPOT_MCP_STANDALONE = 'true';
|
|
142
|
-
const hsCommand = 'hs project upload';
|
|
143
|
-
const expectedResult = {
|
|
144
|
-
stdout: 'success',
|
|
145
|
-
stderr: '',
|
|
146
|
-
};
|
|
147
|
-
mockExistsSync.mockReturnValue(true);
|
|
148
|
-
mockExecAsync.mockResolvedValue(expectedResult);
|
|
149
|
-
await runCommandInDir(mockDirectory, hsCommand);
|
|
150
|
-
expect(mockExecAsync).toHaveBeenCalledWith('npx -p @hubspot/cli hs project upload --disable-usage-tracking "true"', expect.objectContaining({
|
|
151
|
-
cwd: mockResolvedPath,
|
|
152
|
-
env: expect.any(Object),
|
|
153
|
-
}));
|
|
154
|
-
// Restore original env
|
|
155
|
-
if (originalEnv === undefined) {
|
|
156
|
-
delete process.env.HUBSPOT_MCP_STANDALONE;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
process.env.HUBSPOT_MCP_STANDALONE = originalEnv;
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
it('should use regular hs command when HUBSPOT_MCP_STANDALONE is not set', async () => {
|
|
163
|
-
const originalEnv = process.env.HUBSPOT_MCP_STANDALONE;
|
|
164
|
-
delete process.env.HUBSPOT_MCP_STANDALONE;
|
|
165
|
-
const hsCommand = 'hs project upload';
|
|
166
|
-
const expectedResult = {
|
|
167
|
-
stdout: 'success',
|
|
168
|
-
stderr: '',
|
|
169
|
-
};
|
|
170
|
-
mockExistsSync.mockReturnValue(true);
|
|
171
|
-
mockExecAsync.mockResolvedValue(expectedResult);
|
|
172
|
-
await runCommandInDir(mockDirectory, hsCommand);
|
|
173
|
-
expect(mockExecAsync).toHaveBeenCalledWith('hs project upload --disable-usage-tracking "true"', expect.objectContaining({
|
|
174
|
-
cwd: mockResolvedPath,
|
|
175
|
-
env: expect.any(Object),
|
|
176
|
-
}));
|
|
177
|
-
// Restore original env
|
|
178
|
-
if (originalEnv !== undefined) {
|
|
179
|
-
process.env.HUBSPOT_MCP_STANDALONE = originalEnv;
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
it('should use npx -p @hubspot/cli for hs commands with flags in standalone mode', async () => {
|
|
183
|
-
const originalEnv = process.env.HUBSPOT_MCP_STANDALONE;
|
|
184
|
-
process.env.HUBSPOT_MCP_STANDALONE = 'true';
|
|
185
|
-
const hsCommand = 'hs project upload --profile prod';
|
|
186
|
-
const expectedResult = {
|
|
187
|
-
stdout: 'success',
|
|
188
|
-
stderr: '',
|
|
189
|
-
};
|
|
190
|
-
mockExistsSync.mockReturnValue(true);
|
|
191
|
-
mockExecAsync.mockResolvedValue(expectedResult);
|
|
192
|
-
await runCommandInDir(mockDirectory, hsCommand);
|
|
193
|
-
expect(mockExecAsync).toHaveBeenCalledWith('npx -p @hubspot/cli hs project upload --profile prod --disable-usage-tracking "true"', expect.objectContaining({
|
|
194
|
-
cwd: mockResolvedPath,
|
|
195
|
-
env: expect.any(Object),
|
|
196
|
-
}));
|
|
197
|
-
// Restore original env
|
|
198
|
-
if (originalEnv === undefined) {
|
|
199
|
-
delete process.env.HUBSPOT_MCP_STANDALONE;
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
process.env.HUBSPOT_MCP_STANDALONE = originalEnv;
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
it('should use pinned CLI version when HUBSPOT_CLI_VERSION is set in standalone mode', async () => {
|
|
206
|
-
const originalStandaloneEnv = process.env.HUBSPOT_MCP_STANDALONE;
|
|
207
|
-
const originalVersionEnv = process.env.HUBSPOT_CLI_VERSION;
|
|
208
|
-
process.env.HUBSPOT_MCP_STANDALONE = 'true';
|
|
209
|
-
process.env.HUBSPOT_CLI_VERSION = '8.0.0';
|
|
210
|
-
const hsCommand = 'hs project upload';
|
|
211
|
-
const expectedResult = {
|
|
212
|
-
stdout: 'success',
|
|
213
|
-
stderr: '',
|
|
214
|
-
};
|
|
215
|
-
mockExistsSync.mockReturnValue(true);
|
|
216
|
-
mockExecAsync.mockResolvedValue(expectedResult);
|
|
217
|
-
await runCommandInDir(mockDirectory, hsCommand);
|
|
218
|
-
expect(mockExecAsync).toHaveBeenCalledWith('npx -p @hubspot/cli@8.0.0 hs project upload --disable-usage-tracking "true"', expect.objectContaining({
|
|
219
|
-
cwd: mockResolvedPath,
|
|
220
|
-
env: expect.any(Object),
|
|
221
|
-
}));
|
|
222
|
-
// Restore original env
|
|
223
|
-
if (originalStandaloneEnv === undefined) {
|
|
224
|
-
delete process.env.HUBSPOT_MCP_STANDALONE;
|
|
225
|
-
}
|
|
226
|
-
else {
|
|
227
|
-
process.env.HUBSPOT_MCP_STANDALONE = originalStandaloneEnv;
|
|
228
|
-
}
|
|
229
|
-
if (originalVersionEnv === undefined) {
|
|
230
|
-
delete process.env.HUBSPOT_CLI_VERSION;
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
process.env.HUBSPOT_CLI_VERSION = originalVersionEnv;
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
it('should use latest CLI version when HUBSPOT_CLI_VERSION is not set in standalone mode', async () => {
|
|
237
|
-
const originalStandaloneEnv = process.env.HUBSPOT_MCP_STANDALONE;
|
|
238
|
-
const originalVersionEnv = process.env.HUBSPOT_CLI_VERSION;
|
|
239
|
-
process.env.HUBSPOT_MCP_STANDALONE = 'true';
|
|
240
|
-
delete process.env.HUBSPOT_CLI_VERSION;
|
|
241
|
-
const hsCommand = 'hs project upload';
|
|
242
|
-
const expectedResult = {
|
|
243
|
-
stdout: 'success',
|
|
244
|
-
stderr: '',
|
|
245
|
-
};
|
|
246
|
-
mockExistsSync.mockReturnValue(true);
|
|
247
|
-
mockExecAsync.mockResolvedValue(expectedResult);
|
|
248
|
-
await runCommandInDir(mockDirectory, hsCommand);
|
|
249
|
-
expect(mockExecAsync).toHaveBeenCalledWith('npx -p @hubspot/cli hs project upload --disable-usage-tracking "true"', expect.objectContaining({
|
|
250
|
-
cwd: mockResolvedPath,
|
|
251
|
-
env: expect.any(Object),
|
|
252
|
-
}));
|
|
253
|
-
// Restore original env
|
|
254
|
-
if (originalStandaloneEnv === undefined) {
|
|
255
|
-
delete process.env.HUBSPOT_MCP_STANDALONE;
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
process.env.HUBSPOT_MCP_STANDALONE = originalStandaloneEnv;
|
|
259
|
-
}
|
|
260
|
-
if (originalVersionEnv !== undefined) {
|
|
261
|
-
process.env.HUBSPOT_CLI_VERSION = originalVersionEnv;
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
139
|
});
|
|
265
140
|
});
|
|
@@ -7,14 +7,6 @@ export async function runCommandInDir(directory, command) {
|
|
|
7
7
|
}
|
|
8
8
|
let finalCommand = command;
|
|
9
9
|
if (command.startsWith('hs ')) {
|
|
10
|
-
// Check if running in standalone mode
|
|
11
|
-
if (process.env.HUBSPOT_MCP_STANDALONE === 'true') {
|
|
12
|
-
// Use pinned version if available, otherwise use latest
|
|
13
|
-
const cliPackage = process.env.HUBSPOT_CLI_VERSION
|
|
14
|
-
? `@hubspot/cli@8.0.1-experimental.0`
|
|
15
|
-
: '@hubspot/cli';
|
|
16
|
-
finalCommand = command.replace(/^hs /, `npx -y -p ${cliPackage} hs `);
|
|
17
|
-
}
|
|
18
10
|
finalCommand = addFlag(finalCommand, 'disable-usage-tracking', true);
|
|
19
11
|
}
|
|
20
12
|
return execAsync(finalCommand, {
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/cli",
|
|
3
|
-
"version": "8.0.
|
|
3
|
+
"version": "8.0.3-experimental.0",
|
|
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/cms-dev-server": "1.2.
|
|
9
|
+
"@hubspot/cms-dev-server": "1.2.16",
|
|
10
10
|
"@hubspot/local-dev-lib": "5.1.1",
|
|
11
|
-
"@hubspot/project-parsing-lib": "0.
|
|
11
|
+
"@hubspot/project-parsing-lib": "0.12.0",
|
|
12
12
|
"@hubspot/serverless-dev-runtime": "7.0.7",
|
|
13
|
-
"@hubspot/ui-extensions-dev-server": "1.1.
|
|
13
|
+
"@hubspot/ui-extensions-dev-server": "1.1.8",
|
|
14
14
|
"@inquirer/prompts": "7.1.0",
|
|
15
15
|
"@modelcontextprotocol/sdk": "1.25.0",
|
|
16
16
|
"archiver": "7.0.1",
|
|
@@ -22,6 +22,8 @@
|
|
|
22
22
|
"findup-sync": "4.0.0",
|
|
23
23
|
"fs-extra": "8.1.0",
|
|
24
24
|
"ink": "6.6.0",
|
|
25
|
+
"ink-spinner": "5.0.0",
|
|
26
|
+
"ink-text-input": "6.0.0",
|
|
25
27
|
"js-yaml": "4.1.0",
|
|
26
28
|
"minimatch": "10.0.1",
|
|
27
29
|
"moment": "2.30.1",
|
|
@@ -80,7 +82,7 @@
|
|
|
80
82
|
"list-all-commands": "yarn tsx ./scripts/get-all-commands.ts",
|
|
81
83
|
"local-link": "hubspot-linking",
|
|
82
84
|
"mcp-local": "yarn tsx ./scripts/mcp-local.ts",
|
|
83
|
-
"prettier:write": "prettier --write './**/*.{ts,js,json}'",
|
|
85
|
+
"prettier:write": "prettier --write './**/*.{ts,js,json,tsx}'",
|
|
84
86
|
"release": "yarn tsx ./scripts/release.ts release",
|
|
85
87
|
"sync-to-public": "yarn tsx ./scripts/sync-to-public.ts repo-sync",
|
|
86
88
|
"ink-playground": "yarn build && yarn tsx ./scripts/ink-playground.ts",
|
|
@@ -115,5 +117,8 @@
|
|
|
115
117
|
"publishConfig": {
|
|
116
118
|
"access": "public",
|
|
117
119
|
"registry": "https://registry.npmjs.org/"
|
|
120
|
+
},
|
|
121
|
+
"resolutions": {
|
|
122
|
+
"eslint-visitor-keys": "4.2.0"
|
|
118
123
|
}
|
|
119
124
|
}
|
package/types/LocalDev.d.ts
CHANGED
|
@@ -20,10 +20,6 @@ export type LocalDevStateConstructorOptions = {
|
|
|
20
20
|
initialProjectProfileData: HSProfileVariables;
|
|
21
21
|
env: Environment;
|
|
22
22
|
};
|
|
23
|
-
export type LocalDevWebsocketMessage = {
|
|
24
|
-
type: string;
|
|
25
|
-
data?: unknown;
|
|
26
|
-
};
|
|
27
23
|
export type LocalDevDeployWebsocketMessage = {
|
|
28
24
|
type: typeof LOCAL_DEV_UI_MESSAGE_RECEIVE_TYPES.DEPLOY;
|
|
29
25
|
data: {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ValueOf } from '@hubspot/local-dev-lib/types/Utils';
|
|
2
|
+
import { ACTION_STATUSES } from '../constants.js';
|
|
3
|
+
type ActionStatus = ValueOf<typeof ACTION_STATUSES>;
|
|
4
|
+
export type ActionSectionProps = {
|
|
5
|
+
status: ActionStatus;
|
|
6
|
+
statusText: string;
|
|
7
|
+
errorMessage?: string;
|
|
8
|
+
children?: React.ReactNode;
|
|
9
|
+
};
|
|
10
|
+
export declare function ActionSection({ status, statusText, errorMessage, children, }: ActionSectionProps): import("react/jsx-runtime").JSX.Element | null;
|
|
11
|
+
export declare function getActionSection(props: ActionSectionProps): React.ReactNode;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { ACTION_STATUSES } from '../constants.js';
|
|
4
|
+
import { INK_COLORS } from '../styles.js';
|
|
5
|
+
import { StatusIcon } from './StatusIcon.js';
|
|
6
|
+
const LEFT_BORDER_BOX_PROPS = {
|
|
7
|
+
flexDirection: 'column',
|
|
8
|
+
borderStyle: 'single',
|
|
9
|
+
borderColor: INK_COLORS.GRAY,
|
|
10
|
+
borderLeft: true,
|
|
11
|
+
borderTop: false,
|
|
12
|
+
borderRight: false,
|
|
13
|
+
borderBottom: false,
|
|
14
|
+
paddingLeft: 2,
|
|
15
|
+
marginLeft: 1,
|
|
16
|
+
};
|
|
17
|
+
export function ActionSection({ status, statusText, errorMessage, children, }) {
|
|
18
|
+
if (status === ACTION_STATUSES.IDLE) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { flexDirection: "row", columnGap: 1, children: [_jsx(StatusIcon, { status: status }), _jsx(Text, { children: statusText })] }), _jsxs(Box, { ...LEFT_BORDER_BOX_PROPS, children: [children, status === ACTION_STATUSES.ERROR && errorMessage && (_jsx(Text, { color: INK_COLORS.ALERT_RED, wrap: "wrap", children: errorMessage }))] })] }));
|
|
22
|
+
}
|
|
23
|
+
export function getActionSection(props) {
|
|
24
|
+
return _jsx(ActionSection, { ...props });
|
|
25
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export interface BoxWithTitleProps {
|
|
2
2
|
title: string;
|
|
3
|
-
message
|
|
3
|
+
message?: string;
|
|
4
4
|
titleBackgroundColor?: string;
|
|
5
5
|
borderColor?: string;
|
|
6
6
|
textCentered?: boolean;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
flexGrow?: number;
|
|
7
9
|
}
|
|
8
10
|
export declare function getBoxWithTitle(props: BoxWithTitleProps): React.ReactNode;
|
|
9
|
-
export declare function BoxWithTitle({ title, message, titleBackgroundColor, borderColor, textCentered, }: BoxWithTitleProps): React.ReactNode;
|
|
11
|
+
export declare function BoxWithTitle({ title, message, titleBackgroundColor, borderColor, textCentered, children, flexGrow, }: BoxWithTitleProps): React.ReactNode;
|
|
@@ -4,6 +4,6 @@ import { CONTAINER_STYLES } from '../styles.js';
|
|
|
4
4
|
export function getBoxWithTitle(props) {
|
|
5
5
|
return _jsx(BoxWithTitle, { ...props });
|
|
6
6
|
}
|
|
7
|
-
export function BoxWithTitle({ title, message, titleBackgroundColor, borderColor, textCentered, }) {
|
|
8
|
-
return (_jsxs(Box, { ...CONTAINER_STYLES, borderStyle: "round", borderColor: borderColor,
|
|
7
|
+
export function BoxWithTitle({ title, message, titleBackgroundColor, borderColor, textCentered, children, flexGrow, }) {
|
|
8
|
+
return (_jsxs(Box, { ...CONTAINER_STYLES, flexGrow: flexGrow, borderStyle: "round", borderColor: borderColor, children: [_jsx(Box, { position: "absolute", marginTop: -2, paddingX: 0, alignSelf: "flex-start", justifyContent: "center", alignItems: "center", children: _jsx(Text, { backgroundColor: titleBackgroundColor, bold: true, children: ` ${title} ` }) }), _jsxs(Box, { flexDirection: "column", width: "100%", rowGap: 1, children: [message?.split('\n\n').map((section, sectionIndex) => (_jsx(Box, { flexDirection: "column", alignItems: textCentered ? 'center' : 'flex-start', children: section.split('\n').map((line, lineIndex) => (_jsx(Text, { children: line }, `${sectionIndex}-${lineIndex}`))) }, sectionIndex))), children] })] }));
|
|
9
9
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box } from 'ink';
|
|
3
|
+
import { useTerminalSize } from '../lib/useTerminalSize.js';
|
|
4
|
+
export function FullScreen({ children }) {
|
|
5
|
+
// Use rows - 1 to prevent flickering
|
|
6
|
+
// See: https://github.com/vadimdemedes/ink/issues/359
|
|
7
|
+
const { rows, columns } = useTerminalSize();
|
|
8
|
+
const height = rows - 1;
|
|
9
|
+
return (_jsx(Box, { flexDirection: "column", width: columns, height: height, overflow: "hidden", children: children }));
|
|
10
|
+
}
|
|
11
|
+
export function getFullScreen(props) {
|
|
12
|
+
return _jsx(FullScreen, { ...props });
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type InputFieldProps = {
|
|
2
|
+
flag: string;
|
|
3
|
+
prompt: string;
|
|
4
|
+
value: string;
|
|
5
|
+
isEditing: boolean;
|
|
6
|
+
onChange: (value: string) => void;
|
|
7
|
+
onSubmit: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function InputField({ flag, prompt, value, isEditing, onChange, onSubmit, }: InputFieldProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export declare function getInputField(props: InputFieldProps): React.ReactNode;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import TextInput from 'ink-text-input';
|
|
4
|
+
import { INK_COLORS } from '../styles.js';
|
|
5
|
+
export function InputField({ flag, prompt, value, isEditing, onChange, onSubmit, }) {
|
|
6
|
+
return (_jsxs(Box, { flexDirection: "row", flexWrap: "wrap", columnGap: 1, marginBottom: 1, children: [_jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: "?" }), _jsxs(Text, { children: ["[--", flag, "] ", prompt] }), _jsx(Text, { color: INK_COLORS.INFO_BLUE, children: _jsx(TextInput, { focus: isEditing, value: value, onChange: onChange, onSubmit: onSubmit }) })] }));
|
|
7
|
+
}
|
|
8
|
+
export function getInputField(props) {
|
|
9
|
+
return _jsx(InputField, { ...props });
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type SelectInputItem = {
|
|
2
|
+
label: string;
|
|
3
|
+
value: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
};
|
|
6
|
+
export type SelectInputProps = {
|
|
7
|
+
items: SelectInputItem[];
|
|
8
|
+
onSelect: (item: SelectInputItem) => void;
|
|
9
|
+
};
|
|
10
|
+
export declare function SelectInput({ items, onSelect }: SelectInputProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function getSelectInput(props: SelectInputProps): React.ReactNode;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, useInput } from 'ink';
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { INK_COLORS } from '../styles.js';
|
|
5
|
+
export function SelectInput({ items, onSelect }) {
|
|
6
|
+
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
7
|
+
useInput((_, key) => {
|
|
8
|
+
if (key.upArrow) {
|
|
9
|
+
setSelectedIndex(prevIndex => {
|
|
10
|
+
let newIndex = prevIndex - 1;
|
|
11
|
+
if (newIndex < 0) {
|
|
12
|
+
newIndex = items.length - 1;
|
|
13
|
+
}
|
|
14
|
+
// Skip disabled items
|
|
15
|
+
while (items[newIndex]?.disabled && newIndex !== prevIndex) {
|
|
16
|
+
newIndex--;
|
|
17
|
+
if (newIndex < 0) {
|
|
18
|
+
newIndex = items.length - 1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return newIndex;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (key.downArrow) {
|
|
25
|
+
setSelectedIndex(prevIndex => {
|
|
26
|
+
let newIndex = prevIndex + 1;
|
|
27
|
+
if (newIndex >= items.length) {
|
|
28
|
+
newIndex = 0;
|
|
29
|
+
}
|
|
30
|
+
// Skip disabled items
|
|
31
|
+
while (items[newIndex]?.disabled && newIndex !== prevIndex) {
|
|
32
|
+
newIndex++;
|
|
33
|
+
if (newIndex >= items.length) {
|
|
34
|
+
newIndex = 0;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return newIndex;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (key.return) {
|
|
41
|
+
const selectedItem = items[selectedIndex];
|
|
42
|
+
if (selectedItem && !selectedItem.disabled) {
|
|
43
|
+
onSelect(selectedItem);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
return (_jsx(Box, { flexDirection: "column", children: items.map((item, index) => {
|
|
48
|
+
const isSelected = index === selectedIndex;
|
|
49
|
+
const isDisabled = item.disabled;
|
|
50
|
+
return (_jsxs(Box, { flexDirection: "row", columnGap: 1, children: [_jsx(Text, { color: isSelected ? INK_COLORS.INFO_BLUE : undefined, children: isSelected ? '❯' : ' ' }), _jsx(Text, { color: isDisabled
|
|
51
|
+
? INK_COLORS.GRAY
|
|
52
|
+
: isSelected
|
|
53
|
+
? INK_COLORS.INFO_BLUE
|
|
54
|
+
: undefined, dimColor: isDisabled, children: item.label })] }, item.value));
|
|
55
|
+
}) }));
|
|
56
|
+
}
|
|
57
|
+
export function getSelectInput(props) {
|
|
58
|
+
return _jsx(SelectInput, { ...props });
|
|
59
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ValueOf } from '@hubspot/local-dev-lib/types/Utils';
|
|
2
|
+
import { ACTION_STATUSES } from '../constants.js';
|
|
3
|
+
type ActionStatus = ValueOf<typeof ACTION_STATUSES>;
|
|
4
|
+
export type StatusIconProps = {
|
|
5
|
+
status: ActionStatus;
|
|
6
|
+
};
|
|
7
|
+
export declare function StatusIcon({ status }: StatusIconProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function getStatusIcon(props: StatusIconProps): React.ReactNode;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Text } from 'ink';
|
|
3
|
+
import Spinner from 'ink-spinner';
|
|
4
|
+
import { ACTION_STATUSES } from '../constants.js';
|
|
5
|
+
import { INK_COLORS } from '../styles.js';
|
|
6
|
+
export function StatusIcon({ status }) {
|
|
7
|
+
if (status === ACTION_STATUSES.ERROR) {
|
|
8
|
+
return _jsx(Text, { color: INK_COLORS.ALERT_RED, children: "\u00D7" });
|
|
9
|
+
}
|
|
10
|
+
if (status === ACTION_STATUSES.DONE) {
|
|
11
|
+
return _jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: "\u2713" });
|
|
12
|
+
}
|
|
13
|
+
return (_jsx(Text, { color: INK_COLORS.HUBSPOT_TEAL, children: _jsx(Spinner, { type: "dots" }) }));
|
|
14
|
+
}
|
|
15
|
+
export function getStatusIcon(props) {
|
|
16
|
+
return _jsx(StatusIcon, { ...props });
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const DEFAULT_PROJECT_NAME = "my-project";
|
|
2
|
+
export type GetStartedFlowProps = {
|
|
3
|
+
derivedAccountId: number;
|
|
4
|
+
initialName?: string;
|
|
5
|
+
initialDest?: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function getGetStartedFlow(props: GetStartedFlowProps): React.ReactNode;
|
|
8
|
+
export declare function GetStartedFlow({ derivedAccountId, initialName, initialDest, }: GetStartedFlowProps): import("react/jsx-runtime").JSX.Element;
|