@ollie-shop/cli 0.3.4 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/.turbo/turbo-build.log +6 -9
  2. package/CHANGELOG.md +27 -0
  3. package/dist/index.js +993 -3956
  4. package/package.json +15 -37
  5. package/src/README.md +126 -0
  6. package/src/cli.tsx +45 -0
  7. package/src/commands/help.tsx +79 -0
  8. package/src/commands/login.tsx +92 -0
  9. package/src/commands/start.tsx +411 -0
  10. package/src/index.tsx +8 -0
  11. package/src/utils/auth.ts +218 -21
  12. package/src/utils/bundle.ts +177 -0
  13. package/src/utils/config.ts +123 -0
  14. package/src/utils/esbuild.ts +541 -0
  15. package/tsconfig.json +10 -15
  16. package/tsup.config.ts +7 -7
  17. package/CLAUDE_CLI.md +0 -265
  18. package/README.md +0 -711
  19. package/__tests__/mocks/console.ts +0 -22
  20. package/__tests__/mocks/core.ts +0 -137
  21. package/__tests__/mocks/index.ts +0 -4
  22. package/__tests__/mocks/inquirer.ts +0 -16
  23. package/__tests__/mocks/progress.ts +0 -19
  24. package/dist/index.d.ts +0 -1
  25. package/src/__tests__/helpers/cli-test-helper.ts +0 -281
  26. package/src/__tests__/mocks/index.ts +0 -142
  27. package/src/actions/component.actions.ts +0 -278
  28. package/src/actions/function.actions.ts +0 -220
  29. package/src/actions/project.actions.ts +0 -131
  30. package/src/actions/version.actions.ts +0 -233
  31. package/src/commands/__tests__/component-validation.test.ts +0 -250
  32. package/src/commands/__tests__/component.test.ts +0 -318
  33. package/src/commands/__tests__/function-validation.test.ts +0 -220
  34. package/src/commands/__tests__/function.test.ts +0 -286
  35. package/src/commands/__tests__/store-version-validation.test.ts +0 -414
  36. package/src/commands/__tests__/store-version.test.ts +0 -402
  37. package/src/commands/component.ts +0 -178
  38. package/src/commands/docs.ts +0 -24
  39. package/src/commands/function.ts +0 -201
  40. package/src/commands/help.ts +0 -18
  41. package/src/commands/index.ts +0 -27
  42. package/src/commands/login.ts +0 -267
  43. package/src/commands/project.ts +0 -107
  44. package/src/commands/store-version.ts +0 -242
  45. package/src/commands/version.ts +0 -51
  46. package/src/commands/whoami.ts +0 -46
  47. package/src/index.ts +0 -116
  48. package/src/prompts/component.prompts.ts +0 -94
  49. package/src/prompts/function.prompts.ts +0 -168
  50. package/src/schemas/command.schema.ts +0 -644
  51. package/src/types/index.ts +0 -183
  52. package/src/utils/__tests__/command-parser.test.ts +0 -159
  53. package/src/utils/__tests__/command-suggestions.test.ts +0 -185
  54. package/src/utils/__tests__/console.test.ts +0 -192
  55. package/src/utils/__tests__/context-detector.test.ts +0 -258
  56. package/src/utils/__tests__/enhanced-error-handler.test.ts +0 -137
  57. package/src/utils/__tests__/error-handler.test.ts +0 -107
  58. package/src/utils/__tests__/rich-progress.test.ts +0 -181
  59. package/src/utils/__tests__/validation-error-formatter.test.ts +0 -175
  60. package/src/utils/__tests__/validation-helpers.test.ts +0 -125
  61. package/src/utils/cli-progress-reporter.ts +0 -84
  62. package/src/utils/command-builder.ts +0 -390
  63. package/src/utils/command-helpers.ts +0 -83
  64. package/src/utils/command-parser.ts +0 -245
  65. package/src/utils/command-suggestions.ts +0 -176
  66. package/src/utils/console.ts +0 -320
  67. package/src/utils/constants.ts +0 -39
  68. package/src/utils/context-detector.ts +0 -177
  69. package/src/utils/deploy-helpers.ts +0 -357
  70. package/src/utils/enhanced-error-handler.ts +0 -264
  71. package/src/utils/error-handler.ts +0 -60
  72. package/src/utils/errors.ts +0 -256
  73. package/src/utils/interactive-builder.ts +0 -325
  74. package/src/utils/rich-progress.ts +0 -331
  75. package/src/utils/store.ts +0 -23
  76. package/src/utils/validation-error-formatter.ts +0 -337
  77. package/src/utils/validation-helpers.ts +0 -325
  78. package/vitest.config.ts +0 -35
  79. package/vitest.setup.ts +0 -29
