@poetora/cli 0.1.8 → 0.1.10
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-builder.js +1 -1
- package/bin/services/version.service.d.ts +1 -1
- package/bin/services/version.service.js +12 -10
- package/package.json +8 -3
- package/.turbo/turbo-build.log +0 -4
- package/src/accessibility.ts +0 -180
- package/src/cli-builder.ts +0 -274
- package/src/cli.ts +0 -22
- package/src/commands/__tests__/base.command.test.ts +0 -139
- package/src/commands/__tests__/dev.command.test.ts +0 -241
- package/src/commands/__tests__/init.command.test.ts +0 -281
- package/src/commands/__tests__/utils.ts +0 -20
- package/src/commands/base.command.ts +0 -97
- package/src/commands/check.command.ts +0 -40
- package/src/commands/dev.command.ts +0 -63
- package/src/commands/index.ts +0 -6
- package/src/commands/init.command.ts +0 -125
- package/src/commands/link.command.ts +0 -39
- package/src/commands/update.command.ts +0 -23
- package/src/constants.ts +0 -4
- package/src/errors/cli-error.ts +0 -83
- package/src/errors/index.ts +0 -1
- package/src/index.ts +0 -110
- package/src/mdxAccessibility.ts +0 -132
- package/src/middlewares.ts +0 -73
- package/src/services/__tests__/port.service.test.ts +0 -83
- package/src/services/__tests__/template.service.test.ts +0 -234
- package/src/services/__tests__/version.service.test.ts +0 -165
- package/src/services/accessibility-check.service.ts +0 -226
- package/src/services/index.ts +0 -7
- package/src/services/link.service.ts +0 -65
- package/src/services/openapi-check.service.ts +0 -68
- package/src/services/port.service.ts +0 -47
- package/src/services/template.service.ts +0 -203
- package/src/services/update.service.ts +0 -76
- package/src/services/version.service.ts +0 -161
- package/src/start.ts +0 -6
- package/src/types/common.ts +0 -53
- package/src/types/index.ts +0 -2
- package/src/types/options.ts +0 -42
- package/src/utils/console-logger.ts +0 -123
- package/src/utils/index.ts +0 -2
- package/src/utils/logger.interface.ts +0 -70
- package/tsconfig.build.json +0 -17
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -8
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import { CliError } from '../errors/index.js';
|
|
2
|
-
import type { ILogger } from '../utils/index.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Base abstract class for all CLI commands
|
|
6
|
-
* Implements Template Method pattern for consistent command execution flow
|
|
7
|
-
*/
|
|
8
|
-
export abstract class BaseCommand<TOptions = unknown, TResult = void> {
|
|
9
|
-
/**
|
|
10
|
-
* Command name (e.g., 'dev', 'init', 'check')
|
|
11
|
-
*/
|
|
12
|
-
abstract readonly name: string;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Command description for help text
|
|
16
|
-
*/
|
|
17
|
-
abstract readonly description: string;
|
|
18
|
-
|
|
19
|
-
constructor(
|
|
20
|
-
protected readonly logger: ILogger,
|
|
21
|
-
protected readonly packageName: string = 'poet'
|
|
22
|
-
) {}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Template method that orchestrates command execution
|
|
26
|
-
* This is the main entry point called by the CLI framework
|
|
27
|
-
*/
|
|
28
|
-
/* prettier-ignore */
|
|
29
|
-
async run(options: TOptions): Promise<TResult> {
|
|
30
|
-
try {
|
|
31
|
-
// 1. Validate input options
|
|
32
|
-
await this.validate(options);
|
|
33
|
-
|
|
34
|
-
// 2. Execute command logic
|
|
35
|
-
const result = await this.execute(options);
|
|
36
|
-
|
|
37
|
-
// 3. Return result
|
|
38
|
-
return result;
|
|
39
|
-
} catch (error) {
|
|
40
|
-
// 4. Handle errors consistently
|
|
41
|
-
this.handleError(error);
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Validate command options before execution
|
|
48
|
-
* Override this method to add custom validation logic
|
|
49
|
-
* @param options - Command options to validate
|
|
50
|
-
* @throws {ValidationError} if validation fails
|
|
51
|
-
*/
|
|
52
|
-
// prettier-ignore
|
|
53
|
-
protected async validate(_options: TOptions): Promise<void> {
|
|
54
|
-
// Default: no validation
|
|
55
|
-
// Subclasses can override to add validation
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Execute the main command logic
|
|
60
|
-
* This method must be implemented by all command subclasses
|
|
61
|
-
* @param options - Validated command options
|
|
62
|
-
* @returns Command execution result
|
|
63
|
-
*/
|
|
64
|
-
protected abstract execute(options: TOptions): Promise<TResult>;
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Handle errors that occur during command execution
|
|
68
|
-
* Can be overridden to provide custom error handling
|
|
69
|
-
* @param error - The error to handle
|
|
70
|
-
*/
|
|
71
|
-
protected handleError(error: unknown): void {
|
|
72
|
-
if (error instanceof CliError) {
|
|
73
|
-
// CLI-specific errors with user-friendly messages
|
|
74
|
-
this.logger.error(error.message);
|
|
75
|
-
} else if (error instanceof Error) {
|
|
76
|
-
// Generic errors
|
|
77
|
-
this.logger.error(error.message);
|
|
78
|
-
|
|
79
|
-
// In debug mode, show stack trace
|
|
80
|
-
if (process.env.DEBUG === 'true') {
|
|
81
|
-
this.logger.logColor(error.stack ?? '', 'gray');
|
|
82
|
-
}
|
|
83
|
-
} else {
|
|
84
|
-
// Unknown error types
|
|
85
|
-
this.logger.error('An unexpected error occurred');
|
|
86
|
-
this.logger.logColor(String(error), 'gray');
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Exit the process with given code
|
|
92
|
-
* Separated for easier testing (can be mocked)
|
|
93
|
-
*/
|
|
94
|
-
protected exit(code: number): never {
|
|
95
|
-
process.exit(code);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { AccessibilityCheckService, OpenApiCheckService } from '../services/index.js';
|
|
2
|
-
import type { OpenApiCheckOptions } from '../types/index.js';
|
|
3
|
-
import type { ILogger } from '../utils/index.js';
|
|
4
|
-
import { BaseCommand } from './base.command.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Check command - Validate OpenAPI specs and accessibility
|
|
8
|
-
*/
|
|
9
|
-
export class CheckCommand extends BaseCommand {
|
|
10
|
-
readonly name = 'check';
|
|
11
|
-
readonly description = 'check OpenAPI specs or accessibility';
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
logger: ILogger,
|
|
15
|
-
private readonly openApiCheckService: OpenApiCheckService,
|
|
16
|
-
private readonly accessibilityCheckService: AccessibilityCheckService,
|
|
17
|
-
packageName: string = 'poet'
|
|
18
|
-
) {
|
|
19
|
-
super(logger, packageName);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Execute OpenAPI check
|
|
24
|
-
*/
|
|
25
|
-
async checkOpenApi(options: OpenApiCheckOptions): Promise<void> {
|
|
26
|
-
await this.openApiCheckService.validateSpec(options.filename, options.localSchema);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Execute accessibility check
|
|
31
|
-
*/
|
|
32
|
-
async checkAccessibility(): Promise<number> {
|
|
33
|
-
return await this.accessibilityCheckService.checkAccessibility();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
protected override async execute(options: OpenApiCheckOptions): Promise<void> {
|
|
37
|
-
// This is for openapi-check command
|
|
38
|
-
await this.openApiCheckService.validateSpec(options.filename, options.localSchema);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { dev } from '@poetora/previewing';
|
|
2
|
-
import type { ArgumentsCamelCase } from 'yargs';
|
|
3
|
-
import { InvalidEnvironmentError } from '../errors/index.js';
|
|
4
|
-
import type { PortService, VersionService } from '../services/index.js';
|
|
5
|
-
import type { DevOptions } from '../types/index.js';
|
|
6
|
-
import type { ILogger } from '../utils/index.js';
|
|
7
|
-
import { BaseCommand } from './base.command.js';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Dev command - Start local development server
|
|
11
|
-
*/
|
|
12
|
-
export class DevCommand extends BaseCommand {
|
|
13
|
-
readonly name = 'dev';
|
|
14
|
-
readonly description = 'initialize a local preview environment';
|
|
15
|
-
|
|
16
|
-
constructor(
|
|
17
|
-
logger: ILogger,
|
|
18
|
-
private readonly versionService: VersionService,
|
|
19
|
-
private readonly portService: PortService,
|
|
20
|
-
packageName: string = 'poet'
|
|
21
|
-
) {
|
|
22
|
-
super(logger, packageName);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
protected override async validate(_options: DevOptions): Promise<void> {
|
|
26
|
-
// Check Node.js version
|
|
27
|
-
const versionResult = this.versionService.checkNodeVersion();
|
|
28
|
-
|
|
29
|
-
if (!versionResult.isValid) {
|
|
30
|
-
throw new InvalidEnvironmentError(versionResult.message ?? 'Unsupported Node.js version');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Show warning if below recommended version
|
|
34
|
-
if (versionResult.hasWarning && versionResult.message) {
|
|
35
|
-
this.logger.warn(versionResult.message);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
protected override async execute(options: DevOptions): Promise<void> {
|
|
40
|
-
// Find available port
|
|
41
|
-
const port = await this.portService.findAvailablePort(options.port);
|
|
42
|
-
|
|
43
|
-
// Get CLI version
|
|
44
|
-
const cliVersion = this.versionService.getCliVersion();
|
|
45
|
-
|
|
46
|
-
// Start development server (delegate to @poetora/previewing)
|
|
47
|
-
// Convert DevOptions to ArgumentsCamelCase format expected by dev()
|
|
48
|
-
const devArgs: ArgumentsCamelCase = {
|
|
49
|
-
_: [],
|
|
50
|
-
$0: this.packageName,
|
|
51
|
-
port,
|
|
52
|
-
open: options.open ?? true,
|
|
53
|
-
localSchema: options.localSchema ?? false,
|
|
54
|
-
clientVersion: options.clientVersion,
|
|
55
|
-
groups: options.groups,
|
|
56
|
-
disableOpenapi: options.disableOpenapi ?? false,
|
|
57
|
-
packageName: this.packageName,
|
|
58
|
-
cliVersion,
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
await dev(devArgs);
|
|
62
|
-
}
|
|
63
|
-
}
|
package/src/commands/index.ts
DELETED
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { input, select } from '@inquirer/prompts';
|
|
2
|
-
import { ValidationError } from '../errors/index.js';
|
|
3
|
-
import type { TemplateService } from '../services/template.service.js';
|
|
4
|
-
import type { InitOptions } from '../types/index.js';
|
|
5
|
-
import type { ILogger } from '../utils/index.js';
|
|
6
|
-
import { BaseCommand } from './base.command.js';
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Init command - Create a new Poetora documentation site
|
|
10
|
-
*/
|
|
11
|
-
export class InitCommand extends BaseCommand {
|
|
12
|
-
readonly name = 'init';
|
|
13
|
-
readonly description = 'Create a new Poetora documentation site';
|
|
14
|
-
|
|
15
|
-
constructor(
|
|
16
|
-
logger: ILogger,
|
|
17
|
-
private readonly templateService: TemplateService,
|
|
18
|
-
packageName: string = 'poet'
|
|
19
|
-
) {
|
|
20
|
-
super(logger, packageName);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
protected override async execute(options: InitOptions): Promise<void> {
|
|
24
|
-
let installDir = options.directory;
|
|
25
|
-
|
|
26
|
-
// Step 1: Handle existing directory
|
|
27
|
-
const dirStatus = await this.templateService.checkDirectory(installDir);
|
|
28
|
-
|
|
29
|
-
if (dirStatus.exists && dirStatus.hasContents) {
|
|
30
|
-
const choice = await this.promptDirectoryChoice(installDir);
|
|
31
|
-
|
|
32
|
-
if (choice === 'cancel') {
|
|
33
|
-
this.logger.info('Installation cancelled');
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (choice === 'subdir') {
|
|
38
|
-
const subdir = await this.promptSubdirectoryName();
|
|
39
|
-
installDir = installDir === '.' ? subdir : `${installDir}/${subdir}`;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Step 2: Prompt for project configuration
|
|
44
|
-
const projectName = await this.promptProjectName(installDir);
|
|
45
|
-
const theme = await this.promptTheme();
|
|
46
|
-
|
|
47
|
-
// Step 3: Download and install template
|
|
48
|
-
this.logger.info('Setting up documentation project...');
|
|
49
|
-
|
|
50
|
-
await this.templateService.installTemplate({
|
|
51
|
-
directory: installDir,
|
|
52
|
-
projectName,
|
|
53
|
-
theme,
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
// Step 4: Show success message
|
|
57
|
-
this.showOnboardingMessage(installDir);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private async promptDirectoryChoice(
|
|
61
|
-
directory: string
|
|
62
|
-
): Promise<'subdir' | 'overwrite' | 'cancel'> {
|
|
63
|
-
const choice = await select({
|
|
64
|
-
message: `Directory ${directory} is not empty. What would you like to do?`,
|
|
65
|
-
choices: [
|
|
66
|
-
{ name: 'Create in a subdirectory', value: 'subdir' },
|
|
67
|
-
{ name: 'Overwrite current directory (may lose contents)', value: 'overwrite' },
|
|
68
|
-
{ name: 'Cancel', value: 'cancel' },
|
|
69
|
-
],
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
return choice as 'subdir' | 'overwrite' | 'cancel';
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
private async promptSubdirectoryName(): Promise<string> {
|
|
76
|
-
const subdir = await input({
|
|
77
|
-
message: 'Subdirectory name:',
|
|
78
|
-
default: 'docs',
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
if (!subdir || subdir.trim() === '') {
|
|
82
|
-
throw new ValidationError('Subdirectory name cannot be empty');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return subdir.trim();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private async promptProjectName(installDir: string): Promise<string> {
|
|
89
|
-
const defaultProject = installDir === '.' ? 'Poetora' : installDir;
|
|
90
|
-
|
|
91
|
-
const projectName = await input({
|
|
92
|
-
message: 'Project Name',
|
|
93
|
-
default: defaultProject,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
return projectName || defaultProject;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
private async promptTheme(): Promise<string> {
|
|
100
|
-
const themes = this.templateService.getAvailableThemes();
|
|
101
|
-
|
|
102
|
-
const theme = await select({
|
|
103
|
-
message: 'Theme',
|
|
104
|
-
choices: themes.map((t) => ({
|
|
105
|
-
name: t,
|
|
106
|
-
value: t,
|
|
107
|
-
})),
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return theme;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
private showOnboardingMessage(installDir: string): void {
|
|
114
|
-
this.logger.log('');
|
|
115
|
-
this.logger.success('Documentation Setup!');
|
|
116
|
-
this.logger.log('');
|
|
117
|
-
this.logger.log('To see your docs run:');
|
|
118
|
-
this.logger.log('');
|
|
119
|
-
if (installDir !== '.') {
|
|
120
|
-
this.logger.log(` cd ${installDir}`);
|
|
121
|
-
}
|
|
122
|
-
this.logger.log(` ${this.packageName} dev`);
|
|
123
|
-
this.logger.log('');
|
|
124
|
-
}
|
|
125
|
-
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { LinkService } from '../services/index.js';
|
|
2
|
-
import type { RenameOptions } from '../types/index.js';
|
|
3
|
-
import type { ILogger } from '../utils/index.js';
|
|
4
|
-
import { BaseCommand } from './base.command.js';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Link command - Check broken links and rename files
|
|
8
|
-
*/
|
|
9
|
-
export class LinkCommand extends BaseCommand {
|
|
10
|
-
readonly name = 'link';
|
|
11
|
-
readonly description = 'manage documentation links';
|
|
12
|
-
|
|
13
|
-
constructor(
|
|
14
|
-
logger: ILogger,
|
|
15
|
-
private readonly linkService: LinkService,
|
|
16
|
-
packageName: string = 'poet'
|
|
17
|
-
) {
|
|
18
|
-
super(logger, packageName);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Check for broken links
|
|
23
|
-
*/
|
|
24
|
-
async checkBrokenLinks(): Promise<Record<string, string[]>> {
|
|
25
|
-
return await this.linkService.checkBrokenLinks();
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Rename file and update references
|
|
30
|
-
*/
|
|
31
|
-
async renameFile(options: RenameOptions): Promise<void> {
|
|
32
|
-
await this.linkService.renameFile(options.from, options.to, options.force);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
protected override async execute(): Promise<void> {
|
|
36
|
-
// Default action: check broken links
|
|
37
|
-
await this.linkService.checkBrokenLinks();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { UpdateService } from '../services/index.js';
|
|
2
|
-
import type { ILogger } from '../utils/index.js';
|
|
3
|
-
import { BaseCommand } from './base.command.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Update command - Update CLI to latest version
|
|
7
|
-
*/
|
|
8
|
-
export class UpdateCommand extends BaseCommand {
|
|
9
|
-
readonly name = 'update';
|
|
10
|
-
readonly description = 'update the CLI to the latest version';
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
logger: ILogger,
|
|
14
|
-
private readonly updateService: UpdateService,
|
|
15
|
-
packageName: string = 'poet'
|
|
16
|
-
) {
|
|
17
|
-
super(logger, packageName);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
protected override async execute(): Promise<void> {
|
|
21
|
-
await this.updateService.update();
|
|
22
|
-
}
|
|
23
|
-
}
|
package/src/constants.ts
DELETED
package/src/errors/cli-error.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base CLI error class for all custom errors
|
|
3
|
-
*/
|
|
4
|
-
export class CliError extends Error {
|
|
5
|
-
constructor(
|
|
6
|
-
message: string,
|
|
7
|
-
public readonly code: string,
|
|
8
|
-
public readonly exitCode: number = 1
|
|
9
|
-
) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.name = 'CliError';
|
|
12
|
-
Error.captureStackTrace(this, this.constructor);
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Error thrown when environment requirements are not met
|
|
18
|
-
*/
|
|
19
|
-
export class InvalidEnvironmentError extends CliError {
|
|
20
|
-
constructor(message: string) {
|
|
21
|
-
super(message, 'INVALID_ENVIRONMENT', 1);
|
|
22
|
-
this.name = 'InvalidEnvironmentError';
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Error thrown when no available port is found
|
|
28
|
-
*/
|
|
29
|
-
export class NoAvailablePortError extends CliError {
|
|
30
|
-
constructor(message: string) {
|
|
31
|
-
super(message, 'NO_AVAILABLE_PORT', 1);
|
|
32
|
-
this.name = 'NoAvailablePortError';
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Error thrown when configuration file is not found
|
|
38
|
-
*/
|
|
39
|
-
export class ConfigNotFoundError extends CliError {
|
|
40
|
-
constructor(message: string) {
|
|
41
|
-
super(message, 'CONFIG_NOT_FOUND', 1);
|
|
42
|
-
this.name = 'ConfigNotFoundError';
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Error thrown when command validation fails
|
|
48
|
-
*/
|
|
49
|
-
export class ValidationError extends CliError {
|
|
50
|
-
constructor(
|
|
51
|
-
message: string,
|
|
52
|
-
public readonly field?: string
|
|
53
|
-
) {
|
|
54
|
-
super(message, 'VALIDATION_ERROR', 1);
|
|
55
|
-
this.name = 'ValidationError';
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Error thrown when file operations fail
|
|
61
|
-
*/
|
|
62
|
-
export class FileSystemError extends CliError {
|
|
63
|
-
constructor(
|
|
64
|
-
message: string,
|
|
65
|
-
public readonly filePath?: string
|
|
66
|
-
) {
|
|
67
|
-
super(message, 'FILE_SYSTEM_ERROR', 1);
|
|
68
|
-
this.name = 'FileSystemError';
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Error thrown when external service calls fail
|
|
74
|
-
*/
|
|
75
|
-
export class ExternalServiceError extends CliError {
|
|
76
|
-
constructor(
|
|
77
|
-
message: string,
|
|
78
|
-
public readonly service?: string
|
|
79
|
-
) {
|
|
80
|
-
super(message, 'EXTERNAL_SERVICE_ERROR', 1);
|
|
81
|
-
this.name = 'ExternalServiceError';
|
|
82
|
-
}
|
|
83
|
-
}
|
package/src/errors/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './cli-error.js';
|
package/src/index.ts
DELETED
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { type ChildProcess, spawn } from 'child_process';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { fileURLToPath } from 'url';
|
|
5
|
-
|
|
6
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
-
const __dirname = path.dirname(__filename);
|
|
8
|
-
|
|
9
|
-
const packageName =
|
|
10
|
-
path.basename(process.argv[1] ?? '') === 'index'
|
|
11
|
-
? 'poet'
|
|
12
|
-
: path.basename(process.argv[1] ?? '') || 'poet';
|
|
13
|
-
|
|
14
|
-
let cli: ChildProcess | null = null;
|
|
15
|
-
let isShuttingDown = false;
|
|
16
|
-
let hasExited = false;
|
|
17
|
-
|
|
18
|
-
const cleanup = async (): Promise<void> => {
|
|
19
|
-
if (isShuttingDown) return;
|
|
20
|
-
isShuttingDown = true;
|
|
21
|
-
|
|
22
|
-
if (cli && !cli.killed) {
|
|
23
|
-
try {
|
|
24
|
-
cli.kill('SIGTERM');
|
|
25
|
-
|
|
26
|
-
await new Promise<void>((resolve) => {
|
|
27
|
-
const timeout = setTimeout(() => {
|
|
28
|
-
if (cli && !cli.killed) {
|
|
29
|
-
cli.kill('SIGKILL');
|
|
30
|
-
}
|
|
31
|
-
resolve();
|
|
32
|
-
}, 5000);
|
|
33
|
-
|
|
34
|
-
cli?.once('exit', () => {
|
|
35
|
-
clearTimeout(timeout);
|
|
36
|
-
resolve();
|
|
37
|
-
});
|
|
38
|
-
});
|
|
39
|
-
} catch (_error) {
|
|
40
|
-
// ignore
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const exitProcess = (code: number) => {
|
|
46
|
-
if (hasExited) return;
|
|
47
|
-
hasExited = true;
|
|
48
|
-
process.exit(code);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const killSignals = ['SIGINT', 'SIGTERM', 'SIGQUIT', 'SIGHUP'];
|
|
52
|
-
killSignals.forEach((signal) => {
|
|
53
|
-
process.on(signal, async () => {
|
|
54
|
-
await cleanup();
|
|
55
|
-
exitProcess(0);
|
|
56
|
-
});
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
process.on('uncaughtException', async () => {
|
|
60
|
-
await cleanup();
|
|
61
|
-
exitProcess(1);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
process.on('unhandledRejection', async () => {
|
|
65
|
-
await cleanup();
|
|
66
|
-
exitProcess(1);
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
cli = spawn(
|
|
71
|
-
'node',
|
|
72
|
-
['--no-deprecation', path.join(__dirname, '../bin/start'), ...process.argv.slice(2)],
|
|
73
|
-
{
|
|
74
|
-
stdio: 'inherit',
|
|
75
|
-
env: {
|
|
76
|
-
...process.env,
|
|
77
|
-
POETORA_PACKAGE_NAME: packageName,
|
|
78
|
-
CLI_TEST_MODE: process.env.CLI_TEST_MODE ?? 'false',
|
|
79
|
-
},
|
|
80
|
-
shell: process.platform === 'win32',
|
|
81
|
-
windowsHide: process.platform === 'win32',
|
|
82
|
-
detached: false,
|
|
83
|
-
}
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
cli.on('error', async (error) => {
|
|
87
|
-
console.error(`Failed to start ${packageName}: ${error.message}`);
|
|
88
|
-
await cleanup();
|
|
89
|
-
exitProcess(1);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
cli.on('exit', (code) => {
|
|
93
|
-
exitProcess(code ?? 0);
|
|
94
|
-
});
|
|
95
|
-
} catch (error) {
|
|
96
|
-
console.error(`Failed to start ${packageName}: ${error}`);
|
|
97
|
-
exitProcess(1);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
process.on('exit', () => {
|
|
101
|
-
if (cli && !cli.killed) {
|
|
102
|
-
try {
|
|
103
|
-
cli.kill('SIGKILL');
|
|
104
|
-
} catch (_error) {
|
|
105
|
-
// ignore
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
export { cli };
|