@poetora/cli 0.1.4 → 0.1.5

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.
@@ -1,4 +1,4 @@
1
1
 
2
- > @poetora/cli@0.1.3 build /home/runner/work/poetora/poetora/packages/cli
2
+ > @poetora/cli@0.1.4 build /home/runner/work/poetora/poetora/packages/cli
3
3
  > tsc --project tsconfig.build.json
4
4
 
@@ -1,6 +1,8 @@
1
+ import chalk from 'chalk';
1
2
  import yargs from 'yargs';
2
3
  import { hideBin } from 'yargs/helpers';
3
4
  import { CheckCommand, DevCommand, InitCommand, LinkCommand, UpdateCommand, } from './commands/index.js';
5
+ import { checkNodeVersion, suppressConsoleWarnings } from './middlewares.js';
4
6
  import { AccessibilityCheckService, LinkService, OpenApiCheckService, PortService, TemplateService, UpdateService, VersionService, } from './services/index.js';
5
7
  import { ConsoleLogger } from './utils/index.js';
6
8
  export class CliBuilder {
@@ -23,8 +25,12 @@ export class CliBuilder {
23
25
  const checkCommand = new CheckCommand(this.logger, openApiCheckService, accessibilityCheckService, this.packageName);
24
26
  const linkCommand = new LinkCommand(this.logger, linkService, this.packageName);
25
27
  const updateCommand = new UpdateCommand(this.logger, updateService, this.packageName);
28
+ const cliVersion = versionService.getCliVersion() || '0.0.0';
26
29
  return (yargs(hideBin(process.argv))
27
30
  .scriptName(this.packageName)
31
+ .version(cliVersion)
32
+ .middleware(checkNodeVersion)
33
+ .middleware(suppressConsoleWarnings)
28
34
  .command('dev', 'initialize a local preview environment', (yargs) => yargs
29
35
  .option('port', {
30
36
  type: 'number',
@@ -163,8 +169,8 @@ export class CliBuilder {
163
169
  })
164
170
  .command(['version', 'v'], 'display the current version of the CLI and client', () => undefined, async () => {
165
171
  const versions = versionService.getVersions();
166
- this.logger.log(`cli version: ${versions.cli}`);
167
- this.logger.log(`client version: ${versions.client}`);
172
+ console.log(`${chalk.bold.green('cli version')} ${versions.cli}`);
173
+ console.log(`${chalk.bold.green('client version')} ${versions.client}`);
168
174
  process.exit(0);
169
175
  })
170
176
  .strictCommands()
package/bin/cli.js CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import { Logs } from '@poetora/previewing';
3
+ import { render } from 'ink';
4
+ import React from 'react';
2
5
  import { CliBuilder } from './cli-builder.js';
3
6
  export const cli = (options) => {
7
+ render(React.createElement(Logs));
4
8
  const builder = new CliBuilder(options.packageName);
5
9
  builder.run().catch((error) => {
6
10
  console.error('Fatal error:', error);
@@ -26,12 +26,12 @@ export class BaseCommand {
26
26
  else if (error instanceof Error) {
27
27
  this.logger.error(error.message);
28
28
  if (process.env.DEBUG === 'true') {
29
- console.error(error.stack);
29
+ this.logger.logColor(error.stack ?? '', 'gray');
30
30
  }
31
31
  }
32
32
  else {
33
33
  this.logger.error('An unexpected error occurred');
34
- console.error(error);
34
+ this.logger.logColor(String(error), 'gray');
35
35
  }
36
36
  }
37
37
  exit(code) {
@@ -1,7 +1,7 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
1
  import { categorizeFilePaths, getPoetIgnore } from '@poetora/prebuild';
4
2
  import { coreRemark } from '@poetora/shared';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
5
  import { visit } from 'unist-util-visit';
6
6
  const checkAltAttributes = (filePath, content) => {
7
7
  const issues = [];
@@ -0,0 +1,2 @@
1
+ export declare const checkNodeVersion: () => Promise<void>;
2
+ export declare const suppressConsoleWarnings: () => void;
@@ -0,0 +1,47 @@
1
+ import { addLog, ErrorLog } from '@poetora/previewing';
2
+ import React from 'react';
3
+ export const checkNodeVersion = async () => {
4
+ let nodeVersionString = process.version;
5
+ if (nodeVersionString.charAt(0) === 'v') {
6
+ nodeVersionString = nodeVersionString.slice(1);
7
+ }
8
+ const versionArr = nodeVersionString.split('.');
9
+ const versionStr = versionArr[0];
10
+ if (!versionStr) {
11
+ addLog(React.createElement(ErrorLog, {
12
+ message: `Unable to determine Node.js version (got "${process.version}"). Please ensure you are running Node.js >= 18.0.0.`,
13
+ }));
14
+ process.exit(1);
15
+ }
16
+ const majorVersion = parseInt(versionStr, 10);
17
+ if (majorVersion < 18) {
18
+ addLog(React.createElement(ErrorLog, {
19
+ message: `poetora requires Node.js >= 18.0.0 (current version ${nodeVersionString}). Please upgrade Node.js and try again.`,
20
+ }));
21
+ process.exit(1);
22
+ }
23
+ };
24
+ export const suppressConsoleWarnings = () => {
25
+ const ignoredMessages = [
26
+ 'No utility classes were detected',
27
+ 'https://tailwindcss.com/docs/content-configuration',
28
+ 'DeprecationWarning',
29
+ 'punycode',
30
+ ];
31
+ const originalConsoleError = console.error;
32
+ console.error = (...args) => {
33
+ const message = args.join(' ');
34
+ if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
35
+ return;
36
+ }
37
+ originalConsoleError.apply(console, args);
38
+ };
39
+ const originalConsoleWarn = console.warn;
40
+ console.warn = (...args) => {
41
+ const message = args.join(' ');
42
+ if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
43
+ return;
44
+ }
45
+ originalConsoleWarn.apply(console, args);
46
+ };
47
+ };
@@ -1,6 +1,6 @@
1
- import path from 'path';
2
1
  import { getConfigObj, getConfigPath } from '@poetora/prebuild';
3
2
  import { getBackgroundColors } from '@poetora/shared';
3
+ import path from 'path';
4
4
  import { checkDocsColors, } from '../accessibility.js';
5
5
  import { CMD_EXEC_PATH } from '../constants.js';
6
6
  import { checkMdxAccessibility } from '../mdxAccessibility.js';
@@ -1,5 +1,5 @@
1
- import * as path from 'path';
2
1
  import { getBrokenInternalLinks, renameFilesAndUpdateLinksInContent, } from '@poetora/link-rot';
2
+ import * as path from 'path';
3
3
  export class LinkService {
4
4
  logger;
5
5
  constructor(logger) {
@@ -26,7 +26,7 @@ export class LinkService {
26
26
  this.logger.log(`found ${this.logger.highlight?.(brokenLinks.length.toString()) ?? brokenLinks.length} broken link${brokenLinks.length === 1 ? '' : 's'} in ${this.logger.highlight?.(fileCount.toString()) ?? fileCount} file${fileCount === 1 ? '' : 's'}`);
27
27
  this.logger.logNewLine();
28
28
  for (const [filename, links] of Object.entries(brokenLinksByFile)) {
29
- console.log(`\x1b[4m${filename}\x1b[0m`);
29
+ this.logger.logColor(filename, 'cyan');
30
30
  links.forEach((link) => {
31
31
  this.logger.logColor(` ⎿ ${link}`, 'gray');
32
32
  });
@@ -1,5 +1,5 @@
1
- import * as fs from 'fs';
2
1
  import { getOpenApiDocumentFromUrl, isAllowedLocalSchemaUrl, validate } from '@poetora/shared';
2
+ import * as fs from 'fs';
3
3
  import * as yaml from 'js-yaml';
4
4
  import { FileSystemError, ValidationError } from '../errors/index.js';
5
5
  export class OpenApiCheckService {
@@ -1,8 +1,8 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
1
  import { docsConfigSchema } from '@poetora/validation';
4
2
  import AdmZip from 'adm-zip';
3
+ import * as fs from 'fs';
5
4
  import * as fse from 'fs-extra';
5
+ import * as path from 'path';
6
6
  import { ExternalServiceError, FileSystemError } from '../errors/index.js';
7
7
  export class TemplateService {
8
8
  TEMPLATE_URL = 'https://github.com/poetora/starter/archive/refs/heads/main.zip';
@@ -1,5 +1,5 @@
1
- import { execSync } from 'child_process';
2
1
  import { getClientVersion, LOCAL_LINKED_CLI_VERSION } from '@poetora/previewing';
2
+ import { execSync } from 'child_process';
3
3
  import yargs from 'yargs';
4
4
  import { InvalidEnvironmentError } from '../errors/index.js';
5
5
  import { CLI_CONSTANTS } from '../types/index.js';
@@ -1,65 +1,61 @@
1
+ import { addLog, EmptyLineLog, ErrorLog, InfoLog, SpinnerLog, SuccessLog, WarningLog, } from '@poetora/previewing';
1
2
  import chalk from 'chalk';
2
- import ora from 'ora';
3
+ import { Text } from 'ink';
4
+ import React from 'react';
3
5
  export class ConsoleLogger {
4
6
  info(message) {
5
- console.log(chalk.blue(`ℹ ${message}`));
7
+ addLog(React.createElement(InfoLog, { message }));
6
8
  }
7
9
  success(message) {
8
- console.log(chalk.green(`✓ ${message}`));
10
+ addLog(React.createElement(SuccessLog, { message }));
9
11
  }
10
12
  error(message) {
11
- console.error(chalk.red(`✗ ${message}`));
13
+ addLog(React.createElement(ErrorLog, { message }));
12
14
  }
13
15
  warn(message) {
14
- console.warn(chalk.yellow(`⚠ ${message}`));
16
+ addLog(React.createElement(WarningLog, { message }));
15
17
  }
16
18
  spinner(message) {
17
- return new ConsoleSpinner(message);
19
+ addLog(React.createElement(SpinnerLog, { message }));
20
+ return new InkSpinner();
18
21
  }
19
22
  log(message) {
20
- console.log(message);
23
+ addLog(React.createElement(Text, {}, message));
21
24
  }
22
25
  logColor(message, color) {
23
- console.log(chalk[color](message));
26
+ addLog(React.createElement(Text, { color }, message));
24
27
  }
25
28
  logBold(message, color) {
26
- if (color) {
27
- console.log(chalk[color].bold(message));
28
- }
29
- else {
30
- console.log(chalk.bold(message));
31
- }
29
+ addLog(React.createElement(Text, { bold: true, color }, message));
32
30
  }
33
31
  logSeparator() {
34
- console.log(chalk.gray('─'.repeat(50)));
32
+ addLog(React.createElement(Text, { color: 'gray' }, '─'.repeat(50)));
35
33
  }
36
34
  logNewLine() {
37
- console.log();
35
+ addLog(React.createElement(EmptyLineLog));
38
36
  }
39
37
  logHeader(message) {
40
- console.log();
41
- console.log(chalk.bold.cyan(message));
42
- console.log();
38
+ this.logNewLine();
39
+ addLog(React.createElement(Text, { bold: true, color: 'cyan' }, message));
40
+ this.logNewLine();
43
41
  }
44
42
  highlight(text) {
45
43
  return chalk.yellow(text);
46
44
  }
47
45
  }
48
- class ConsoleSpinner {
49
- spinner;
50
- constructor(message) {
51
- this.spinner = ora(message);
52
- }
46
+ class InkSpinner {
53
47
  start() {
54
- this.spinner.start();
55
48
  }
56
49
  stop() {
57
- this.spinner.stop();
58
50
  }
59
51
  succeed(message) {
60
- this.spinner.succeed(message);
52
+ if (message) {
53
+ addLog(React.createElement(SuccessLog, { message }));
54
+ }
61
55
  }
62
56
  fail(message) {
63
- this.spinner.fail(message);
57
+ if (message) {
58
+ addLog(React.createElement(ErrorLog, { message }));
59
+ }
64
60
  }
65
61
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poetora/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "The CLI for Poetora documentation Engine",
5
5
  "engines": {
6
6
  "node": ">=18.0.0"
@@ -33,19 +33,19 @@
33
33
  "detect-port": "1.5.1",
34
34
  "front-matter": "4.0.2",
35
35
  "fs-extra": "11.2.0",
36
+ "ink": "6.3.0",
36
37
  "inquirer": "12.3.0",
37
38
  "js-yaml": "4.1.0",
38
39
  "mdast-util-mdx-jsx": "3.2.0",
39
- "ora": "^8.1.1",
40
- "react": "^19.0.1",
40
+ "react": "19.2.3",
41
41
  "semver": "7.7.2",
42
42
  "unist-util-visit": "5.0.0",
43
43
  "yargs": "17.7.1",
44
- "@poetora/link-rot": "0.0.6",
45
- "@poetora/prebuild": "0.1.5",
46
- "@poetora/previewing": "0.1.5",
47
- "@poetora/shared": "0.1.5",
48
- "@poetora/validation": "0.1.5"
44
+ "@poetora/link-rot": "0.0.7",
45
+ "@poetora/prebuild": "0.1.6",
46
+ "@poetora/previewing": "0.1.6",
47
+ "@poetora/shared": "0.1.6",
48
+ "@poetora/validation": "0.1.6"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@tsconfig/recommended": "1.0.2",
@@ -53,9 +53,10 @@
53
53
  "@types/color": "^3.0.3",
54
54
  "@types/detect-port": "1.3.2",
55
55
  "@types/fs-extra": "^9.0.13",
56
- "@types/js-yaml": "^4.0.9",
56
+ "@types/js-yaml": "4.0.9",
57
57
  "@types/mdast": "4.0.4",
58
58
  "@types/node": "22.19.2",
59
+ "@types/react": "19.2.7",
59
60
  "@types/yargs": "17.0.22",
60
61
  "@typescript-eslint/eslint-plugin": "8.49.0",
61
62
  "@typescript-eslint/parser": "8.49.0",
@@ -1,7 +1,7 @@
1
+ import chalk from 'chalk';
1
2
  import type { Argv } from 'yargs';
2
3
  import yargs from 'yargs';
3
4
  import { hideBin } from 'yargs/helpers';
4
-
5
5
  import {
6
6
  CheckCommand,
7
7
  DevCommand,
@@ -9,6 +9,7 @@ import {
9
9
  LinkCommand,
10
10
  UpdateCommand,
11
11
  } from './commands/index.js';
12
+ import { checkNodeVersion, suppressConsoleWarnings } from './middlewares.js';
12
13
  import {
13
14
  AccessibilityCheckService,
14
15
  LinkService,
@@ -57,9 +58,15 @@ export class CliBuilder {
57
58
  const linkCommand = new LinkCommand(this.logger, linkService, this.packageName);
58
59
  const updateCommand = new UpdateCommand(this.logger, updateService, this.packageName);
59
60
 
61
+ // Get CLI version for yargs
62
+ const cliVersion = versionService.getCliVersion() || '0.0.0';
63
+
60
64
  return (
61
65
  yargs(hideBin(process.argv))
62
66
  .scriptName(this.packageName)
67
+ .version(cliVersion) // Explicitly set version to fix "unknown" issue
68
+ .middleware(checkNodeVersion) // Check Node.js version before any command
69
+ .middleware(suppressConsoleWarnings) // Suppress known console warnings
63
70
  // Dev command
64
71
  .command(
65
72
  'dev',
@@ -245,8 +252,9 @@ export class CliBuilder {
245
252
  () => undefined,
246
253
  async () => {
247
254
  const versions = versionService.getVersions();
248
- this.logger.log(`cli version: ${versions.cli}`);
249
- this.logger.log(`client version: ${versions.client}`);
255
+ // Use chalk for consistent formatting (mintlify uses ink Text, we use chalk)
256
+ console.log(`${chalk.bold.green('cli version')} ${versions.cli}`);
257
+ console.log(`${chalk.bold.green('client version')} ${versions.client}`);
250
258
  process.exit(0);
251
259
  }
252
260
  )
package/src/cli.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import { Logs } from '@poetora/previewing';
3
+ import { render } from 'ink';
4
+ import React from 'react';
5
+
2
6
  import { CliBuilder } from './cli-builder.js';
3
7
 
4
8
  export interface CliOptions {
@@ -6,6 +10,9 @@ export interface CliOptions {
6
10
  }
7
11
 
8
12
  export const cli = (options: CliOptions): void => {
13
+ // Initialize ink rendering for logs (like mintlify)
14
+ render(React.createElement(Logs));
15
+
9
16
  const builder = new CliBuilder(options.packageName);
10
17
 
11
18
  builder.run().catch((error) => {
@@ -78,12 +78,12 @@ export abstract class BaseCommand<TOptions = unknown, TResult = void> {
78
78
 
79
79
  // In debug mode, show stack trace
80
80
  if (process.env.DEBUG === 'true') {
81
- console.error(error.stack);
81
+ this.logger.logColor(error.stack ?? '', 'gray');
82
82
  }
83
83
  } else {
84
84
  // Unknown error types
85
85
  this.logger.error('An unexpected error occurred');
86
- console.error(error);
86
+ this.logger.logColor(String(error), 'gray');
87
87
  }
88
88
  }
89
89
 
@@ -1,9 +1,9 @@
1
- import fs from 'fs';
2
- import path from 'path';
3
1
  import { categorizeFilePaths, getPoetIgnore } from '@poetora/prebuild';
4
2
  import { coreRemark } from '@poetora/shared';
3
+ import fs from 'fs';
5
4
  import type { Node, Root, Text } from 'mdast';
6
5
  import type { MdxJsxFlowElement } from 'mdast-util-mdx-jsx';
6
+ import path from 'path';
7
7
  import { visit } from 'unist-util-visit';
8
8
 
9
9
  export interface AccessibilityFixAttribute {
@@ -0,0 +1,73 @@
1
+ import { addLog, ErrorLog } from '@poetora/previewing';
2
+ import React from 'react';
3
+
4
+ /**
5
+ * Yargs middleware functions
6
+ * These run before command execution
7
+ */
8
+
9
+ /**
10
+ * Check if Node.js version is supported
11
+ * Middleware that validates Node version before any command runs
12
+ *
13
+ * Minimum requirement: Node.js >= 18.0.0
14
+ * Note: Individual commands may have stricter requirements (e.g., dev command)
15
+ */
16
+ export const checkNodeVersion = async (): Promise<void> => {
17
+ let nodeVersionString = process.version;
18
+ if (nodeVersionString.charAt(0) === 'v') {
19
+ nodeVersionString = nodeVersionString.slice(1);
20
+ }
21
+ const versionArr = nodeVersionString.split('.');
22
+ const versionStr = versionArr[0];
23
+ if (!versionStr) {
24
+ addLog(
25
+ React.createElement(ErrorLog, {
26
+ message: `Unable to determine Node.js version (got "${process.version}"). Please ensure you are running Node.js >= 18.0.0.`,
27
+ })
28
+ );
29
+ process.exit(1);
30
+ }
31
+ const majorVersion = parseInt(versionStr, 10);
32
+
33
+ if (majorVersion < 18) {
34
+ addLog(
35
+ React.createElement(ErrorLog, {
36
+ message: `poetora requires Node.js >= 18.0.0 (current version ${nodeVersionString}). Please upgrade Node.js and try again.`,
37
+ })
38
+ );
39
+ process.exit(1);
40
+ }
41
+ };
42
+
43
+ /**
44
+ * Suppress common console warnings that don't affect functionality
45
+ * Filters out known noise from dependencies
46
+ */
47
+ export const suppressConsoleWarnings = (): void => {
48
+ // Ignore tailwind warnings and punycode deprecation warning
49
+ const ignoredMessages = [
50
+ 'No utility classes were detected',
51
+ 'https://tailwindcss.com/docs/content-configuration',
52
+ 'DeprecationWarning',
53
+ 'punycode',
54
+ ];
55
+
56
+ const originalConsoleError = console.error;
57
+ console.error = (...args) => {
58
+ const message = args.join(' ');
59
+ if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
60
+ return;
61
+ }
62
+ originalConsoleError.apply(console, args);
63
+ };
64
+
65
+ const originalConsoleWarn = console.warn;
66
+ console.warn = (...args) => {
67
+ const message = args.join(' ');
68
+ if (ignoredMessages.some((ignoredMessage) => message.includes(ignoredMessage))) {
69
+ return;
70
+ }
71
+ originalConsoleWarn.apply(console, args);
72
+ };
73
+ };
@@ -1,5 +1,5 @@
1
- import * as fs from 'fs';
2
1
  import AdmZip from 'adm-zip';
2
+ import * as fs from 'fs';
3
3
  import * as fse from 'fs-extra';
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
5
  import { ExternalServiceError, FileSystemError } from '../../errors/index.js';
@@ -1,6 +1,6 @@
1
- import path from 'path';
2
1
  import { getConfigObj, getConfigPath } from '@poetora/prebuild';
3
2
  import { getBackgroundColors } from '@poetora/shared';
3
+ import path from 'path';
4
4
  import {
5
5
  type AccessibilityCheckResult,
6
6
  type ContrastResult,
@@ -1,9 +1,9 @@
1
- import * as path from 'path';
2
1
  import {
3
2
  getBrokenInternalLinks,
4
3
  type MdxPath,
5
4
  renameFilesAndUpdateLinksInContent,
6
5
  } from '@poetora/link-rot';
6
+ import * as path from 'path';
7
7
 
8
8
  import type { ILogger } from '../utils/index.js';
9
9
 
@@ -46,7 +46,7 @@ export class LinkService {
46
46
 
47
47
  for (const [filename, links] of Object.entries(brokenLinksByFile)) {
48
48
  // Underline filename for better visibility
49
- console.log(`\x1b[4m${filename}\x1b[0m`);
49
+ this.logger.logColor(filename, 'cyan');
50
50
  links.forEach((link) => {
51
51
  this.logger.logColor(` ⎿ ${link}`, 'gray');
52
52
  });
@@ -1,5 +1,5 @@
1
- import * as fs from 'fs';
2
1
  import { getOpenApiDocumentFromUrl, isAllowedLocalSchemaUrl, validate } from '@poetora/shared';
2
+ import * as fs from 'fs';
3
3
  import * as yaml from 'js-yaml';
4
4
 
5
5
  import { FileSystemError, ValidationError } from '../errors/index.js';
@@ -1,8 +1,8 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
1
  import { docsConfigSchema } from '@poetora/validation';
4
2
  import AdmZip from 'adm-zip';
3
+ import * as fs from 'fs';
5
4
  import * as fse from 'fs-extra';
5
+ import * as path from 'path';
6
6
 
7
7
  import { ExternalServiceError, FileSystemError } from '../errors/index.js';
8
8
 
@@ -1,5 +1,5 @@
1
- import { execSync } from 'child_process';
2
1
  import { getClientVersion, LOCAL_LINKED_CLI_VERSION } from '@poetora/previewing';
2
+ import { execSync } from 'child_process';
3
3
  import yargs from 'yargs';
4
4
 
5
5
  import { InvalidEnvironmentError } from '../errors/index.js';
@@ -1,37 +1,50 @@
1
+ import {
2
+ addLog,
3
+ EmptyLineLog,
4
+ ErrorLog,
5
+ InfoLog,
6
+ SpinnerLog,
7
+ SuccessLog,
8
+ WarningLog,
9
+ } from '@poetora/previewing';
1
10
  import chalk from 'chalk';
2
- import ora, { type Ora } from 'ora';
11
+ import { Text } from 'ink';
12
+ import React from 'react';
3
13
 
4
14
  import type { LoggerSpinner } from '../types/index.js';
5
15
 
6
16
  import type { ILogger } from './logger.interface.js';
7
17
 
8
18
  /**
9
- * Console-based logger implementation using chalk for colors
10
- * Provides rich colored output similar to ink but with simpler console-based approach
19
+ * Logger implementation using ink and addLog from @poetora/previewing
20
+ * Provides consistent output with the preview server's logging system
21
+ * Following mintlify's architecture pattern
11
22
  */
12
23
  export class ConsoleLogger implements ILogger {
13
24
  info(message: string): void {
14
- console.log(chalk.blue(`ℹ ${message}`));
25
+ addLog(React.createElement(InfoLog, { message }));
15
26
  }
16
27
 
17
28
  success(message: string): void {
18
- console.log(chalk.green(`✓ ${message}`));
29
+ addLog(React.createElement(SuccessLog, { message }));
19
30
  }
20
31
 
21
32
  error(message: string): void {
22
- console.error(chalk.red(`✗ ${message}`));
33
+ addLog(React.createElement(ErrorLog, { message }));
23
34
  }
24
35
 
25
36
  warn(message: string): void {
26
- console.warn(chalk.yellow(`⚠ ${message}`));
37
+ addLog(React.createElement(WarningLog, { message }));
27
38
  }
28
39
 
29
40
  spinner(message: string): LoggerSpinner {
30
- return new ConsoleSpinner(message);
41
+ // Immediately add spinner log
42
+ addLog(React.createElement(SpinnerLog, { message }));
43
+ return new InkSpinner();
31
44
  }
32
45
 
33
46
  log(message: string): void {
34
- console.log(message);
47
+ addLog(React.createElement(Text, {}, message));
35
48
  }
36
49
 
37
50
  /**
@@ -41,45 +54,42 @@ export class ConsoleLogger implements ILogger {
41
54
  message: string,
42
55
  color: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta' | 'gray'
43
56
  ): void {
44
- console.log(chalk[color](message));
57
+ addLog(React.createElement(Text, { color }, message));
45
58
  }
46
59
 
47
60
  /**
48
61
  * Log bold text
49
62
  */
50
63
  logBold(message: string, color?: 'green' | 'red' | 'yellow' | 'blue' | 'cyan' | 'magenta'): void {
51
- if (color) {
52
- console.log(chalk[color].bold(message));
53
- } else {
54
- console.log(chalk.bold(message));
55
- }
64
+ addLog(React.createElement(Text, { bold: true, color }, message));
56
65
  }
57
66
 
58
67
  /**
59
68
  * Log a separator line
60
69
  */
61
70
  logSeparator(): void {
62
- console.log(chalk.gray('─'.repeat(50)));
71
+ addLog(React.createElement(Text, { color: 'gray' }, '─'.repeat(50)));
63
72
  }
64
73
 
65
74
  /**
66
75
  * Log an empty line
67
76
  */
68
77
  logNewLine(): void {
69
- console.log();
78
+ addLog(React.createElement(EmptyLineLog));
70
79
  }
71
80
 
72
81
  /**
73
82
  * Log a section header
74
83
  */
75
84
  logHeader(message: string): void {
76
- console.log();
77
- console.log(chalk.bold.cyan(message));
78
- console.log();
85
+ this.logNewLine();
86
+ addLog(React.createElement(Text, { bold: true, color: 'cyan' }, message));
87
+ this.logNewLine();
79
88
  }
80
89
 
81
90
  /**
82
91
  * Highlight text (typically numbers) with yellow color
92
+ * Note: Returns styled text string for embedding in messages
83
93
  */
84
94
  highlight(text: string): string {
85
95
  return chalk.yellow(text);
@@ -87,28 +97,28 @@ export class ConsoleLogger implements ILogger {
87
97
  }
88
98
 
89
99
  /**
90
- * Console spinner implementation using ora
100
+ * Spinner implementation for ink-based logging
101
+ * Note: In ink/React rendering model, spinners are added as logs
102
+ * and don't need explicit start/stop/succeed/fail methods
91
103
  */
92
- class ConsoleSpinner implements LoggerSpinner {
93
- private spinner: Ora;
94
-
95
- constructor(message: string) {
96
- this.spinner = ora(message);
97
- }
98
-
104
+ class InkSpinner implements LoggerSpinner {
99
105
  start(): void {
100
- this.spinner.start();
106
+ // No-op: spinner already added to log stream
101
107
  }
102
108
 
103
109
  stop(): void {
104
- this.spinner.stop();
110
+ // No-op: will be replaced by next log
105
111
  }
106
112
 
107
113
  succeed(message?: string): void {
108
- this.spinner.succeed(message);
114
+ if (message) {
115
+ addLog(React.createElement(SuccessLog, { message }));
116
+ }
109
117
  }
110
118
 
111
119
  fail(message?: string): void {
112
- this.spinner.fail(message);
120
+ if (message) {
121
+ addLog(React.createElement(ErrorLog, { message }));
122
+ }
113
123
  }
114
124
  }