@@ -49,6 +49,190 @@ export const defaultCommitMessageGitContextSettings: Required<CommitMessageGitCo
4949 recentCommitDiffCount : 1 ,
5050}
5151
52+ export const DEFAULT_COMMIT_MESSAGE_ATTRIBUTION_TEMPLATE = "Assisted-by: ${agentName}:${providerModel} [${toolName}]"
53+
54+ export const commitMessageAttributionSchema = z . object ( {
55+ enabled : z . boolean ( ) . optional ( ) ,
56+ template : z . string ( ) . optional ( ) ,
57+ } )
58+
59+ export type CommitMessageAttributionSettings = z . infer < typeof commitMessageAttributionSchema >
60+
61+ export const defaultCommitMessageAttributionSettings : Required < CommitMessageAttributionSettings > = {
62+ enabled : false ,
63+ template : DEFAULT_COMMIT_MESSAGE_ATTRIBUTION_TEMPLATE ,
64+ }
65+
66+ export const MAX_COMMIT_MESSAGE_PROFILES = 5
67+ export const DEFAULT_COMMIT_MESSAGE_PROFILE_ID = "default"
68+
69+ export const commitMessageProfileSchema = z . object ( {
70+ id : z . string ( ) . optional ( ) ,
71+ name : z . string ( ) . optional ( ) ,
72+ prompt : z . string ( ) . optional ( ) ,
73+ apiConfigId : z . string ( ) . optional ( ) ,
74+ gitContext : commitMessageGitContextSchema . optional ( ) ,
75+ attribution : commitMessageAttributionSchema . optional ( ) ,
76+ } )
77+
78+ export const commitMessageProfilesSchema = z . object ( {
79+ activeProfileId : z . string ( ) . optional ( ) ,
80+ profiles : z . array ( commitMessageProfileSchema ) . max ( MAX_COMMIT_MESSAGE_PROFILES ) . optional ( ) ,
81+ } )
82+
83+ export type CommitMessageProfileSettings = z . infer < typeof commitMessageProfileSchema >
84+ export type CommitMessageProfilesSettings = z . infer < typeof commitMessageProfilesSchema >
85+
86+ export type NormalizedCommitMessageProfile = Omit <
87+ CommitMessageProfileSettings ,
88+ "id" | "name" | "gitContext" | "attribution"
89+ > & {
90+ id : string
91+ name : string
92+ gitContext : Required < CommitMessageGitContextSettings >
93+ attribution : Required < CommitMessageAttributionSettings >
94+ }
95+
96+ export interface NormalizedCommitMessageProfiles {
97+ activeProfileId : string
98+ profiles : NormalizedCommitMessageProfile [ ]
99+ }
100+
101+ export interface CommitMessageProfileFallbackSettings {
102+ prompt ?: string
103+ apiConfigId ?: string
104+ gitContext ?: CommitMessageGitContextSettings
105+ attribution ?: CommitMessageAttributionSettings
106+ }
107+
108+ export function normalizeCommitMessageGitContextSettings (
109+ settings ?: CommitMessageGitContextSettings ,
110+ ) : Required < CommitMessageGitContextSettings > {
111+ return {
112+ ...defaultCommitMessageGitContextSettings ,
113+ ...settings ,
114+ diffContextLines : clampNumberSetting (
115+ settings ?. diffContextLines ,
116+ 0 ,
117+ 20 ,
118+ defaultCommitMessageGitContextSettings . diffContextLines ,
119+ ) ,
120+ recentCommitCount : clampNumberSetting (
121+ settings ?. recentCommitCount ,
122+ 1 ,
123+ 20 ,
124+ defaultCommitMessageGitContextSettings . recentCommitCount ,
125+ ) ,
126+ recentCommitDiffCount : clampNumberSetting (
127+ settings ?. recentCommitDiffCount ,
128+ 1 ,
129+ 5 ,
130+ defaultCommitMessageGitContextSettings . recentCommitDiffCount ,
131+ ) ,
132+ }
133+ }
134+
135+ export function normalizeCommitMessageAttributionSettings (
136+ settings ?: CommitMessageAttributionSettings ,
137+ ) : Required < CommitMessageAttributionSettings > {
138+ return {
139+ ...defaultCommitMessageAttributionSettings ,
140+ ...settings ,
141+ template : normalizeOptionalString ( settings ?. template ) ?? defaultCommitMessageAttributionSettings . template ,
142+ }
143+ }
144+
145+ export function normalizeCommitMessageProfiles (
146+ settings ?: CommitMessageProfilesSettings ,
147+ fallback : CommitMessageProfileFallbackSettings = { } ,
148+ ) : NormalizedCommitMessageProfiles {
149+ const sourceProfiles = settings ?. profiles ?. length
150+ ? settings . profiles . slice ( 0 , MAX_COMMIT_MESSAGE_PROFILES )
151+ : [
152+ {
153+ id : DEFAULT_COMMIT_MESSAGE_PROFILE_ID ,
154+ name : "Default" ,
155+ prompt : fallback . prompt ,
156+ apiConfigId : fallback . apiConfigId ,
157+ gitContext : fallback . gitContext ,
158+ attribution : fallback . attribution ,
159+ } ,
160+ ]
161+
162+ const profiles : NormalizedCommitMessageProfile [ ] = sourceProfiles . map ( ( profile , index ) => ( {
163+ id : normalizeProfileId ( profile . id , index ) ,
164+ name : normalizeProfileName ( profile . name , index ) ,
165+ prompt : profile . prompt ,
166+ apiConfigId : normalizeOptionalString ( profile . apiConfigId ) ,
167+ gitContext : normalizeCommitMessageGitContextSettings ( profile . gitContext ) ,
168+ attribution : normalizeCommitMessageAttributionSettings ( profile . attribution ) ,
169+ } ) )
170+ const firstProfile = profiles [ 0 ] !
171+
172+ const activeProfileId = profiles . some ( ( profile ) => profile . id === settings ?. activeProfileId )
173+ ? settings ! . activeProfileId !
174+ : firstProfile . id
175+
176+ return {
177+ activeProfileId,
178+ profiles,
179+ }
180+ }
181+
182+ export function getActiveCommitMessageProfile (
183+ settings ?: CommitMessageProfilesSettings ,
184+ fallback ?: CommitMessageProfileFallbackSettings ,
185+ ) : NormalizedCommitMessageProfile {
186+ const normalized = normalizeCommitMessageProfiles ( settings , fallback )
187+ return normalized . profiles . find ( ( profile ) => profile . id === normalized . activeProfileId ) ?? normalized . profiles [ 0 ] !
188+ }
189+
190+ export function createCommitMessageProfileId ( ) : string {
191+ return `profile-${ Date . now ( ) . toString ( 36 ) } -${ Math . random ( ) . toString ( 36 ) . slice ( 2 , 8 ) } `
192+ }
193+
194+ export function createCommitMessageProfileName ( profiles : Array < { name ?: string } > ) : string {
195+ for ( let index = profiles . length + 1 ; index <= MAX_COMMIT_MESSAGE_PROFILES + 1 ; index ++ ) {
196+ const candidate = `Profile ${ index } `
197+ if ( ! profiles . some ( ( profile ) => profile . name === candidate ) ) {
198+ return candidate
199+ }
200+ }
201+
202+ return `Profile ${ profiles . length + 1 } `
203+ }
204+
205+ function normalizeProfileId ( id : string | undefined , index : number ) : string {
206+ const normalized = normalizeOptionalString ( id )
207+ if ( normalized ) {
208+ return normalized
209+ }
210+
211+ return index === 0 ? DEFAULT_COMMIT_MESSAGE_PROFILE_ID : `profile-${ index + 1 } `
212+ }
213+
214+ function normalizeProfileName ( name : string | undefined , index : number ) : string {
215+ const normalized = normalizeOptionalString ( name )
216+ return normalized || ( index === 0 ? "Default" : `Profile ${ index + 1 } ` )
217+ }
218+
219+ function normalizeOptionalString ( value : string | undefined ) : string | undefined {
220+ if ( typeof value !== "string" ) {
221+ return undefined
222+ }
223+
224+ const trimmed = value . trim ( )
225+ return trimmed . length > 0 ? trimmed : undefined
226+ }
227+
228+ function clampNumberSetting ( value : number | undefined , min : number , max : number , fallback : number ) : number {
229+ if ( typeof value !== "number" || ! Number . isFinite ( value ) ) {
230+ return fallback
231+ }
232+
233+ return Math . min ( Math . max ( Math . trunc ( value ) , min ) , max )
234+ }
235+
52236/**
53237 * Terminal output preview size options for persisted command output.
54238 *
@@ -261,6 +445,8 @@ export const globalSettingsSchema = z.object({
261445
262446 commitMessageApiConfigId : z . string ( ) . optional ( ) ,
263447 commitMessageGitContext : commitMessageGitContextSchema . optional ( ) ,
448+ commitMessageAttribution : commitMessageAttributionSchema . optional ( ) ,
449+ commitMessageProfiles : commitMessageProfilesSchema . optional ( ) ,
264450} )
265451
266452export type GlobalSettings = z . infer < typeof globalSettingsSchema >
0 commit comments