@@ -3,7 +3,7 @@ import * as path from 'node:path';
33import { fileURLToPath } from 'node:url' ;
44import chalk from 'chalk' ;
55import { Command } from 'commander' ;
6- import { select , checkbox } from '@inquirer/prompts' ;
6+ import { select , checkbox , confirm } from '@inquirer/prompts' ;
77import { saveConfig , type LeanSpecConfig } from '../config.js' ;
88import {
99 detectExistingSystemPrompts ,
@@ -13,6 +13,9 @@ import {
1313 createAgentToolSymlinks ,
1414 AI_TOOL_CONFIGS ,
1515 getDefaultAIToolSelection ,
16+ getCliCapableDetectedTools ,
17+ executeMergeWithAI ,
18+ getDisplayCommand ,
1619 type AIToolKey ,
1720} from '../utils/template-helpers.js' ;
1821import {
@@ -26,6 +29,72 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
2629const TEMPLATES_DIR = path . join ( __dirname , '..' , 'templates' ) ;
2730const EXAMPLES_DIR = path . join ( TEMPLATES_DIR , 'examples' ) ;
2831
32+ /**
33+ * Attempt to auto-merge AGENTS.md using detected AI CLI tool
34+ * Returns true if merge was successfully completed
35+ */
36+ async function attemptAutoMerge ( cwd : string , promptPath : string , autoExecute : boolean ) : Promise < boolean > {
37+ // Check for CLI-capable AI tools
38+ const cliTools = await getCliCapableDetectedTools ( ) ;
39+
40+ if ( cliTools . length === 0 ) {
41+ // No CLI tools detected, fall back to manual instructions
42+ return false ;
43+ }
44+
45+ // Use first detected CLI-capable tool
46+ const tool = cliTools [ 0 ] ;
47+ const displayCmd = getDisplayCommand ( tool . tool , promptPath ) ;
48+
49+ console . log ( '' ) ;
50+ console . log ( chalk . cyan ( `🔍 Detected AI CLI: ${ tool . config . description } ` ) ) ;
51+ for ( const reason of tool . reasons ) {
52+ console . log ( chalk . gray ( ` └─ ${ reason } ` ) ) ;
53+ }
54+ console . log ( '' ) ;
55+ console . log ( chalk . gray ( `Command: ${ displayCmd } ` ) ) ;
56+ console . log ( '' ) ;
57+
58+ let shouldExecute = autoExecute ;
59+
60+ if ( ! autoExecute ) {
61+ shouldExecute = await confirm ( {
62+ message : 'Run merge automatically using detected AI CLI?' ,
63+ default : true ,
64+ } ) ;
65+ }
66+
67+ if ( ! shouldExecute ) {
68+ console . log ( chalk . gray ( 'Skipping auto-merge. Run the command above manually to merge.' ) ) ;
69+ return false ;
70+ }
71+
72+ console . log ( '' ) ;
73+ console . log ( chalk . cyan ( '🤖 Running AI-assisted merge...' ) ) ;
74+ console . log ( chalk . gray ( ' (This may take a moment)' ) ) ;
75+ console . log ( '' ) ;
76+
77+ const result = await executeMergeWithAI ( cwd , promptPath , tool . tool ) ;
78+
79+ if ( result . success ) {
80+ console . log ( '' ) ;
81+ console . log ( chalk . green ( '✓ AGENTS.md merged successfully!' ) ) ;
82+ console . log ( chalk . gray ( ' Review changes: git diff AGENTS.md' ) ) ;
83+ return true ;
84+ } else if ( result . timedOut ) {
85+ console . log ( '' ) ;
86+ console . log ( chalk . yellow ( '⚠ Merge timed out. Try running the command manually:' ) ) ;
87+ console . log ( chalk . gray ( ` ${ displayCmd } ` ) ) ;
88+ return false ;
89+ } else {
90+ console . log ( '' ) ;
91+ console . log ( chalk . yellow ( `⚠ Auto-merge encountered an issue: ${ result . error } ` ) ) ;
92+ console . log ( chalk . gray ( ' Try running the command manually:' ) ) ;
93+ console . log ( chalk . gray ( ` ${ displayCmd } ` ) ) ;
94+ return false ;
95+ }
96+ }
97+
2998/**
3099 * Init command - initialize LeanSpec in current directory
31100 */
@@ -307,6 +376,7 @@ export async function initProject(skipPrompts = false, templateOption?: string,
307376 // Check for existing system prompt files
308377 const existingFiles = await detectExistingSystemPrompts ( cwd ) ;
309378 let skipFiles : string [ ] = [ ] ;
379+ let mergeCompleted = false ;
310380
311381 if ( existingFiles . length > 0 ) {
312382 console . log ( '' ) ;
@@ -317,6 +387,10 @@ export async function initProject(skipPrompts = false, templateOption?: string,
317387 console . log ( chalk . gray ( 'Using AI-Assisted Merge for existing AGENTS.md' ) ) ;
318388 const projectName = await getProjectName ( cwd ) ;
319389 await handleExistingFiles ( 'merge-ai' , existingFiles , templateDir , cwd , { project_name : projectName } ) ;
390+
391+ // Auto-execute merge if CLI tool is available
392+ const promptPath = path . join ( cwd , '.lean-spec' , 'MERGE-AGENTS-PROMPT.md' ) ;
393+ mergeCompleted = await attemptAutoMerge ( cwd , promptPath , true /* skipPrompts */ ) ;
320394 } else {
321395 const action = await select < 'merge-ai' | 'merge-append' | 'overwrite' | 'skip' > ( {
322396 message : 'How would you like to handle existing AGENTS.md?' ,
@@ -351,15 +425,19 @@ export async function initProject(skipPrompts = false, templateOption?: string,
351425
352426 if ( action === 'skip' ) {
353427 skipFiles = existingFiles ;
428+ } else if ( action === 'merge-ai' ) {
429+ // Offer auto-merge if CLI tool is available
430+ const promptPath = path . join ( cwd , '.lean-spec' , 'MERGE-AGENTS-PROMPT.md' ) ;
431+ mergeCompleted = await attemptAutoMerge ( cwd , promptPath , false /* skipPrompts */ ) ;
354432 }
355433 }
356434 }
357435
358436 // Get project name for variable substitution
359437 const projectName = await getProjectName ( cwd ) ;
360438
361- // Copy AGENTS.md from template root to project root (unless skipping)
362- if ( ! skipFiles . includes ( 'AGENTS.md' ) ) {
439+ // Copy AGENTS.md from template root to project root (unless skipping or already merged )
440+ if ( ! skipFiles . includes ( 'AGENTS.md' ) && ! mergeCompleted ) {
363441 const agentsSourcePath = path . join ( templateDir , 'AGENTS.md' ) ;
364442 const agentsTargetPath = path . join ( cwd , 'AGENTS.md' ) ;
365443
0 commit comments