11import { Command , Option } from '@commander-js/extra-typings' ;
2- import { aiCommits } from './aicommits' ;
2+ import { bgCyan , black , green , red , yellow } from 'kolorist' ;
3+ import { handleCliError , KnownError } from '../utils/error' ;
4+ import { isError } from '../utils/typeguards' ;
5+ import { Container } from 'inversify' ;
6+ import { AIAgentService } from '../services/ai-agent.service' ;
7+ import { AICommitMessageService } from '../services/ai-commit-message.service' ;
8+ import { AICommitSplittingService } from '../services/ai-commit-splitting.service' ;
9+ import { GitService } from '../services/git.service' ;
10+ import { ConfigService } from '../services/config.service' ;
11+ import { ClackPromptService } from '../services/clack-prompt.service' ;
12+ import { agentStreamingReviewAndRevise , handleCommitSplitting } from './aicommits-utils' ;
13+ import { trimLines } from '../utils/string' ;
314import { container } from '../utils/di' ;
415import { CLI_ARGUMENTS } from '../services/config.service' ;
516
17+ export const aiCommitsAgent = async ( {
18+ container,
19+ stageAll = false ,
20+ profile = 'default' ,
21+ splitMode = false ,
22+ } : {
23+ container : Container ;
24+ stageAll ?: boolean ;
25+ profile ?: string ;
26+ splitMode ?: boolean ;
27+ } ) => {
28+ const configService = container . get ( ConfigService ) ;
29+ const gitService = container . get ( GitService ) ;
30+ const aiAgentService = container . get ( AIAgentService ) ;
31+ const aiCommitMessageService = container . get ( AICommitMessageService ) ;
32+ const aiCommitSplittingService = container . get ( AICommitSplittingService ) ;
33+ const promptUI = container . get ( ClackPromptService ) ;
34+
35+ try {
36+ await configService . readConfig ( ) ;
37+
38+ promptUI . intro ( bgCyan ( black ( ' aicommits agent ' ) ) ) ;
39+ const validResult = configService . validConfig ( ) ;
40+ if ( ! validResult . valid ) {
41+ promptUI . note (
42+ trimLines ( `
43+ It looks like you haven't set up aicommits yet. Let's get you started!
44+
45+ Run ${ yellow ( 'aicommits setup' ) } to configure your settings.
46+ ` ) ,
47+ ) ;
48+ process . exit ( 1 ) ;
49+ }
50+
51+ const currentProfile = configService . getProfile ( profile ) ;
52+ if ( ! currentProfile ) {
53+ const config = configService . getProfileNames ( ) ;
54+ promptUI . note (
55+ trimLines ( `
56+ Profile "${ profile } " not found. Available profiles: ${ config . join ( ', ' ) }
57+
58+ Run ${ yellow ( 'aicommits setup --profile ' + profile ) } to create this profile.
59+ ` ) ,
60+ ) ;
61+ process . exit ( 1 ) ;
62+ }
63+
64+ const config = currentProfile ;
65+
66+ // Display provider and model information
67+ promptUI . note (
68+ trimLines ( `
69+ Profile: ${ yellow ( profile ) }
70+ Provider: ${ yellow ( config . provider ) }
71+ Model: ${ yellow ( config . model ) }
72+ Endpoint: ${ yellow ( config . baseUrl ) }
73+ ` ) ,
74+ ) ;
75+
76+ await gitService . assertGitRepo ( ) ;
77+
78+ if ( stageAll ) {
79+ const stagingSpinner = promptUI . spinner ( ) ;
80+ stagingSpinner . start ( 'Staging all files' ) ;
81+ await gitService . stageAllFiles ( ) ;
82+ stagingSpinner . stop ( 'All files staged' ) ;
83+ }
84+
85+ if ( splitMode ) {
86+ await handleSplitMode ( aiCommitSplittingService , aiCommitMessageService , gitService , promptUI ) ;
87+ } else {
88+ await handleAgentMode ( aiAgentService , gitService , promptUI ) ;
89+ }
90+ } catch ( error ) {
91+ if ( isError ( error ) ) {
92+ promptUI . outro ( `${ red ( '✖' ) } ${ error . message } ` ) ;
93+ } else {
94+ promptUI . outro ( `${ red ( '✖' ) } An unknown error occurred` ) ;
95+ }
96+ handleCliError ( error ) ;
97+ process . exit ( 1 ) ;
98+ }
99+ } ;
100+
101+ async function handleAgentMode (
102+ aiAgentService : AIAgentService ,
103+ gitService : GitService ,
104+ promptUI : ClackPromptService ,
105+ ) : Promise < void > {
106+ const analyzeSpinner = promptUI . spinner ( ) ;
107+ analyzeSpinner . start ( 'AI agent is analyzing the repository...' ) ;
108+
109+ try {
110+ const result = await aiAgentService . generateCommitWithAgent ( {
111+ onToolCall : ( message : string ) => {
112+ analyzeSpinner . message ( `AI agent: ${ message } ` ) ;
113+ } ,
114+ } ) ;
115+ analyzeSpinner . stop ( 'Repository analysis complete' ) ;
116+
117+ // Display the generated commit message
118+ promptUI . log . step ( 'Generated commit message:' ) ;
119+ promptUI . log . message ( green ( result . commitMessage ) ) ;
120+
121+ if ( result . body ) {
122+ promptUI . log . step ( 'Commit body:' ) ;
123+ promptUI . log . message ( result . body ) ;
124+ }
125+
126+ if ( ! result . commitMessage ) {
127+ throw new KnownError ( 'No commit message was generated by the agent. Try again.' ) ;
128+ }
129+
130+ // Use the agent-specific review and revision flow
131+ const reviewResult = await agentStreamingReviewAndRevise ( {
132+ aiAgentService,
133+ promptUI,
134+ message : result . commitMessage ,
135+ body : result . body || '' ,
136+ } ) ;
137+
138+ if ( ! reviewResult ?. accepted ) {
139+ return ;
140+ }
141+
142+ const message = reviewResult . message ?? '' ;
143+ const body = reviewResult . body ?? '' ;
144+
145+ const fullMessage = `${ message } \n\n${ body } ` . trim ( ) ;
146+ await gitService . commitChanges ( fullMessage ) ;
147+
148+ promptUI . outro ( `${ green ( '✔' ) } Successfully committed with AI agent` ) ;
149+ } catch ( error ) {
150+ analyzeSpinner . stop ( 'Agent analysis failed' ) ;
151+ throw error ;
152+ }
153+ }
154+
155+ const handleSplitMode = async (
156+ aiCommitSplittingService : AICommitSplittingService ,
157+ aiCommitMessageService : AICommitMessageService ,
158+ gitService : GitService ,
159+ promptUI : ClackPromptService ,
160+ ) : Promise < void > => {
161+ // Check if we have staged changes
162+ const hasStagedChanges = await gitService . hasStagedChanges ( ) ;
163+ if ( ! hasStagedChanges ) {
164+ throw new KnownError (
165+ trimLines ( `
166+ No staged changes found. Stage your changes manually, or automatically stage all changes with the \`--stage-all\` flag.
167+ ` ) ,
168+ ) ;
169+ }
170+
171+ const result = await handleCommitSplitting ( {
172+ aiCommitSplittingService,
173+ aiCommitMessageService,
174+ gitService,
175+ promptUI,
176+ } ) ;
177+
178+ if ( result . accepted && result . commitCount && result . commitCount > 0 ) {
179+ promptUI . outro (
180+ `${ green ( '✔' ) } Successfully created ${ result . commitCount } commit${ result . commitCount > 1 ? 's' : '' } using AI-guided splitting` ,
181+ ) ;
182+ } else {
183+ promptUI . outro ( `${ red ( '✖' ) } No commits were created` ) ;
184+ }
185+ } ;
186+
6187export const agentCommand = new Command ( 'agent' )
7188 . description ( 'Enable AI agent mode for autonomous repository analysis' )
8189 . addOption ( new Option ( '--api-key <apiKey>' , 'API key for the AI provider' ) )
@@ -16,8 +197,7 @@ export const agentCommand = new Command('agent')
16197 . addOption ( new Option ( '--stage-all' , 'Stage all modified files before generating commit' ) )
17198 . action ( async ( options ) => {
18199 container . bind ( CLI_ARGUMENTS ) . toConstantValue ( options ) ;
19- await aiCommits ( {
20- agentMode : true ,
200+ await aiCommitsAgent ( {
21201 container,
22202 profile : options . profile ,
23203 splitMode : options . split ,
0 commit comments