@@ -541,9 +541,163 @@ async function editAndCommit(subject: string, body: string) {
541541}
542542
543543async function handleCheckCommand ( ) {
544- console . log ( 'Check command not yet optimized for performance mode.' ) ;
545- console . log ( 'Use: npx tsx scripts/check-commit.ts for now.' ) ;
546- process . exit ( 0 ) ;
544+ const { execSync } = await lazy ( ( ) => import ( 'child_process' ) ) ;
545+ const { readFile } = await lazy ( ( ) => import ( 'fs/promises' ) ) ;
546+ const { join } = await lazy ( ( ) => import ( 'path' ) ) ;
547+
548+ interface ValidationResult {
549+ valid: boolean ;
550+ errors: string [ ] ;
551+ }
552+
553+ interface ParsedCommit {
554+ type ? : string ;
555+ scope ? : string | undefined ;
556+ breaking ? : boolean ;
557+ subject ? : string ;
558+ body ? : string | undefined ;
559+ footer ? : string | undefined ;
560+ }
561+
562+ // Load configuration
563+ async function loadConfig ( ) {
564+ try {
565+ const configPath = join ( process . cwd ( ) , 'glinr-commit.json' ) ;
566+ const configFile = await readFile ( configPath , 'utf-8' ) ;
567+ const configData = JSON . parse ( configFile ) ;
568+ const { ConfigSchema } = await lazy ( ( ) => import ( '../src/types/config.js' ) ) ;
569+ return ConfigSchema . parse ( configData ) ;
570+ } catch ( error ) {
571+ const { defaultConfig } = await lazy ( ( ) => import ( '../src/config/defaultConfig.js' ) ) ;
572+ return defaultConfig ;
573+ }
574+ }
575+
576+ // Get latest commit message
577+ function getLatestCommitMessage ( ) : string {
578+ try {
579+ const message = execSync ( 'git log -1 --pretty=%B' , { encoding : 'utf-8' } ) ;
580+ return message . trim ( ) ;
581+ } catch ( error ) {
582+ console . error ( chalk . red ( '❌ Error: Failed to read commit message from git' ) ) ;
583+ console . error ( chalk . yellow ( '💡 Make sure you are in a git repository with at least one commit' ) ) ;
584+ console . error ( chalk . gray ( ' Run: ' ) + chalk . cyan ( 'git log --oneline -1' ) + chalk . gray ( ' to check recent commits' ) ) ;
585+ process . exit ( 1 ) ;
586+ }
587+ }
588+
589+ // Check if commit is special (merge, revert, etc.)
590+ function isSpecialCommit ( message : string ) : boolean {
591+ const header = message . split ( '\n' ) [ 0 ] || '' ;
592+ return header . startsWith ( 'Merge ' ) ||
593+ header . startsWith ( 'Revert ' ) ||
594+ header . startsWith ( 'fixup! ' ) ||
595+ header . startsWith ( 'squash! ' ) ||
596+ header . toLowerCase ( ) . includes ( 'initial commit' ) ;
597+ }
598+
599+ // Parse conventional commit message
600+ function parseCommitMessage ( message : string ) : ParsedCommit {
601+ const lines = message . split ( '\n' ) ;
602+ const header = lines [ 0 ] || '' ;
603+
604+ const conventionalPattern = / ^ ( \w + ) ( \( [ ^ ) ] + \) ) ? ( ! ) ? \s * : \s * ( .+ ) $ / ;
605+ const match = header . match ( conventionalPattern ) ;
606+
607+ if ( match ) {
608+ const [ , type , scopeWithParens , breaking , subject ] = match ;
609+ const scope = scopeWithParens ? scopeWithParens . slice ( 1 , - 1 ) : undefined ;
610+ const bodyText = lines . slice ( 2 ) . join ( '\n' ) . trim ( ) ;
611+
612+ return {
613+ type,
614+ scope,
615+ breaking : ! ! breaking ,
616+ subject,
617+ body : bodyText || undefined ,
618+ footer : undefined
619+ } ;
620+ }
621+
622+ return { subject : header } ;
623+ }
624+
625+ // Validate commit message
626+ function validateCommitMessage ( commit : ParsedCommit , config : any ) : ValidationResult {
627+ const errors : string [ ] = [ ] ;
628+
629+ if ( ! commit . type ) {
630+ errors . push ( 'Missing commit type (e.g., feat, fix, docs)' ) ;
631+ return { valid : false , errors } ;
632+ }
633+
634+ const validTypes = config . commitTypes . map ( ( t : any ) => t . type ) ;
635+ if ( ! validTypes . includes ( commit . type ) ) {
636+ errors . push ( `Invalid commit type "${ commit . type } ". Valid types: ${ validTypes . join ( ', ' ) } ` ) ;
637+ }
638+
639+ if ( ! commit . subject || commit . subject . length === 0 ) {
640+ errors . push ( 'Missing commit subject' ) ;
641+ } else {
642+ if ( commit . subject . length > config . maxSubjectLength ) {
643+ errors . push ( `Subject too long (${ commit . subject . length } /${ config . maxSubjectLength } chars)` ) ;
644+ }
645+
646+ if ( commit . subject . endsWith ( '.' ) ) {
647+ errors . push ( 'Subject should not end with a period' ) ;
648+ }
649+
650+ if ( commit . subject !== commit . subject . toLowerCase ( ) ) {
651+ errors . push ( 'Subject should be in lowercase' ) ;
652+ }
653+ }
654+
655+ return { valid : errors . length === 0 , errors } ;
656+ }
657+
658+ // Main check logic
659+ try {
660+ const config = await loadConfig ( ) ;
661+ const commitMessage = getLatestCommitMessage ( ) ;
662+
663+ console . log ( chalk . hex ( '#8b008b' ) . bold ( '🔍 Checking latest commit message...\n' ) ) ;
664+
665+ if ( isSpecialCommit ( commitMessage ) ) {
666+ console . log ( chalk . yellow ( '⚠️ Special commit detected (merge/revert/fixup/initial)' ) ) ;
667+ console . log ( chalk . gray ( ' Skipping conventional commit validation' ) ) ;
668+ console . log ( chalk . green ( '✅ Check complete' ) ) ;
669+ return ;
670+ }
671+
672+ const parsed = parseCommitMessage ( commitMessage ) ;
673+ const validation = validateCommitMessage ( parsed , config ) ;
674+
675+ console . log ( chalk . gray ( 'Latest commit:' ) ) ;
676+ console . log ( chalk . cyan ( `"${ commitMessage . split ( '\n' ) [ 0 ] } "` ) ) ;
677+ console . log ( '' ) ;
678+
679+ if ( validation . valid ) {
680+ console . log ( chalk . green ( '✅ Commit message follows conventional commit format' ) ) ;
681+ if ( parsed . type ) {
682+ const commitType = config . commitTypes . find ( ( t : any ) => t . type === parsed . type ) ;
683+ if ( commitType ) {
684+ console . log ( chalk . gray ( ` Type: ${ commitType . emoji } ${ parsed . type } - ${ commitType . description } ` ) ) ;
685+ }
686+ }
687+ } else {
688+ console . log ( chalk . red ( '❌ Commit message validation failed:' ) ) ;
689+ validation . errors . forEach ( error => {
690+ console . log ( chalk . red ( ` • ${ error } ` ) ) ;
691+ } ) ;
692+ console . log ( '' ) ;
693+ console . log ( chalk . yellow ( '💡 Example valid commit:' ) ) ;
694+ console . log ( chalk . green ( ' feat: add user authentication' ) ) ;
695+ console . log ( chalk . green ( ' fix(api): resolve login timeout issue' ) ) ;
696+ }
697+ } catch ( error ) {
698+ console . error ( chalk . red ( '❌ Validation failed:' ) , error instanceof Error ? error . message : error ) ;
699+ process . exit ( 1 ) ;
700+ }
547701}
548702
549703async function handleConfigSubmenu ( ) {
0 commit comments