Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 31 additions & 5 deletions src/ai/guidance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@
import { assetsAI } from '../consts'
import { logger } from './logger'

/**
* Type definition for markdown-to-ansi converter function.
* Takes markdown text and returns ANSI-formatted string.
*/
type MarkdownConverter = (text: string) => string

/**
* Type definition for markdown-to-ansi factory function.
* Returns a converter function when called.
*/
type MarkdownToAnsiFactory = () => MarkdownConverter

/**
* Type definition for the markdown-to-ansi module.
* Can export the factory as default or as the module itself.
*/
type MarkdownToAnsiModule = {
default?: MarkdownToAnsiFactory
} & MarkdownToAnsiFactory

/**
* Loads and formats the guidance message from markdown file for terminal display.
* Converts markdown formatting (bold, italic, code, etc.) to ANSI escape codes.
Expand All @@ -18,21 +38,27 @@

/*
* Dynamic import is used because markdown-to-ansi is an ES module.
* When compiled to CommonJS, static imports would be transformed to require(),
* which doesn't work for ES modules in Node.js 18 and below.
* When compiled to CommonJS, TypeScript transforms import() to require(),
* which doesn't work for ES modules in Node.js 16 and 18.
* Using Function constructor prevents TypeScript from transforming the import.
*/
const markdownToAnsiModule = await import('markdown-to-ansi')
const markdownToAnsiFactory = markdownToAnsiModule.default ?? markdownToAnsiModule
const converter = markdownToAnsiFactory()
// eslint-disable-next-line @typescript-eslint/no-implied-eval
const dynamicImport = new Function('specifier', 'return import(specifier)') as (

Check warning on line 46 in src/ai/guidance.ts

View workflow job for this annotation

GitHub Actions / ci / ci

The 'new Function('specifier', 'return import(specifier)') as ( specifier: string ) => Promise<MarkdownToAnsiModule>' has unsafe 'as' type assertion
specifier: string
) => Promise<MarkdownToAnsiModule>
const markdownToAnsiModule = await dynamicImport('markdown-to-ansi')
const markdownToAnsiFactory: MarkdownToAnsiFactory = markdownToAnsiModule.default ?? markdownToAnsiModule
// markdown-to-ansi exports a factory function that returns a converter function
const converter: MarkdownConverter = markdownToAnsiFactory()
// Convert markdown to ANSI-formatted terminal text (supports bold, italic, code, etc.)

return converter(guidanceTemplate).trim()
} catch (error) {

Check warning on line 56 in src/ai/guidance.ts

View workflow job for this annotation

GitHub Actions / ci / ci

The type of 'error' is 'any'
/*
* Fallback if guidance file doesn't exist or conversion fails
* File not found (ENOENT) is expected and silent, other errors are logged
*/
if (error instanceof Error && 'code' in error && error.code !== 'ENOENT') {

Check warning on line 61 in src/ai/guidance.ts

View workflow job for this annotation

GitHub Actions / ci / ci

The type of 'error' is 'any'
logger.warn(`Failed to load guidance file: ${error.message}`)
}
return ''
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ program
} catch (error) {
if (error instanceof GuidanceError) {
const guidance = await error.guidance

if (guidance) {
console.log() // Add spacing before guidance
logger.info(guidance)
Expand Down
Loading