@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,357 +0,0 @@
1
- import {
2
- type BuildResponse,
3
- type BuildResult,
4
- formatBuildError,
5
- setBuilderUrl,
6
- waitForBuildCompletion,
7
- } from "@ollie-shop/core";
8
- import { validateBuilderApiUrl } from "../schemas/command.schema";
9
- import type { CliConsole } from "./console";
10
- import { DEPLOYMENT_SETTINGS, ERROR_MESSAGES } from "./constants";
11
- import { RichProgressReporter } from "./rich-progress.js";
12
-
13
- /**
14
- * Resource types that can be deployed through the CLI
15
- * @typedef {"component" | "function"} ResourceType
16
- */
17
- export type ResourceType = "component" | "function";
18
-
19
- /**
20
- * Error types that can occur during deployment operations
21
- * @typedef {"BuildTimeoutError" | "BuildFailedError" | "BuildValidationError" | "UnknownError"} DeploymentErrorType
22
- */
23
- export type DeploymentErrorType =
24
- | "BuildTimeoutError"
25
- | "BuildFailedError"
26
- | "BuildValidationError"
27
- | "UnknownError";
28
-
29
- /**
30
- * Deployment progress information returned after successful deployment
31
- * @interface DeploymentProgress
32
- * @property {BuildResponse} completedBuild - The completed build response from the builder service
33
- * @property {number} duration - Total deployment duration in seconds
34
- */
35
- export interface DeploymentProgress {
36
- completedBuild: BuildResponse;
37
- duration: number;
38
- }
39
-
40
- /**
41
- * Configure the builder URL from environment variable with validation
42
- * Uses BUILDER_API_URL environment variable if set, validates it's a proper URL
43
- *
44
- * @throws {Error} If BUILDER_API_URL is set but invalid
45
- * @example
46
- * ```typescript
47
- * // Set environment variable first
48
- * process.env.BUILDER_API_URL = "https://builder.ollie.shop";
49
- *
50
- * // Configure the builder
51
- * configureBuilderUrl();
52
- * ```
53
- */
54
- export function configureBuilderUrl(): void {
55
- const builderUrl = process.env.BUILDER_API_URL;
56
- if (builderUrl) {
57
- if (!validateBuilderApiUrl(builderUrl)) {
58
- throw new Error(
59
- "Invalid BUILDER_API_URL environment variable. Must be a valid HTTP or HTTPS URL.",
60
- );
61
- }
62
- setBuilderUrl(builderUrl);
63
- }
64
- }
65
-
66
- /**
67
- * Handle deployment errors with proper type safety and user-friendly messages
68
- * Provides specific error messages and recovery suggestions based on error type
69
- *
70
- * @param {unknown} error - The error that occurred during deployment
71
- * @param {string} _buildId - The build ID (currently unused but kept for future use)
72
- * @param {ResourceType} resourceType - Type of resource being deployed (component/function)
73
- * @param {CliConsole} cliConsole - Console instance for output
74
- * @example
75
- * ```typescript
76
- * try {
77
- * await deployComponent(options);
78
- * } catch (error) {
79
- * handleDeploymentError(error, buildId, "component", console);
80
- * }
81
- * ```
82
- */
83
- export function handleDeploymentError(
84
- error: unknown,
85
- _buildId: string,
86
- resourceType: ResourceType,
87
- cliConsole: CliConsole,
88
- ): void {
89
- const errorType = getErrorType(error);
90
- const errorMessage = getErrorMessage(error);
91
-
92
- switch (errorType) {
93
- case "BuildTimeoutError":
94
- cliConsole.error(ERROR_MESSAGES.DEPLOYMENT_TIMEOUT);
95
- cliConsole.suggestions([
96
- `Retry deployment: ollieshop ${resourceType} deploy --id <${resourceType}-id>`,
97
- "Check your network connection and try again",
98
- "Contact support if timeouts persist - this may indicate infrastructure issues",
99
- ]);
100
- break;
101
- case "BuildFailedError":
102
- cliConsole.error(ERROR_MESSAGES.BUILD_FAILED);
103
- cliConsole.info("Review the build logs above for specific error details");
104
- if (errorMessage) {
105
- cliConsole.info(`Error details: ${errorMessage}`);
106
- }
107
- cliConsole.suggestions([
108
- `Validate your ${resourceType} code: ollieshop ${resourceType} validate`,
109
- "Check your code for syntax errors and missing dependencies",
110
- "Ensure all imports and exports are correctly defined",
111
- ]);
112
- break;
113
- case "BuildValidationError":
114
- cliConsole.error(ERROR_MESSAGES.BUILD_VALIDATION_FAILED);
115
- handleBuildValidationError(error, resourceType, cliConsole);
116
- break;
117
- default:
118
- cliConsole.error(`${ERROR_MESSAGES.UNKNOWN_ERROR}: ${errorMessage}`);
119
- break;
120
- }
121
- }
122
-
123
- /**
124
- * Get the error type from an unknown error with proper type safety
125
- */
126
- function getErrorType(error: unknown): DeploymentErrorType {
127
- if (error && typeof error === "object" && "name" in error) {
128
- const errorName = (error as { name: string }).name;
129
- if (isValidErrorType(errorName)) {
130
- return errorName;
131
- }
132
- }
133
- return "UnknownError";
134
- }
135
-
136
- /**
137
- * Get the error message from an unknown error with proper type safety
138
- */
139
- function getErrorMessage(error: unknown): string {
140
- if (error && typeof error === "object" && "message" in error) {
141
- return String((error as { message: unknown }).message);
142
- }
143
- return "An unknown error occurred";
144
- }
145
-
146
- /**
147
- * Type guard to check if a string is a valid error type
148
- */
149
- function isValidErrorType(errorName: string): errorName is DeploymentErrorType {
150
- return [
151
- "BuildTimeoutError",
152
- "BuildFailedError",
153
- "BuildValidationError",
154
- ].includes(errorName);
155
- }
156
-
157
- /**
158
- * Show deployment success message with build details
159
- * Displays build ID, duration, and infrastructure deployment confirmation
160
- *
161
- * @param {BuildResponse} completedBuild - The completed build response
162
- * @param {number} duration - Deployment duration in seconds
163
- * @param {string} _resourceId - Resource ID (currently unused but kept for future use)
164
- * @param {ResourceType} _resourceType - Resource type (currently unused but kept for future use)
165
- * @param {CliConsole} cliConsole - Console instance for output
166
- * @example
167
- * ```typescript
168
- * const { completedBuild, duration } = await waitForDeploymentWithProgress(
169
- * buildId,
170
- * "component",
171
- * console
172
- * );
173
- * showDeploymentSuccess(completedBuild, duration, componentId, "component", console);
174
- * ```
175
- */
176
- export function showDeploymentSuccess(
177
- completedBuild: BuildResponse,
178
- duration: number,
179
- _resourceId: string,
180
- _resourceType: ResourceType,
181
- cliConsole: CliConsole,
182
- ): void {
183
- cliConsole.success("\nāœ… Deployment completed successfully!");
184
- cliConsole.info(`Build ID: ${completedBuild.id}`);
185
- cliConsole.info(`Duration: ${duration.toFixed(1)}s`);
186
-
187
- // Note: Deployment URLs are dynamically generated by the infrastructure
188
- // For components: CloudFront URL (managed by SST router)
189
- // For functions: Lambda ARN (managed by AWS)
190
- cliConsole.info("✨ Resources deployed to cloud infrastructure");
191
- }
192
-
193
- // Removed showAsyncModeNextSteps as deployments now always wait for completion
194
-
195
- /**
196
- * Wait for deployment completion with real-time progress reporting
197
- * Shows animated progress bar with ETA while polling the builder service
198
- *
199
- * @async
200
- * @param {string} buildId - The build ID to monitor
201
- * @param {ResourceType} resourceType - Type of resource being deployed
202
- * @param {CliConsole} cliConsole - Console instance for progress display
203
- * @returns {Promise<DeploymentProgress>} Deployment details including completed build and duration
204
- * @throws {Error} If deployment times out or fails
205
- * @example
206
- * ```typescript
207
- * const result = await buildAndDeployComponent(componentId, path);
208
- * const { completedBuild, duration } = await waitForDeploymentWithProgress(
209
- * result.buildId,
210
- * "component",
211
- * console
212
- * );
213
- * console.log(`Deployment completed in ${duration}s`);
214
- * ```
215
- */
216
- export async function waitForDeploymentWithProgress(
217
- buildId: string,
218
- resourceType: ResourceType,
219
- cliConsole: CliConsole,
220
- ): Promise<DeploymentProgress> {
221
- const progressReporter = new RichProgressReporter(cliConsole);
222
- progressReporter.start();
223
-
224
- const startTime = Date.now();
225
- const estimatedDuration = DEPLOYMENT_SETTINGS.ESTIMATED_BUILD_DURATION_MS;
226
-
227
- // Update progress based on elapsed time
228
- const progressTimer = setInterval(() => {
229
- const elapsed = Date.now() - startTime;
230
- const progress = Math.min(
231
- elapsed / estimatedDuration,
232
- DEPLOYMENT_SETTINGS.MAX_PROGRESS_BEFORE_COMPLETION,
233
- );
234
- const remainingSeconds = Math.max(
235
- 0,
236
- Math.ceil((estimatedDuration - elapsed) / 1000),
237
- );
238
-
239
- progressReporter.updateProgress({
240
- phase: "building",
241
- message: `Building ${resourceType}... ETA: ${remainingSeconds}s`,
242
- progress,
243
- });
244
- }, DEPLOYMENT_SETTINGS.PROGRESS_UPDATE_INTERVAL_MS);
245
-
246
- try {
247
- const completedBuild = await waitForBuildCompletion(buildId, {
248
- pollIntervalMs: DEPLOYMENT_SETTINGS.DEFAULT_POLL_INTERVAL_MS,
249
- maxWaitMs: DEPLOYMENT_SETTINGS.DEFAULT_MAX_WAIT_MS,
250
- });
251
-
252
- clearInterval(progressTimer);
253
- const duration = (Date.now() - startTime) / 1000;
254
- progressReporter.stop(true);
255
-
256
- return { completedBuild, duration };
257
- } catch (error) {
258
- clearInterval(progressTimer);
259
- progressReporter.stop(false);
260
- throw error;
261
- }
262
- }
263
-
264
- /**
265
- * Handle build validation errors with specific suggestions
266
- * Provides targeted help for common validation issues
267
- *
268
- * @param {unknown} error - The validation error
269
- * @param {ResourceType} resourceType - Type of resource that failed validation
270
- * @param {CliConsole} cliConsole - Console instance for output
271
- * @example
272
- * ```typescript
273
- * if (error.code === "BUILD_VALIDATION_ERROR") {
274
- * handleBuildValidationError(error, "component", console);
275
- * }
276
- * ```
277
- */
278
- export function handleBuildValidationError(
279
- error: unknown,
280
- resourceType: ResourceType,
281
- cliConsole: CliConsole,
282
- ): void {
283
- const errorCode = getErrorCode(error);
284
-
285
- if (errorCode === "BUILD_VALIDATION_ERROR") {
286
- cliConsole.suggestions([
287
- `Ensure the ${resourceType} ID is a valid UUID format (e.g., 123e4567-e89b-12d3-a456-426614174000)`,
288
- `Verify the ${resourceType} directory exists and contains the required files`,
289
- `Check that your ${resourceType} has a valid package.json with correct entry point`,
290
- `Run: ollieshop ${resourceType} validate --path <path> to identify specific issues`,
291
- ]);
292
- }
293
- }
294
-
295
- /**
296
- * Get error code from unknown error with proper type safety
297
- */
298
- function getErrorCode(error: unknown): string | undefined {
299
- if (error && typeof error === "object" && "code" in error) {
300
- const code = (error as { code: unknown }).code;
301
- return typeof code === "string" ? code : undefined;
302
- }
303
- return undefined;
304
- }
305
-
306
- /**
307
- * Handle deployment result with proper error handling and type safety
308
- * Updates spinner state and throws error if deployment failed
309
- *
310
- * @param {BuildResult} result - The build result from the deployment attempt
311
- * @param {ResourceType} resourceType - Type of resource being deployed
312
- * @param {CliConsole} cliConsole - Console instance for output
313
- * @param {ReturnType<CliConsole["spinner"]>} spinner - Active spinner to update
314
- * @throws {Error} If the deployment failed
315
- * @example
316
- * ```typescript
317
- * const result = await buildAndDeployComponent(componentId, path);
318
- * handleDeploymentResult(result, "component", console, spinner);
319
- * // If we get here, deployment was initiated successfully
320
- * ```
321
- */
322
- export function handleDeploymentResult(
323
- result: BuildResult,
324
- resourceType: ResourceType,
325
- cliConsole: CliConsole,
326
- spinner: ReturnType<CliConsole["spinner"]>,
327
- ): void {
328
- if (!result.success) {
329
- const capitalizedType = capitalizeResourceType(resourceType);
330
- spinner.fail(`${capitalizedType} deployment failed`);
331
-
332
- const errorMessage = result.error
333
- ? formatBuildError(result.error)
334
- : "Unknown error occurred";
335
-
336
- cliConsole.error(errorMessage);
337
- handleBuildValidationError(result.error, resourceType, cliConsole);
338
-
339
- const error = new Error(
340
- getErrorMessage(result.error) || "Deployment failed",
341
- );
342
- error.name = "DeploymentError";
343
- throw error;
344
- }
345
-
346
- const capitalizedType = capitalizeResourceType(resourceType);
347
- spinner.succeed(`${capitalizedType} deployment initiated!`);
348
- cliConsole.success(`Build ID: ${result.buildId}`);
349
- cliConsole.info(`Status: ${result.status}`);
350
- }
351
-
352
- /**
353
- * Capitalize resource type for display purposes
354
- */
355
- function capitalizeResourceType(resourceType: ResourceType): string {
356
- return resourceType.charAt(0).toUpperCase() + resourceType.slice(1);
357
- }
@@ -1,264 +0,0 @@
1
- import chalk from "chalk";
2
- import type { ErrorContext } from "../types";
3
- import { isNodeError } from "../types";
4
- import type { CliConsole } from "./console.js";
5
- import { detectProjectContext } from "./context-detector.js";
6
-
7
- interface ErrorRecovery {
8
- message: string;
9
- suggestions: string[];
10
- commands?: string[];
11
- }
12
-
13
- export class EnhancedErrorHandler {
14
- constructor(private console: CliConsole) {}
15
-
16
- /**
17
- * Common error patterns with recovery suggestions
18
- */
19
- private readonly errorPatterns = new Map<string | RegExp, ErrorRecovery>([
20
- [
21
- "ENOENT",
22
- {
23
- message: "File or directory not found",
24
- suggestions: [
25
- "Check if the path exists",
26
- "Use --path to specify the correct location",
27
- ],
28
- commands: ["ls", "pwd"],
29
- },
30
- ],
31
- [
32
- "EACCES",
33
- {
34
- message: "Permission denied",
35
- suggestions: [
36
- "Check file permissions",
37
- "Try running with appropriate permissions",
38
- ],
39
- commands: ["ls -la"],
40
- },
41
- ],
42
- [
43
- "ECONNREFUSED",
44
- {
45
- message: "Connection refused",
46
- suggestions: [
47
- "Check your internet connection",
48
- "Verify your authentication",
49
- "Check if backend services are running",
50
- ],
51
- commands: ["ollieshop login", "ollieshop status"],
52
- },
53
- ],
54
- [
55
- /Component .* already exists/,
56
- {
57
- message: "Component already exists",
58
- suggestions: [
59
- "Use a different name",
60
- "Delete the existing component first",
61
- "Update the existing component instead",
62
- ],
63
- commands: ["ollieshop component list", "rm -rf ./components/{name}"],
64
- },
65
- ],
66
- [
67
- /Invalid component name/,
68
- {
69
- message: "Component name validation failed",
70
- suggestions: [
71
- "Use lowercase letters and hyphens only",
72
- "Examples: header-nav, shopping-cart, product-list",
73
- ],
74
- },
75
- ],
76
- ]);
77
-
78
- /**
79
- * Handle errors with enhanced recovery suggestions
80
- */
81
- handle(error: Error, context?: ErrorContext): void {
82
- // Display the main error
83
- this.console.error(`\nāŒ ${error.message}\n`);
84
-
85
- // Get recovery suggestions
86
- const recovery = this.getRecoverySuggestions(error);
87
-
88
- if (recovery) {
89
- this.displayRecoverySuggestions(recovery, context);
90
- }
91
-
92
- // Show contextual information
93
- this.displayContextualInfo(error, context);
94
-
95
- // Suggest similar commands if applicable
96
- if (this.isCommandError(error)) {
97
- this.suggestSimilarCommands(context);
98
- }
99
- }
100
-
101
- /**
102
- * Get recovery suggestions based on error
103
- */
104
- private getRecoverySuggestions(error: Error): ErrorRecovery | undefined {
105
- // Check error code
106
- if (isNodeError(error) && this.errorPatterns.has(error.code)) {
107
- return this.errorPatterns.get(error.code);
108
- }
109
-
110
- // Check error message patterns
111
- for (const [pattern, recovery] of this.errorPatterns) {
112
- if (pattern instanceof RegExp && pattern.test(error.message)) {
113
- return recovery;
114
- }
115
- }
116
-
117
- return undefined;
118
- }
119
-
120
- /**
121
- * Display recovery suggestions
122
- */
123
- private displayRecoverySuggestions(
124
- recovery: ErrorRecovery,
125
- context?: ErrorContext,
126
- ): void {
127
- this.console.warn("šŸ’” Possible solutions:\n");
128
-
129
- for (const [index, suggestion] of recovery.suggestions.entries()) {
130
- // Replace placeholders in suggestions
131
- const formatted = this.formatSuggestion(suggestion, context);
132
- this.console.log(chalk.yellow(` ${index + 1}. ${formatted}`));
133
- }
134
-
135
- if (recovery.commands && recovery.commands.length > 0) {
136
- this.console.log(chalk.dim("\nšŸ“ Helpful commands:"));
137
- for (const cmd of recovery.commands) {
138
- const formatted = this.formatSuggestion(cmd, context);
139
- this.console.log(chalk.dim(` $ ${formatted}`));
140
- }
141
- }
142
- }
143
-
144
- /**
145
- * Display contextual information
146
- */
147
- private displayContextualInfo(_error: Error, context?: ErrorContext): void {
148
- const projectContext = detectProjectContext();
149
-
150
- this.console.log(chalk.dim("\nšŸ“ Context:"));
151
- this.console.log(chalk.dim(` Current directory: ${process.cwd()}`));
152
-
153
- if (projectContext.type !== "unknown") {
154
- this.console.log(chalk.dim(` Project type: ${projectContext.type}`));
155
- if (projectContext.name) {
156
- this.console.log(
157
- chalk.dim(` ${projectContext.type} name: ${projectContext.name}`),
158
- );
159
- }
160
- }
161
-
162
- if (context?.path) {
163
- this.console.log(chalk.dim(` Target path: ${context.path}`));
164
- }
165
- }
166
-
167
- /**
168
- * Format suggestion with context values
169
- */
170
- private formatSuggestion(suggestion: string, context?: ErrorContext): string {
171
- if (!context) return suggestion;
172
-
173
- return suggestion.replace(/{(\w+)}/g, (match, key) => {
174
- const value = context[key as keyof ErrorContext];
175
- return typeof value === "string" ? value : match;
176
- });
177
- }
178
-
179
- /**
180
- * Check if this is a command-related error
181
- */
182
- private isCommandError(error: Error): boolean {
183
- return (
184
- error.message.includes("Unknown command") ||
185
- error.message.includes("not found") ||
186
- (isNodeError(error) && error.code === "COMMAND_NOT_FOUND")
187
- );
188
- }
189
-
190
- /**
191
- * Suggest similar commands
192
- */
193
- private suggestSimilarCommands(context?: ErrorContext): void {
194
- if (!context?.attemptedCommand) return;
195
-
196
- const suggestions = this.findSimilarCommands(
197
- String(context.attemptedCommand),
198
- );
199
-
200
- if (suggestions.length > 0) {
201
- this.console.log(chalk.dim("\nšŸ’” Did you mean:"));
202
- for (const cmd of suggestions) {
203
- this.console.log(chalk.dim(` $ ollieshop ${cmd}`));
204
- }
205
- }
206
- }
207
-
208
- /**
209
- * Find similar commands using basic string matching
210
- */
211
- private findSimilarCommands(attempted: string): string[] {
212
- const commands = [
213
- "component create",
214
- "component validate",
215
- "component build",
216
- "component deploy",
217
- "component list",
218
- "function create",
219
- "function validate",
220
- "function build",
221
- "function test",
222
- "function deploy",
223
- "store-version create",
224
- "store-version list",
225
- "template list",
226
- "login",
227
- "whoami",
228
- ];
229
-
230
- return commands
231
- .filter((cmd) => {
232
- // Simple similarity check
233
- const cmdParts = cmd.toLowerCase().split(" ");
234
- const attemptedParts = attempted.toLowerCase().split(" ");
235
-
236
- // Check if any part matches
237
- return cmdParts.some((part) =>
238
- attemptedParts.some(
239
- (aPart) => part.startsWith(aPart) || aPart.startsWith(part),
240
- ),
241
- );
242
- })
243
- .slice(0, 3); // Show top 3 suggestions
244
- }
245
- }
246
-
247
- /**
248
- * Create an error with additional context
249
- */
250
- export function createContextualError(
251
- message: string,
252
- code?: string,
253
- context?: Record<string, unknown>,
254
- ): Error {
255
- const error = new Error(message) as Error & {
256
- code?: string;
257
- context?: Record<string, unknown>;
258
- };
259
-
260
- if (code) error.code = code;
261
- if (context) error.context = context;
262
-
263
- return error;
264
- }
@@ -1,60 +0,0 @@
1
- import type { ErrorContext } from "../types";
2
- import { console as cliConsole } from "./console";
3
- import { EnhancedErrorHandler } from "./enhanced-error-handler.js";
4
- import { OllieShopCLIError, type RecoveryAction } from "./errors";
5
-
6
- function handleOllieShopError(error: OllieShopCLIError): void {
7
- cliConsole.error(`\n${error.message}`);
8
-
9
- if (error.details) {
10
- displayErrorDetails(error.details);
11
- }
12
-
13
- if (error.suggestions && error.suggestions.length > 0) {
14
- displayRecoveryActions(error.suggestions);
15
- }
16
- }
17
-
18
- function displayErrorDetails(details: ErrorContext): void {
19
- cliConsole.dim("\nContext:");
20
- for (const [key, value] of Object.entries(details)) {
21
- if (key === "fields" && Array.isArray(value)) {
22
- displayFieldErrors(value);
23
- } else {
24
- cliConsole.dim(` ${key}: ${value}`);
25
- }
26
- }
27
- }
28
-
29
- function displayFieldErrors(
30
- fields: Array<{ field: string; message: string }>,
31
- ): void {
32
- cliConsole.dim(" fields:");
33
- for (const field of fields) {
34
- cliConsole.dim(` ${field.field}: ${field.message}`);
35
- }
36
- }
37
-
38
- function displayRecoveryActions(actions: RecoveryAction[]): void {
39
- cliConsole.info("\nSuggestions:");
40
- for (const action of actions) {
41
- cliConsole.dim(` • ${action.description}`);
42
- if (action.command) {
43
- cliConsole.dim(` $ ${action.command}`);
44
- }
45
- }
46
- }
47
-
48
- export function handleError(error: unknown, context?: ErrorContext): never {
49
- if (error instanceof OllieShopCLIError) {
50
- handleOllieShopError(error);
51
- } else if (error instanceof Error) {
52
- const enhancedHandler = new EnhancedErrorHandler(cliConsole);
53
- enhancedHandler.handle(error, context);
54
- } else {
55
- cliConsole.error("\nAn unexpected error occurred");
56
- cliConsole.dim(String(error));
57
- }
58
-
59
- process.exit(1);
60
- }