@@ -42,19 +42,23 @@ const openInEditor = (
4242 }
4343} ;
4444
45- export const streamingReviewAndRevise = async ( {
46- aiCommitMessageService,
47- promptUI,
48- message,
49- body,
50- diff,
51- } : {
52- aiCommitMessageService : AICommitMessageService ;
53- promptUI : ClackPromptService ;
54- message : string ;
55- body : string ;
56- diff : string ;
57- } ) : Promise < { accepted : boolean ; message ?: string ; body ?: string } > => {
45+ interface RevisionConfig {
46+ reviseLabel : string ;
47+ promptMessage : string ;
48+ promptPlaceholder : string ;
49+ revise : (
50+ userPrompt : string ,
51+ currentMessage : string ,
52+ currentBody : string ,
53+ ) => Promise < { message : string ; body : string } > ;
54+ }
55+
56+ const reviewAndRevise = async (
57+ promptUI : ClackPromptService ,
58+ message : string ,
59+ body : string ,
60+ config : RevisionConfig ,
61+ ) : Promise < { accepted : boolean ; message ?: string ; body ?: string } > => {
5862 let currentMessage = message ;
5963 let currentBody = body ;
6064
@@ -65,7 +69,7 @@ export const streamingReviewAndRevise = async ({
6569 ) } \n\n${ cyan ( currentBody ) } \n\nWhat would you like to do?`,
6670 options : [
6771 { label : 'Accept and commit' , value : 'accept' } ,
68- { label : 'Revise with a prompt' , value : 'revise' } ,
72+ { label : config . reviseLabel , value : 'revise' } ,
6973 { label : 'Edit in $EDITOR' , value : 'edit' } ,
7074 { label : 'Cancel' , value : 'cancel' } ,
7175 ] ,
@@ -78,21 +82,80 @@ export const streamingReviewAndRevise = async ({
7882 return { accepted : false } ;
7983 } else if ( confirmed === 'revise' ) {
8084 const userPrompt = await promptUI . text ( {
81- message :
82- 'Describe how you want to revise the commit message (e.g. "make it more descriptive", "use imperative mood", etc):' ,
83- placeholder : 'Enter revision prompt' ,
85+ message : config . promptMessage ,
86+ placeholder : config . promptPlaceholder ,
8487 } ) ;
8588 if ( ! userPrompt || promptUI . isCancel ( userPrompt ) ) {
8689 promptUI . outro ( 'Commit cancelled' ) ;
8790 return { accepted : false } ;
8891 }
8992
93+ try {
94+ const result = await config . revise ( userPrompt , currentMessage , currentBody ) ;
95+ currentMessage = result . message ;
96+ currentBody = result . body ;
97+ } catch ( error ) {
98+ promptUI . outro ( `Failed to revise: ${ error instanceof Error ? error . message : 'Unknown error' } ` ) ;
99+ return { accepted : false } ;
100+ }
101+ } else if ( confirmed === 'edit' ) {
102+ const result = handleEditorRevision ( promptUI , currentMessage , currentBody ) ;
103+ if ( ! result ) {
104+ return { accepted : false } ;
105+ }
106+ currentMessage = result . message ;
107+ currentBody = result . body ;
108+ }
109+ }
110+ promptUI . outro ( 'Too many revisions requested, commit cancelled.' ) ;
111+ return { accepted : false } ;
112+ } ;
113+
114+ const handleEditorRevision = (
115+ promptUI : ClackPromptService ,
116+ currentMessage : string ,
117+ currentBody : string ,
118+ ) : { message : string ; body : string } | null => {
119+ const initial = `${ currentMessage } \n\n${ currentBody } ` . trim ( ) ;
120+ const edited = openInEditor ( initial , promptUI ) ;
121+ if ( edited === null ) {
122+ promptUI . outro ( 'Commit cancelled' ) ;
123+ return null ;
124+ }
125+ // Split edited message into subject and body (first line = subject, rest = body)
126+ const [ firstLine , ...rest ] = edited . split ( '\n' ) ;
127+ return {
128+ message : firstLine . trim ( ) ,
129+ body : rest . join ( '\n' ) . trim ( ) ,
130+ } ;
131+ } ;
132+
133+ export const streamingReviewAndRevise = async ( {
134+ aiCommitMessageService,
135+ promptUI,
136+ message,
137+ body,
138+ diff,
139+ } : {
140+ aiCommitMessageService : AICommitMessageService ;
141+ promptUI : ClackPromptService ;
142+ message : string ;
143+ body : string ;
144+ diff : string ;
145+ } ) : Promise < { accepted : boolean ; message ?: string ; body ?: string } > => {
146+ const config : RevisionConfig = {
147+ reviseLabel : 'Revise with a prompt' ,
148+ promptMessage :
149+ 'Describe how you want to revise the commit message (e.g. "make it more descriptive", "use imperative mood", etc):' ,
150+ promptPlaceholder : 'Enter revision prompt' ,
151+ revise : async ( userPrompt : string ) => {
90152 const reviseSpinner = promptUI . spinner ( ) ;
91153 reviseSpinner . start ( 'The AI is revising your commit message' ) ;
92154
93155 let messageBuffer = '' ;
156+ let updatedMessage = '' ;
157+ let updatedBody = '' ;
94158
95- // Use streaming to show revision in real-time
96159 await aiCommitMessageService . reviseStreamingCommitMessage ( {
97160 diff,
98161 userPrompt,
@@ -105,36 +168,27 @@ export const streamingReviewAndRevise = async ({
105168 onBodyUpdate : ( ) => {
106169 // Don't show body updates in real-time
107170 } ,
108- onComplete : ( updatedMessage , updatedBody ) => {
109- currentMessage = updatedMessage ;
110- currentBody = updatedBody ;
171+ onComplete : ( message , body ) => {
172+ updatedMessage = message ;
173+ updatedBody = body ;
111174 reviseSpinner . stop ( 'Revision complete' ) ;
112175
113176 // Display the updated message and body
114177 promptUI . log . step ( 'Updated commit message:' ) ;
115- promptUI . log . message ( green ( updatedMessage ) ) ;
178+ promptUI . log . message ( green ( message ) ) ;
116179
117- if ( updatedBody ) {
180+ if ( body ) {
118181 promptUI . log . step ( 'Updated commit body:' ) ;
119- promptUI . log . message ( updatedBody ) ;
182+ promptUI . log . message ( body ) ;
120183 }
121184 } ,
122185 } ) ;
123- } else if ( confirmed === 'edit' ) {
124- const initial = `${ currentMessage } \n\n${ currentBody } ` . trim ( ) ;
125- const edited = openInEditor ( initial , promptUI ) ;
126- if ( edited === null ) {
127- promptUI . outro ( 'Commit cancelled' ) ;
128- return { accepted : false } ;
129- }
130- // Split edited message into subject and body (first line = subject, rest = body)
131- const [ firstLine , ...rest ] = edited . split ( '\n' ) ;
132- currentMessage = firstLine . trim ( ) ;
133- currentBody = rest . join ( '\n' ) . trim ( ) ;
134- }
135- }
136- promptUI . outro ( 'Too many revisions requested, commit cancelled.' ) ;
137- return { accepted : false } ;
186+
187+ return { message : updatedMessage , body : updatedBody } ;
188+ } ,
189+ } ;
190+
191+ return reviewAndRevise ( promptUI , message , body , config ) ;
138192} ;
139193
140194export const agentStreamingReviewAndRevise = async ( {
@@ -148,81 +202,35 @@ export const agentStreamingReviewAndRevise = async ({
148202 message : string ;
149203 body : string ;
150204} ) : Promise < { accepted : boolean ; message ?: string ; body ?: string } > => {
151- let currentMessage = message ;
152- let currentBody = body ;
205+ const config : RevisionConfig = {
206+ reviseLabel : 'Revise with AI agent' ,
207+ promptMessage :
208+ 'Describe how you want the AI agent to revise the commit message (e.g. "make it more descriptive", "use imperative mood", "check related files for context"):' ,
209+ promptPlaceholder : 'Enter revision prompt for the AI agent' ,
210+ revise : async ( userPrompt : string , currentMessage : string , currentBody : string ) => {
211+ const reviseSpinner = promptUI . spinner ( ) ;
212+ reviseSpinner . start ( 'AI agent is revising your commit message...' ) ;
153213
154- for ( let i = 0 ; i < 10 ; i ++ ) {
155- const confirmed = await promptUI . select ( {
156- message : `Proposed commit message:\n\n${ cyan (
214+ const result = await aiAgentService . reviseCommitWithAgent ( {
157215 currentMessage,
158- ) } \n\n${ cyan ( currentBody ) } \n\nWhat would you like to do?`,
159- options : [
160- { label : 'Accept and commit' , value : 'accept' } ,
161- { label : 'Revise with AI agent' , value : 'revise' } ,
162- { label : 'Edit in $EDITOR' , value : 'edit' } ,
163- { label : 'Cancel' , value : 'cancel' } ,
164- ] ,
165- } ) ;
166-
167- if ( confirmed === 'accept' ) {
168- return { accepted : true , message : currentMessage , body : currentBody } ;
169- } else if ( confirmed === 'cancel' || promptUI . isCancel ( confirmed ) ) {
170- promptUI . outro ( 'Commit cancelled' ) ;
171- return { accepted : false } ;
172- } else if ( confirmed === 'revise' ) {
173- const userPrompt = await promptUI . text ( {
174- message :
175- 'Describe how you want the AI agent to revise the commit message (e.g. "make it more descriptive", "use imperative mood", "check related files for context"):' ,
176- placeholder : 'Enter revision prompt for the AI agent' ,
216+ currentBody,
217+ userRevisionPrompt : userPrompt ,
177218 } ) ;
178- if ( ! userPrompt || promptUI . isCancel ( userPrompt ) ) {
179- promptUI . outro ( 'Commit cancelled' ) ;
180- return { accepted : false } ;
181- }
182219
183- const reviseSpinner = promptUI . spinner ( ) ;
184- reviseSpinner . start ( 'AI agent is revising your commit message...' ) ;
185-
186- try {
187- const result = await aiAgentService . reviseCommitWithAgent ( {
188- currentMessage,
189- currentBody,
190- userRevisionPrompt : userPrompt ,
191- } ) ;
220+ reviseSpinner . stop ( 'Agent revision complete' ) ;
192221
193- reviseSpinner . stop ( 'Agent revision complete' ) ;
222+ // Display the updated message and body
223+ promptUI . log . step ( 'Agent-revised commit message:' ) ;
224+ promptUI . log . message ( green ( result . commitMessage ) ) ;
194225
195- currentMessage = result . commitMessage ;
196- currentBody = result . body ;
226+ if ( result . body ) {
227+ promptUI . log . step ( 'Agent-revised commit body:' ) ;
228+ promptUI . log . message ( result . body ) ;
229+ }
197230
198- // Display the updated message and body
199- promptUI . log . step ( 'Agent-revised commit message:' ) ;
200- promptUI . log . message ( green ( result . commitMessage ) ) ;
231+ return { message : result . commitMessage , body : result . body } ;
232+ } ,
233+ } ;
201234
202- if ( result . body ) {
203- promptUI . log . step ( 'Agent-revised commit body:' ) ;
204- promptUI . log . message ( result . body ) ;
205- }
206- } catch ( error ) {
207- reviseSpinner . stop ( 'Agent revision failed' ) ;
208- promptUI . outro (
209- `Failed to revise with agent: ${ error instanceof Error ? error . message : 'Unknown error' } ` ,
210- ) ;
211- return { accepted : false } ;
212- }
213- } else if ( confirmed === 'edit' ) {
214- const initial = `${ currentMessage } \n\n${ currentBody } ` . trim ( ) ;
215- const edited = openInEditor ( initial , promptUI ) ;
216- if ( edited === null ) {
217- promptUI . outro ( 'Commit cancelled' ) ;
218- return { accepted : false } ;
219- }
220- // Split edited message into subject and body (first line = subject, rest = body)
221- const [ firstLine , ...rest ] = edited . split ( '\n' ) ;
222- currentMessage = firstLine . trim ( ) ;
223- currentBody = rest . join ( '\n' ) . trim ( ) ;
224- }
225- }
226- promptUI . outro ( 'Too many revisions requested, commit cancelled.' ) ;
227- return { accepted : false } ;
235+ return reviewAndRevise ( promptUI , message , body , config ) ;
228236} ;
0 commit comments