@@ -9,6 +9,7 @@ import ChatInterface from "./ui/components/chat-interface";
99import * as fs from "fs" ;
1010import * as path from "path" ;
1111import * as os from "os" ;
12+ import { ConfirmationService } from "./utils/confirmation-service" ;
1213
1314// Load environment variables
1415dotenv . config ( ) ;
@@ -17,48 +18,115 @@ dotenv.config();
1718function loadApiKey ( ) : string | undefined {
1819 // First check environment variables
1920 let apiKey = process . env . GROK_API_KEY ;
20-
21+
2122 if ( ! apiKey ) {
2223 // Try to load from user settings file
2324 try {
2425 const homeDir = os . homedir ( ) ;
25- const settingsFile = path . join ( homeDir , ' .grok' , ' user-settings.json' ) ;
26-
26+ const settingsFile = path . join ( homeDir , " .grok" , " user-settings.json" ) ;
27+
2728 if ( fs . existsSync ( settingsFile ) ) {
28- const settings = JSON . parse ( fs . readFileSync ( settingsFile , ' utf8' ) ) ;
29+ const settings = JSON . parse ( fs . readFileSync ( settingsFile , " utf8" ) ) ;
2930 apiKey = settings . apiKey ;
3031 }
3132 } catch ( error ) {
3233 // Ignore errors, apiKey will remain undefined
3334 }
3435 }
35-
36+
3637 return apiKey ;
3738}
3839
3940// Load base URL from user settings if not in environment
4041function loadBaseURL ( ) : string | undefined {
4142 // First check environment variables
4243 let baseURL = process . env . GROK_BASE_URL ;
43-
44+
4445 if ( ! baseURL ) {
4546 // Try to load from user settings file
4647 try {
4748 const homeDir = os . homedir ( ) ;
48- const settingsFile = path . join ( homeDir , ' .grok' , ' user-settings.json' ) ;
49-
49+ const settingsFile = path . join ( homeDir , " .grok" , " user-settings.json" ) ;
50+
5051 if ( fs . existsSync ( settingsFile ) ) {
51- const settings = JSON . parse ( fs . readFileSync ( settingsFile , ' utf8' ) ) ;
52+ const settings = JSON . parse ( fs . readFileSync ( settingsFile , " utf8" ) ) ;
5253 baseURL = settings . baseURL ;
5354 }
5455 } catch ( error ) {
5556 // Ignore errors, baseURL will remain undefined
5657 }
5758 }
58-
59+
5960 return baseURL ;
6061}
6162
63+ // Headless mode processing function
64+ async function processPromptHeadless (
65+ prompt : string ,
66+ apiKey : string ,
67+ baseURL ?: string ,
68+ model ?: string
69+ ) : Promise < void > {
70+ try {
71+ const agent = new GrokAgent ( apiKey , baseURL , model ) ;
72+
73+ // Configure confirmation service for headless mode (auto-approve all operations)
74+ const confirmationService = ConfirmationService . getInstance ( ) ;
75+ confirmationService . setSessionFlag ( "allOperations" , true ) ;
76+
77+ console . log ( "🤖 Processing prompt...\n" ) ;
78+
79+ // Process the user message
80+ const chatEntries = await agent . processUserMessage ( prompt ) ;
81+
82+ // Output the results
83+ for ( const entry of chatEntries ) {
84+ switch ( entry . type ) {
85+ case "user" :
86+ console . log ( `> ${ entry . content } \n` ) ;
87+ break ;
88+
89+ case "assistant" :
90+ if ( entry . content . trim ( ) ) {
91+ console . log ( entry . content . trim ( ) ) ;
92+ console . log ( ) ;
93+ }
94+ break ;
95+
96+ case "tool_result" :
97+ const toolName = entry . toolCall ?. function ?. name || "unknown" ;
98+ const getFilePath = ( toolCall : any ) => {
99+ if ( toolCall ?. function ?. arguments ) {
100+ try {
101+ const args = JSON . parse ( toolCall . function . arguments ) ;
102+ if ( toolCall . function . name === "search" ) {
103+ return args . query ;
104+ }
105+ return args . path || args . file_path || args . command || "" ;
106+ } catch {
107+ return "" ;
108+ }
109+ }
110+ return "" ;
111+ } ;
112+
113+ const filePath = getFilePath ( entry . toolCall ) ;
114+ const toolDisplay = filePath ? `${ toolName } (${ filePath } )` : toolName ;
115+
116+ if ( entry . toolResult ?. success ) {
117+ console . log ( `✅ ${ toolDisplay } : ${ entry . content . split ( "\n" ) [ 0 ] } ` ) ;
118+ } else {
119+ console . log ( `❌ ${ toolDisplay } : ${ entry . content } ` ) ;
120+ }
121+ break ;
122+ }
123+ }
124+ } catch ( error : any ) {
125+ console . error ( "❌ Error processing prompt :", error . message ) ;
126+ process . exit ( 1 ) ;
127+ }
128+ }
129+
62130program
63131 . name ( "grok" )
64132 . description (
@@ -67,9 +135,19 @@ program
67135 . version ( "1.0.0" )
68136 . option ( "-d, --directory <dir>" , "set working directory" , process . cwd ( ) )
69137 . option ( "-k, --api-key <key>" , "Grok API key (or set GROK_API_KEY env var)" )
70- . option ( "-u, --base-url <url>" , "Grok API base URL (or set GROK_BASE_URL env var)" )
71- . option ( "-m, --model <model>" , "AI model to use (e.g., gemini-2.5-pro, grok-4-latest)" )
72- . action ( ( options ) => {
138+ . option (
139+ "-u, --base-url <url>" ,
140+ "Grok API base URL (or set GROK_BASE_URL env var)"
141+ )
142+ . option (
143+ "-m, --model <model>" ,
144+ "AI model to use (e.g., gemini-2.5-pro, grok-4-latest)"
145+ )
146+ . option (
147+ "-p, --prompt <prompt>" ,
148+ "process a single prompt and exit (headless mode)"
149+ )
150+ . action ( async ( options ) => {
73151 if ( options . directory ) {
74152 try {
75153 process . chdir ( options . directory ) ;
@@ -87,10 +165,23 @@ program
87165 const apiKey = options . apiKey || loadApiKey ( ) ;
88166 const baseURL = options . baseUrl || loadBaseURL ( ) ;
89167 const model = options . model ;
90- const agent = apiKey ? new GrokAgent ( apiKey , baseURL , model ) : undefined ;
91168
92- console . log ( "🤖 Starting Grok CLI Conversational Assistant...\n" ) ;
169+ if ( ! apiKey ) {
170+ console . error (
171+ "❌ Error: API key required. Set GROK_API_KEY environment variable, use --api-key flag, or save to ~/.grok/user-settings.json"
172+ ) ;
173+ process . exit ( 1 ) ;
174+ }
93175
176+ // Headless mode: process prompt and exit
177+ if ( options . prompt ) {
178+ await processPromptHeadless ( options . prompt , apiKey , baseURL , model ) ;
179+ return ;
180+ }
181+
182+ // Interactive mode: launch UI
183+ const agent = new GrokAgent ( apiKey , baseURL , model ) ;
184+ console . log ( "🤖 Starting Grok CLI Conversational Assistant...\n" ) ;
94185 render ( React . createElement ( ChatInterface , { agent } ) ) ;
95186 } catch ( error : any ) {
96187 console . error ( "❌ Error initializing Grok CLI:" , error . message ) ;
0 commit comments