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,40 @@ 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, terminalSupportsOSC } = await import (
54+ './utils/terminal-color-detection'
55+ )
56+
57+ if ( ! terminalSupportsOSC ( ) ) {
58+ console . log ( JSON . stringify ( { theme : null } ) )
59+ await new Promise ( ( resolve ) => setImmediate ( resolve ) )
60+ process . exit ( 0 )
61+ }
62+
63+ try {
64+ const theme = await detectTerminalTheme ( )
65+ console . log ( JSON . stringify ( { theme } ) )
66+ await new Promise ( ( resolve ) => setImmediate ( resolve ) )
67+ } catch {
68+ console . log ( JSON . stringify ( { theme : null } ) )
69+ await new Promise ( ( resolve ) => setImmediate ( resolve ) )
70+ }
71+
72+ process . exit ( 0 )
73+ }
74+
2175function loadPackageVersion ( ) : string {
2276 if ( process . env . CODEBUFF_CLI_VERSION ) {
2377 return process . env . CODEBUFF_CLI_VERSION
@@ -37,6 +91,24 @@ function loadPackageVersion(): string {
3791
3892const VERSION = loadPackageVersion ( )
3993
94+ function createQueryClient ( ) : QueryClient {
95+ return new QueryClient ( {
96+ defaultOptions : {
97+ queries : {
98+ staleTime : 5 * 60 * 1000 , // 5 minutes - auth tokens don't change frequently
99+ gcTime : 10 * 60 * 1000 , // 10 minutes - keep cached data a bit longer
100+ retry : false , // Don't retry failed auth queries automatically
101+ refetchOnWindowFocus : false , // CLI doesn't have window focus
102+ refetchOnReconnect : true , // Refetch when network reconnects
103+ refetchOnMount : false , // Don't refetch on every mount
104+ } ,
105+ mutations : {
106+ retry : 1 , // Retry mutations once on failure
107+ } ,
108+ } ,
109+ } )
110+ }
111+
40112type ParsedArgs = {
41113 initialPrompt : string | null
42114 agent ?: string
@@ -70,85 +142,63 @@ function parseArgs(): ParsedArgs {
70142 }
71143}
72144
73- const { initialPrompt, agent, clearLogs } = parseArgs ( )
145+ async function bootstrapCli ( ) : Promise < void > {
146+ const { initialPrompt, agent, clearLogs } = parseArgs ( )
74147
75- // Initialize theme store and watchers
76- initializeThemeStore ( )
148+ initializeThemeStore ( )
77149
78- if ( clearLogs ) {
79- clearLogFile ( )
80- }
81-
82- const loadedAgentsData = getLoadedAgentsData ( )
150+ if ( clearLogs ) {
151+ clearLogFile ( )
152+ }
83153
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- } )
154+ const loadedAgentsData = getLoadedAgentsData ( )
91155
92- if ( ! validationResult . success ) {
93- validationErrors = validationResult . validationErrors
94- }
95- }
156+ let validationErrors : Array < { id : string ; message: string } > = [ ]
157+ if ( loadedAgentsData ) {
158+ const agentDefinitions = loadAgentDefinitions ( )
159+ const validationResult = await validateAgents ( agentDefinitions , {
160+ remote : true ,
161+ } )
96162
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
163+ if ( ! validationResult . success ) {
164+ validationErrors = validationResult . validationErrors
131165 }
166+ }
132167
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- }
168+ const queryClient = createQueryClient ( )
169+
170+ const AppWithAsyncAuth = ( ) => {
171+ const [ requireAuth , setRequireAuth ] = React . useState < boolean | null > ( null )
172+ const [ hasInvalidCredentials , setHasInvalidCredentials ] =
173+ React . useState ( false )
174+
175+ React . useEffect ( ( ) => {
176+ const userCredentials = getUserCredentials ( )
177+ const apiKey =
178+ userCredentials ?. authToken || process . env [ API_KEY_ENV_VAR ] || ''
179+
180+ if ( ! apiKey ) {
181+ setRequireAuth ( true )
182+ setHasInvalidCredentials ( false )
183+ return
184+ }
185+
186+ setHasInvalidCredentials ( true )
187+ setRequireAuth ( false )
188+ } , [ ] )
189+
190+ return (
191+ < App
192+ initialPrompt = { initialPrompt }
193+ agentId = { agent }
194+ requireAuth = { requireAuth }
195+ hasInvalidCredentials = { hasInvalidCredentials }
196+ loadedAgentsData = { loadedAgentsData }
197+ validationErrors = { validationErrors }
198+ />
199+ )
200+ }
149201
150- // Start app immediately with QueryClientProvider
151- function startApp ( ) {
152202 render (
153203 < QueryClientProvider client = { queryClient } >
154204 < AppWithAsyncAuth />
@@ -160,4 +210,13 @@ function startApp() {
160210 )
161211}
162212
163- startApp ( )
213+ async function main ( ) : Promise < void > {
214+ if ( isOscDetectionRun ( ) ) {
215+ await runOscDetectionSubprocess ( )
216+ return
217+ }
218+
219+ await bootstrapCli ( )
220+ }
221+
222+ void main ( )
0 commit comments