@@ -1951,18 +1951,26 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => {
19511951 } ) ,
19521952 ) ;
19531953
1954- it . effect ( "preserves repository conventions style when recent history is empty" , ( ) =>
1954+ it . effect ( "includes local agent instructions when recent history is empty" , ( ) =>
19551955 Effect . gen ( function * ( ) {
19561956 const repoDir = yield * makeTempDir ( "t3code-git-manager-" ) ;
19571957 yield * runGit ( repoDir , [ "init" , "--initial-branch=main" ] ) ;
19581958 yield * runGit ( repoDir , [ "config" , "user.email" , "test@example.com" ] ) ;
19591959 yield * runGit ( repoDir , [ "config" , "user.name" , "Test User" ] ) ;
1960+ const agentInstructions = "Use lowercase source control text." ;
1961+ const claudeInstructions = "Keep pull request bodies brief." ;
1962+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "AGENTS.md" ) , agentInstructions ) ;
1963+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "CLAUDE.md" ) , claudeInstructions ) ;
19601964 NodeFS . writeFileSync ( NodePath . join ( repoDir , "README.md" ) , "hello\n" ) ;
19611965 yield * runGit ( repoDir , [ "add" , "README.md" ] ) ;
19621966 let generatedPolicy : TextGeneration . CommitMessageGenerationInput [ "policy" ] = undefined ;
19631967
19641968 const { manager } = yield * makeManager ( {
19651969 serverSettings : {
1970+ textGenerationModelSelection : {
1971+ instanceId : ProviderInstanceId . make ( "claudeAgent" ) ,
1972+ model : "claude-sonnet-4-6" ,
1973+ } ,
19661974 sourceControlWritingStyle : {
19671975 mode : "repo_conventions" as const ,
19681976 } ,
@@ -1979,6 +1987,42 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => {
19791987 action : "commit" ,
19801988 } ) ;
19811989
1990+ expect ( generatedPolicy ) . toEqual ( {
1991+ kind : "repo_conventions" ,
1992+ commitInstructions : `Follow the repository's established commit message style when examples are available.\n\nLocal AGENTS.md:\n${ agentInstructions } \n\nLocal CLAUDE.md:\n${ claudeInstructions } ` ,
1993+ changeRequestInstructions : `Follow the repository's established change request title and body style when examples are available.\n\nLocal AGENTS.md:\n${ agentInstructions } \n\nLocal CLAUDE.md:\n${ claudeInstructions } ` ,
1994+ inferRepositoryConventions : true ,
1995+ } ) ;
1996+ } ) ,
1997+ ) ;
1998+
1999+ it . effect ( "leaves the policy unmodified when the repository offers no examples" , ( ) =>
2000+ Effect . gen ( function * ( ) {
2001+ const repoDir = yield * makeTempDir ( "t3code-git-manager-" ) ;
2002+ yield * runGit ( repoDir , [ "init" , "--initial-branch=main" ] ) ;
2003+ yield * runGit ( repoDir , [ "config" , "user.email" , "test@example.com" ] ) ;
2004+ yield * runGit ( repoDir , [ "config" , "user.name" , "Test User" ] ) ;
2005+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "README.md" ) , "hello\n" ) ;
2006+ yield * runGit ( repoDir , [ "add" , "README.md" ] ) ;
2007+ let generatedPolicy : TextGeneration . CommitMessageGenerationInput [ "policy" ] = undefined ;
2008+
2009+ const { manager } = yield * makeManager ( {
2010+ serverSettings : {
2011+ textGenerationModelSelection : {
2012+ instanceId : ProviderInstanceId . make ( "claudeAgent" ) ,
2013+ model : "claude-sonnet-4-6" ,
2014+ } ,
2015+ sourceControlWritingStyle : { mode : "repo_conventions" as const } ,
2016+ } ,
2017+ textGeneration : {
2018+ generateCommitMessage : ( input ) => {
2019+ generatedPolicy = input . policy ;
2020+ return Effect . succeed ( { subject : "Create initial commit" , body : "" } ) ;
2021+ } ,
2022+ } ,
2023+ } ) ;
2024+ yield * runStackedAction ( manager , { cwd : repoDir , action : "commit" } ) ;
2025+
19822026 expect ( generatedPolicy ) . toEqual ( {
19832027 kind : "repo_conventions" ,
19842028 commitInstructions :
@@ -1990,6 +2034,91 @@ it.layer(GitManagerTestLayer)("GitManager", (it) => {
19902034 } ) ,
19912035 ) ;
19922036
2037+ it . effect ( "truncates oversized instructions instead of dropping them" , ( ) =>
2038+ Effect . gen ( function * ( ) {
2039+ const repoDir = yield * makeTempDir ( "t3code-git-manager-" ) ;
2040+ yield * runGit ( repoDir , [ "init" , "--initial-branch=main" ] ) ;
2041+ yield * runGit ( repoDir , [ "config" , "user.email" , "test@example.com" ] ) ;
2042+ yield * runGit ( repoDir , [ "config" , "user.name" , "Test User" ] ) ;
2043+ // This repository's own AGENTS.md is past 20 KB, which is what made the
2044+ // original drop-on-oversize guard a silent no-op.
2045+ const oversized = `Use lowercase source control text.\n${ "x" . repeat ( 30_000 ) } ` ;
2046+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "AGENTS.md" ) , oversized ) ;
2047+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "README.md" ) , "hello\n" ) ;
2048+ yield * runGit ( repoDir , [ "add" , "README.md" ] ) ;
2049+ let generatedPolicy : TextGeneration . CommitMessageGenerationInput [ "policy" ] = undefined ;
2050+
2051+ const { manager } = yield * makeManager ( {
2052+ serverSettings : {
2053+ textGenerationModelSelection : {
2054+ instanceId : ProviderInstanceId . make ( "claudeAgent" ) ,
2055+ model : "claude-sonnet-4-6" ,
2056+ } ,
2057+ sourceControlWritingStyle : { mode : "repo_conventions" as const } ,
2058+ } ,
2059+ textGeneration : {
2060+ generateCommitMessage : ( input ) => {
2061+ generatedPolicy = input . policy ;
2062+ return Effect . succeed ( { subject : "Create initial commit" , body : "" } ) ;
2063+ } ,
2064+ } ,
2065+ } ) ;
2066+ yield * runStackedAction ( manager , { cwd : repoDir , action : "commit" } ) ;
2067+
2068+ expect ( generatedPolicy ) . toMatchObject ( {
2069+ commitInstructions : expect . stringContaining ( "Use lowercase source control text." ) ,
2070+ } ) ;
2071+ expect ( generatedPolicy ) . toMatchObject ( {
2072+ commitInstructions : expect . stringContaining ( "[Truncated]" ) ,
2073+ } ) ;
2074+ } ) ,
2075+ ) ;
2076+
2077+ it . effect ( "skips a CLAUDE.md that only imports another file" , ( ) =>
2078+ Effect . gen ( function * ( ) {
2079+ const repoDir = yield * makeTempDir ( "t3code-git-manager-" ) ;
2080+ yield * runGit ( repoDir , [ "init" , "--initial-branch=main" ] ) ;
2081+ yield * runGit ( repoDir , [ "config" , "user.email" , "test@example.com" ] ) ;
2082+ yield * runGit ( repoDir , [ "config" , "user.name" , "Test User" ] ) ;
2083+ NodeFS . writeFileSync (
2084+ NodePath . join ( repoDir , "AGENTS.md" ) ,
2085+ "Use lowercase source control text." ,
2086+ ) ;
2087+ // Exactly this repository's CLAUDE.md.
2088+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "CLAUDE.md" ) , "@AGENTS.md\n" ) ;
2089+ NodeFS . writeFileSync ( NodePath . join ( repoDir , "README.md" ) , "hello\n" ) ;
2090+ yield * runGit ( repoDir , [ "add" , "README.md" ] ) ;
2091+ let generatedPolicy : TextGeneration . CommitMessageGenerationInput [ "policy" ] = undefined ;
2092+
2093+ const { manager } = yield * makeManager ( {
2094+ serverSettings : {
2095+ textGenerationModelSelection : {
2096+ instanceId : ProviderInstanceId . make ( "claudeAgent" ) ,
2097+ model : "claude-sonnet-4-6" ,
2098+ } ,
2099+ sourceControlWritingStyle : { mode : "repo_conventions" as const } ,
2100+ } ,
2101+ textGeneration : {
2102+ generateCommitMessage : ( input ) => {
2103+ generatedPolicy = input . policy ;
2104+ return Effect . succeed ( { subject : "Create initial commit" , body : "" } ) ;
2105+ } ,
2106+ } ,
2107+ } ) ;
2108+ yield * runStackedAction ( manager , { cwd : repoDir , action : "commit" } ) ;
2109+
2110+ expect ( generatedPolicy ) . toMatchObject ( {
2111+ commitInstructions : expect . stringContaining ( "Local AGENTS.md:" ) ,
2112+ } ) ;
2113+ expect ( generatedPolicy ) . toMatchObject ( {
2114+ commitInstructions : expect . not . stringContaining ( "Local CLAUDE.md:" ) ,
2115+ } ) ;
2116+ expect ( generatedPolicy ) . toMatchObject ( {
2117+ commitInstructions : expect . not . stringContaining ( "@AGENTS.md" ) ,
2118+ } ) ;
2119+ } ) ,
2120+ ) ;
2121+
19932122 it . effect ( "uses custom commit message when provided" , ( ) =>
19942123 Effect . gen ( function * ( ) {
19952124 const repoDir = yield * makeTempDir ( "t3code-git-manager-" ) ;
0 commit comments