@@ -1,256 +0,0 @@
1
- import type { ZodError } from "zod";
2
- import type { ErrorContext } from "../types";
3
-
4
- /**
5
- * Recovery action that can be suggested to users when an error occurs
6
- * @interface RecoveryAction
7
- * @property {string} description - Human-readable description of the recovery action
8
- * @property {string} [command] - Optional CLI command that can help resolve the issue
9
- */
10
- export interface RecoveryAction {
11
- description: string;
12
- command?: string;
13
- }
14
-
15
- /**
16
- * Base error class for all Ollie Shop CLI errors
17
- * Provides context and recovery suggestions to help users resolve issues
18
- *
19
- * @class OllieShopCLIError
20
- * @extends {Error}
21
- * @example
22
- * ```typescript
23
- * throw new OllieShopCLIError(
24
- * "Component build failed",
25
- * { componentId: "123", path: "./src" },
26
- * [
27
- * { description: "Check your TypeScript configuration" },
28
- * { description: "Run validation", command: "ollieshop component validate" }
29
- * ]
30
- * );
31
- * ```
32
- */
33
- export class OllieShopCLIError extends Error {
34
- public readonly context: ErrorContext;
35
- public readonly recoveryActions: RecoveryAction[];
36
-
37
- /**
38
- * Creates a new OllieShopCLIError instance
39
- * @param {string} message - The error message
40
- * @param {ErrorContext} [context={}] - Additional context about the error
41
- * @param {RecoveryAction[]} [recoveryActions=[]] - Suggested actions to resolve the error
42
- */
43
- constructor(
44
- message: string,
45
- context: ErrorContext = {},
46
- recoveryActions: RecoveryAction[] = [],
47
- ) {
48
- super(message);
49
- this.name = "OllieShopCLIError";
50
- this.context = context;
51
- this.recoveryActions = recoveryActions;
52
- }
53
-
54
- /**
55
- * Get the error context details
56
- * @returns {ErrorContext} The error context object
57
- */
58
- get details(): ErrorContext {
59
- return this.context;
60
- }
61
-
62
- /**
63
- * Get suggested recovery actions
64
- * @returns {RecoveryAction[]} Array of recovery actions
65
- */
66
- get suggestions(): RecoveryAction[] {
67
- return this.recoveryActions;
68
- }
69
-
70
- /**
71
- * Create an OllieShopCLIError from a Zod validation error
72
- * Extracts the most relevant error message and provides validation-specific suggestions
73
- *
74
- * @static
75
- * @param {ZodError} error - The Zod validation error
76
- * @param {ErrorContext} [context={}] - Additional context to include
77
- * @returns {OllieShopCLIError} A new OllieShopCLIError instance
78
- * @example
79
- * ```typescript
80
- * try {
81
- * ComponentNameSchema.parse("Invalid Name!");
82
- * } catch (error) {
83
- * if (error instanceof ZodError) {
84
- * throw OllieShopCLIError.fromZodError(error, { field: "name" });
85
- * }
86
- * }
87
- * ```
88
- */
89
- static fromZodError(
90
- error: ZodError,
91
- context: ErrorContext = {},
92
- ): OllieShopCLIError {
93
- const firstIssue = error.issues[0];
94
- if (!firstIssue) {
95
- return new OllieShopCLIError("Validation failed", context);
96
- }
97
-
98
- const message =
99
- error.issues.length > 1
100
- ? `${firstIssue.message} (and ${error.issues.length - 1} more error${error.issues.length === 2 ? "" : "s"})`
101
- : firstIssue.message;
102
-
103
- return new OllieShopCLIError(message, context, [
104
- { description: "Check the command documentation for valid formats" },
105
- ]);
106
- }
107
-
108
- /**
109
- * Create an OllieShopCLIError from an unknown error type
110
- * Safely handles any error type and converts it to OllieShopCLIError
111
- *
112
- * @static
113
- * @param {unknown} error - Any error or value
114
- * @param {ErrorContext} [context={}] - Additional context to include
115
- * @returns {OllieShopCLIError} A new OllieShopCLIError instance
116
- * @example
117
- * ```typescript
118
- * try {
119
- * // some operation
120
- * } catch (error) {
121
- * throw OllieShopCLIError.fromUnknown(error, { operation: "deploy" });
122
- * }
123
- * ```
124
- */
125
- static fromUnknown(
126
- error: unknown,
127
- context: ErrorContext = {},
128
- ): OllieShopCLIError {
129
- if (error instanceof OllieShopCLIError) {
130
- return error;
131
- }
132
-
133
- if (error instanceof Error) {
134
- return new OllieShopCLIError(error.message, context, [
135
- { description: "Check the command syntax and try again" },
136
- ]);
137
- }
138
-
139
- return new OllieShopCLIError(
140
- String(error) || "Unknown error occurred",
141
- context,
142
- );
143
- }
144
-
145
- /**
146
- * Create a file not found error with helpful suggestions
147
- *
148
- * @static
149
- * @param {string} path - The file path that was not found
150
- * @param {ErrorContext} [context={}] - Additional context to include
151
- * @returns {OllieShopCLIError} A new OllieShopCLIError instance with file-specific suggestions
152
- * @example
153
- * ```typescript
154
- * if (!fs.existsSync(configPath)) {
155
- * throw OllieShopCLIError.fileNotFound(configPath, { operation: "load-config" });
156
- * }
157
- * ```
158
- */
159
- static fileNotFound(
160
- path: string,
161
- context: ErrorContext = {},
162
- ): OllieShopCLIError {
163
- return new OllieShopCLIError(
164
- `File not found: ${path}`,
165
- { ...context, file: path },
166
- [
167
- { description: "Check if the file path is correct" },
168
- { description: "Ensure the file exists in the specified location" },
169
- ],
170
- );
171
- }
172
- }
173
-
174
- export const CLIError = OllieShopCLIError;
175
-
176
- /**
177
- * Error thrown when a CLI command execution fails
178
- * Includes an error code for programmatic error handling
179
- *
180
- * @class CommandError
181
- * @extends {OllieShopCLIError}
182
- * @example
183
- * ```typescript
184
- * throw new CommandError(
185
- * "Failed to connect to builder service",
186
- * "BUILDER_CONNECTION_ERROR",
187
- * { url: builderUrl, timeout: 5000 }
188
- * );
189
- * ```
190
- */
191
- export class CommandError extends OllieShopCLIError {
192
- public readonly code: string;
193
-
194
- /**
195
- * Creates a new CommandError instance
196
- * @param {string} message - The error message
197
- * @param {string} code - A unique error code for this type of error
198
- * @param {ErrorContext} [context={}] - Additional context about the error
199
- */
200
- constructor(message: string, code: string, context: ErrorContext = {}) {
201
- super(message, context);
202
- this.name = "CommandError";
203
- this.code = code;
204
- }
205
- }
206
-
207
- /**
208
- * Error thrown when validation fails with detailed field-level information
209
- * Useful for form validation and input checking scenarios
210
- *
211
- * @class ValidationError
212
- * @extends {OllieShopCLIError}
213
- * @example
214
- * ```typescript
215
- * throw new ValidationError(
216
- * "Component configuration is invalid",
217
- * [
218
- * { field: "name", message: "Must be lowercase with hyphens" },
219
- * { field: "slot", message: "Invalid slot type" }
220
- * ],
221
- * { componentPath: "./src/components/header" }
222
- * );
223
- * ```
224
- */
225
- export class ValidationError extends OllieShopCLIError {
226
- public readonly fields: Array<{ field: string; message: string }>;
227
-
228
- /**
229
- * Creates a new ValidationError instance
230
- * @param {string} message - The overall error message
231
- * @param {Array<{field: string; message: string}>} [fields=[]] - Field-specific validation errors
232
- * @param {ErrorContext} [context={}] - Additional context about the error
233
- */
234
- constructor(
235
- message: string,
236
- fields: Array<{ field: string; message: string }> = [],
237
- context: ErrorContext = {},
238
- ) {
239
- super(message, context);
240
- this.name = "ValidationError";
241
- this.fields = fields;
242
- }
243
-
244
- /**
245
- * Get error details including field-level errors
246
- * @returns {ErrorContext & {fields: Array<{field: string; message: string}>}} Combined context and field errors
247
- */
248
- get details(): ErrorContext & {
249
- fields: Array<{ field: string; message: string }>;
250
- } {
251
- return {
252
- ...this.context,
253
- fields: this.fields,
254
- };
255
- }
256
- }
@@ -1,325 +0,0 @@
1
- import { ComponentSlot } from "@ollie-shop/core";
2
- import chalk from "chalk";
3
- import inquirer from "inquirer";
4
- import type { ComponentDeployOptions } from "../schemas/command.schema";
5
- import type { InteractiveChoice, MockComponent } from "../types";
6
- import type { CliConsole } from "./console.js";
7
-
8
- /**
9
- * Interactive command builder for creating CLI commands through prompts
10
- * Provides a wizard-like interface for complex commands
11
- *
12
- * @class InteractiveCommandBuilder
13
- * @example
14
- * ```typescript
15
- * const builder = new InteractiveCommandBuilder(console);
16
- * await builder.buildDeployComponentCommand();
17
- * // User is guided through deployment options
18
- * ```
19
- */
20
- export class InteractiveCommandBuilder {
21
- /**
22
- * Creates a new InteractiveCommandBuilder instance
23
- * @param {CliConsole} console - Console instance for I/O operations
24
- */
25
- constructor(private console: CliConsole) {}
26
-
27
- /**
28
- * Build component deploy command interactively
29
- * Guides user through selecting a component and deployment options
30
- *
31
- * @async
32
- * @throws {Error} If user cancels the wizard
33
- * @example
34
- * ```typescript
35
- * await builder.buildDeployComponentCommand();
36
- * // Shows:
37
- * // - List of available components
38
- * // - Deployment options checkboxes
39
- * // - Command preview
40
- * // - Execution confirmation
41
- * ```
42
- */
43
- async buildDeployComponentCommand(): Promise<void> {
44
- this.console.log(chalk.blue.bold("\n🚀 Component Deployment Wizard\n"));
45
-
46
- try {
47
- // Get available components (mock data for now)
48
- const components = await this.getAvailableComponents();
49
-
50
- const answers = await inquirer.prompt([
51
- {
52
- type: "list",
53
- name: "component",
54
- message: "Select component to deploy:",
55
- choices: components.map(
56
- (c): InteractiveChoice => ({
57
- name: `${c.name} (${c.slot}) - v${c.version || "1.0.0"} - ${chalk.dim(
58
- `Created ${new Date(c.createdAt).toLocaleDateString()}`,
59
- )}`,
60
- value: c.id,
61
- }),
62
- ),
63
- },
64
- {
65
- type: "checkbox",
66
- name: "options",
67
- message: "Deployment options:",
68
- choices: [
69
- { name: "Run tests before deploy", value: "test", checked: true },
70
- {
71
- name: "Enable verbose logging",
72
- value: "verbose",
73
- checked: false,
74
- },
75
- ],
76
- },
77
- ]);
78
-
79
- // Build the command
80
- let command = `ollieshop component deploy --id ${answers.component}`;
81
-
82
- if (answers.options.includes("verbose")) {
83
- command += " --verbose";
84
- }
85
-
86
- // Show preview
87
- this.console.log(`\n${chalk.dim("[Preview] This will run:")}`);
88
- this.console.log(chalk.cyan(` ${command}\n`));
89
-
90
- // Confirm execution
91
- const { proceed } = await inquirer.prompt({
92
- type: "confirm",
93
- name: "proceed",
94
- message: "Execute this command?",
95
- default: true,
96
- });
97
-
98
- if (proceed) {
99
- // Execute the command
100
- this.console.log(chalk.dim("\nExecuting command...\n"));
101
-
102
- // Import and execute the action directly
103
- const { deployComponent } = await import(
104
- "../actions/component.actions.js"
105
- );
106
- const deployOptions: ComponentDeployOptions = {
107
- componentId: answers.component,
108
- path: process.cwd(),
109
- };
110
- await deployComponent(deployOptions, this.console);
111
- } else {
112
- this.console.log(chalk.yellow("\n⚠️ Deployment cancelled"));
113
- }
114
- } catch (error) {
115
- if (error instanceof Error && error.name === "ExitPromptError") {
116
- this.console.log(chalk.yellow("\n⚠️ Wizard cancelled"));
117
- } else {
118
- throw error;
119
- }
120
- }
121
- }
122
-
123
- /**
124
- * Build component create command interactively
125
- * Guides user through component creation options with live validation
126
- *
127
- * @async
128
- * @throws {Error} If user cancels the wizard
129
- * @example
130
- * ```typescript
131
- * await builder.buildCreateComponentCommand();
132
- * // Prompts for:
133
- * // - Component name (with live validation)
134
- * // - Component slot selection
135
- * // - Language preference (TypeScript/JavaScript)
136
- * // - Test file inclusion
137
- * ```
138
- */
139
- async buildCreateComponentCommand(): Promise<void> {
140
- this.console.log(chalk.blue.bold("\n🎨 Component Creation Wizard\n"));
141
-
142
- try {
143
- const answers = await inquirer.prompt([
144
- {
145
- type: "input",
146
- name: "name",
147
- message: "Component name:",
148
- validate: (input: string) => {
149
- if (!input) return "Component name is required";
150
- if (!/^[a-z0-9-]+$/.test(input)) {
151
- return "Must be lowercase with hyphens only (e.g., header-nav)";
152
- }
153
- return true;
154
- },
155
- transformer: (input: string) => {
156
- // Show live validation
157
- if (!/^[a-z0-9-]+$/.test(input) && input) {
158
- return chalk.red(input);
159
- }
160
- return input;
161
- },
162
- },
163
- {
164
- type: "list",
165
- name: "slot",
166
- message: "Component slot:",
167
- choices: ComponentSlot.options.map((slot) => ({
168
- name:
169
- slot.charAt(0).toUpperCase() + slot.slice(1).replace(/-/g, " "),
170
- value: slot,
171
- })),
172
- default: "main",
173
- },
174
- {
175
- type: "list",
176
- name: "language",
177
- message: "Language:",
178
- choices: [
179
- { name: "TypeScript (recommended)", value: "typescript" },
180
- { name: "JavaScript", value: "javascript" },
181
- ],
182
- default: "typescript",
183
- },
184
- {
185
- type: "confirm",
186
- name: "tests",
187
- message: "Include test files?",
188
- default: true,
189
- },
190
- ]);
191
-
192
- // Build the command
193
- let command = `ollieshop component create --name ${answers.name}`;
194
-
195
- if (answers.slot !== "main") {
196
- command += ` --slot ${answers.slot}`;
197
- }
198
-
199
- if (answers.language === "javascript") {
200
- command += " --no-typescript";
201
- }
202
-
203
- if (!answers.tests) {
204
- command += " --no-tests";
205
- }
206
-
207
- // Show preview
208
- this.console.log(`\n${chalk.dim("[Preview] This will run:")}`);
209
- this.console.log(chalk.cyan(` ${command}\n`));
210
-
211
- // Confirm execution
212
- const { proceed } = await inquirer.prompt({
213
- type: "confirm",
214
- name: "proceed",
215
- message: "Create this component?",
216
- default: true,
217
- });
218
-
219
- if (proceed) {
220
- // Execute the command
221
- this.console.log(chalk.dim("\nCreating component...\n"));
222
-
223
- const { createComponent } = await import(
224
- "../actions/component.actions.js"
225
- );
226
- await createComponent(
227
- {
228
- name: answers.name,
229
- slot: answers.slot,
230
- tests: answers.tests,
231
- },
232
- this.console,
233
- );
234
- } else {
235
- this.console.log(chalk.yellow("\n⚠️ Component creation cancelled"));
236
- }
237
- } catch (error) {
238
- if (error instanceof Error && error.name === "ExitPromptError") {
239
- this.console.log(chalk.yellow("\n⚠️ Wizard cancelled"));
240
- } else {
241
- throw error;
242
- }
243
- }
244
- }
245
-
246
- /**
247
- * Get available components (mock for now)
248
- * TODO: Replace with actual API call to list components
249
- *
250
- * @private
251
- * @async
252
- * @returns {Promise<MockComponent[]>} Array of mock component data
253
- */
254
- private async getAvailableComponents(): Promise<MockComponent[]> {
255
- // TODO: Replace with actual API call
256
- return [
257
- {
258
- id: "comp_header_123",
259
- name: "header-nav",
260
- slot: "header",
261
- version: "1.2.0",
262
- enabled: true,
263
- createdAt: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(),
264
- type: "ui",
265
- description: "Navigation header component",
266
- },
267
- {
268
- id: "comp_cart_456",
269
- name: "shopping-cart",
270
- slot: "sidebar",
271
- version: "1.0.0",
272
- enabled: true,
273
- createdAt: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(),
274
- type: "ui",
275
- description: "Shopping cart widget",
276
- },
277
- {
278
- id: "comp_product_789",
279
- name: "product-list",
280
- slot: "main",
281
- version: "2.1.0",
282
- enabled: true,
283
- createdAt: new Date(Date.now() - 3 * 24 * 60 * 60 * 1000).toISOString(),
284
- type: "ui",
285
- description: "Product listing component",
286
- },
287
- ];
288
- }
289
- }
290
-
291
- /**
292
- * Run an interactive command builder for the specified command
293
- * Creates a wizard-like interface based on the command type
294
- *
295
- * @async
296
- * @param {string} command - The command type to run interactively
297
- * @param {CliConsole} console - Console instance for I/O
298
- * @example
299
- * ```typescript
300
- * // Run deployment wizard
301
- * await runInteractiveCommand("deploy", console);
302
- *
303
- * // Run component creation wizard
304
- * await runInteractiveCommand("create", console);
305
- * ```
306
- */
307
- export async function runInteractiveCommand(
308
- command: string,
309
- console: CliConsole,
310
- ): Promise<void> {
311
- const builder = new InteractiveCommandBuilder(console);
312
-
313
- switch (command) {
314
- case "deploy":
315
- case "component-deploy":
316
- await builder.buildDeployComponentCommand();
317
- break;
318
- case "create":
319
- case "component-create":
320
- await builder.buildCreateComponentCommand();
321
- break;
322
- default:
323
- console.warn(`Interactive mode not available for command: ${command}`);
324
- }
325
- }