11#!/usr/bin/env node
2+
3+ const cliEntryPoint =
4+ ( typeof Bun !== 'undefined' && typeof Bun . main === 'string' && Bun . main ) ||
5+ ( typeof process !== 'undefined' &&
6+ Array . isArray ( process . argv ) &&
7+ process . argv [ 1 ] ) ||
8+ ''
9+
10+ if ( cliEntryPoint && typeof globalThis !== 'undefined' ) {
11+ const globalScope = globalThis as Record < string , unknown >
12+ if ( ! ( '__CLI_ENTRY_POINT' in globalScope ) ) {
13+ Object . defineProperty ( globalScope , '__CLI_ENTRY_POINT' , {
14+ value : cliEntryPoint ,
15+ enumerable : false ,
16+ writable : false ,
17+ configurable : false ,
18+ } )
19+ }
20+ }
21+
222import './polyfills/bun-strip-ansi'
323import { createRequire } from 'module'
424
@@ -18,6 +38,31 @@ import { initializeThemeStore } from './state/theme-store'
1838
1939const require = createRequire ( import . meta. url )
2040
41+ const INTERNAL_OSC_FLAG = '--internal-osc-detect'
42+
43+ function isOscDetectionRun ( ) : boolean {
44+ return process . argv . includes ( INTERNAL_OSC_FLAG )
45+ }
46+
47+ async function runOscDetectionSubprocess ( ) : Promise < void > {
48+ // Set env vars to keep subprocess quiet
49+ process. env . __INTERNAL_OSC_DETECT = '1'
50+ process . env . CODEBUFF_GITHUB_ACTIONS = 'true'
51+
52+ // Avoid importing logger or other modules that produce output
53+ const { detectTerminalTheme } = await import ( './utils/terminal-color-detection' )
54+ try {
55+ const theme = await detectTerminalTheme ( )
56+ console . log ( JSON . stringify ( { theme } ) )
57+ await new Promise ( ( resolve ) => setImmediate ( resolve ) )
58+ } catch {
59+ console . log ( JSON . stringify ( { theme : null } ) )
60+ await new Promise ( ( resolve ) => setImmediate ( resolve ) )
61+ }
62+
63+ process . exit ( 0 )
64+ }
65+
2166function loadPackageVersion ( ) : string {
2267 if ( process . env . CODEBUFF_CLI_VERSION ) {
2368 return process . env . CODEBUFF_CLI_VERSION
@@ -37,6 +82,24 @@ function loadPackageVersion(): string {
3782
3883const VERSION = loadPackageVersion ( )
3984
85+ function createQueryClient ( ) : QueryClient {
86+ return new QueryClient ( {
87+ defaultOptions : {
88+ queries : {
89+ staleTime : 5 * 60 * 1000 , // 5 minutes - auth tokens don't change frequently
90+ gcTime : 10 * 60 * 1000 , // 10 minutes - keep cached data a bit longer
91+ retry : false , // Don't retry failed auth queries automatically
92+ refetchOnWindowFocus : false , // CLI doesn't have window focus
93+ refetchOnReconnect : true , // Refetch when network reconnects
94+ refetchOnMount : false , // Don't refetch on every mount
95+ } ,
96+ mutations : {
97+ retry : 1 , // Retry mutations once on failure
98+ } ,
99+ } ,
100+ } )
101+ }
102+
40103type ParsedArgs = {
41104 initialPrompt : string | null
42105 agent ?: string
@@ -70,85 +133,63 @@ function parseArgs(): ParsedArgs {
70133 }
71134}
72135
73- const { initialPrompt, agent, clearLogs } = parseArgs ( )
136+ async function bootstrapCli ( ) : Promise < void > {
137+ const { initialPrompt, agent, clearLogs } = parseArgs ( )
74138
75- // Initialize theme store and watchers
76- initializeThemeStore ( )
139+ initializeThemeStore ( )
77140
78- if ( clearLogs ) {
79- clearLogFile ( )
80- }
141+ if ( clearLogs ) {
142+ clearLogFile ( )
143+ }
81144
82- const loadedAgentsData = getLoadedAgentsData ( )
145+ const loadedAgentsData = getLoadedAgentsData ( )
83146
84- // Validate local agents and capture any errors
85- let validationErrors : Array < { id : string ; message: string } > = [ ]
86- if ( loadedAgentsData ) {
87- const agentDefinitions = loadAgentDefinitions ( )
88- const validationResult = await validateAgents ( agentDefinitions , {
89- remote : true , // Use remote validation to ensure spawnable agents exist
90- } )
147+ let validationErrors : Array < { id : string ; message: string } > = [ ]
148+ if ( loadedAgentsData ) {
149+ const agentDefinitions = loadAgentDefinitions ( )
150+ const validationResult = await validateAgents ( agentDefinitions , {
151+ remote : true ,
152+ } )
91153
92- if ( ! validationResult . success ) {
93- validationErrors = validationResult . validationErrors
94- }
95- }
96-
97- // Create QueryClient instance with CLI-optimized defaults
98- const queryClient = new QueryClient ( {
99- defaultOptions : {
100- queries : {
101- staleTime : 5 * 60 * 1000 , // 5 minutes - auth tokens don't change frequently
102- gcTime : 10 * 60 * 1000 , // 10 minutes - keep cached data a bit longer
103- retry : false , // Don't retry failed auth queries automatically
104- refetchOnWindowFocus : false , // CLI doesn't have window focus
105- refetchOnReconnect : true , // Refetch when network reconnects
106- refetchOnMount : false , // Don't refetch on every mount
107- } ,
108- mutations : {
109- retry : 1 , // Retry mutations once on failure
110- } ,
111- } ,
112- } )
113-
114- // Wrapper component to handle async auth check
115- const AppWithAsyncAuth = ( ) => {
116- const [ requireAuth , setRequireAuth ] = React . useState < boolean | null > ( null )
117- const [ hasInvalidCredentials , setHasInvalidCredentials ] =
118- React . useState ( false )
119-
120- React . useEffect ( ( ) => {
121- // Check authentication asynchronously
122- const userCredentials = getUserCredentials ( )
123- const apiKey =
124- userCredentials ?. authToken || process . env [ API_KEY_ENV_VAR ] || ''
125-
126- if ( ! apiKey ) {
127- // No credentials, require auth
128- setRequireAuth ( true )
129- setHasInvalidCredentials ( false )
130- return
154+ if ( ! validationResult . success ) {
155+ validationErrors = validationResult . validationErrors
131156 }
157+ }
132158
133- // We have credentials - require auth but show invalid credentials banner until validation succeeds
134- setHasInvalidCredentials ( true )
135- setRequireAuth ( false )
136- } , [ ] )
137-
138- return (
139- < App
140- initialPrompt = { initialPrompt }
141- agentId = { agent }
142- requireAuth = { requireAuth }
143- hasInvalidCredentials = { hasInvalidCredentials }
144- loadedAgentsData = { loadedAgentsData }
145- validationErrors = { validationErrors }
146- />
147- )
148- }
159+ const queryClient = createQueryClient ( )
160+
161+ const AppWithAsyncAuth = ( ) => {
162+ const [ requireAuth , setRequireAuth ] = React . useState < boolean | null > ( null )
163+ const [ hasInvalidCredentials , setHasInvalidCredentials ] =
164+ React . useState ( false )
165+
166+ React . useEffect ( ( ) => {
167+ const userCredentials = getUserCredentials ( )
168+ const apiKey =
169+ userCredentials ?. authToken || process . env [ API_KEY_ENV_VAR ] || ''
170+
171+ if ( ! apiKey ) {
172+ setRequireAuth ( true )
173+ setHasInvalidCredentials ( false )
174+ return
175+ }
176+
177+ setHasInvalidCredentials ( true )
178+ setRequireAuth ( false )
179+ } , [ ] )
180+
181+ return (
182+ < App
183+ initialPrompt = { initialPrompt }
184+ agentId = { agent }
185+ requireAuth = { requireAuth }
186+ hasInvalidCredentials = { hasInvalidCredentials }
187+ loadedAgentsData = { loadedAgentsData }
188+ validationErrors = { validationErrors }
189+ />
190+ )
191+ }
149192
150- // Start app immediately with QueryClientProvider
151- function startApp ( ) {
152193 render (
153194 < QueryClientProvider client = { queryClient } >
154195 < AppWithAsyncAuth />
@@ -160,4 +201,13 @@ function startApp() {
160201 )
161202}
162203
163- startApp ( )
204+ async function main ( ) : Promise < void > {
205+ if ( isOscDetectionRun ( ) ) {
206+ await runOscDetectionSubprocess ( )
207+ return
208+ }
209+
210+ await bootstrapCli ( )
211+ }
212+
213+ void main ( )
0 commit comments