@@ -23,21 +23,21 @@ export namespace Config {
2323 for ( const file of [ "opencode.jsonc" , "opencode.json" ] ) {
2424 const found = await Filesystem . findUp ( file , app . path . cwd , app . path . root )
2525 for ( const resolved of found . toReversed ( ) ) {
26- result = mergeDeep ( result , await load ( resolved ) )
26+ result = mergeDeep ( result , await loadFile ( resolved ) )
2727 }
2828 }
2929
3030 // Override with custom config if provided
3131 if ( Flag . OPENCODE_CONFIG ) {
32- result = mergeDeep ( result , await load ( Flag . OPENCODE_CONFIG ) )
32+ result = mergeDeep ( result , await loadFile ( Flag . OPENCODE_CONFIG ) )
3333 log . debug ( "loaded custom config" , { path : Flag . OPENCODE_CONFIG } )
3434 }
3535
3636 for ( const [ key , value ] of Object . entries ( auth ) ) {
3737 if ( value . type === "wellknown" ) {
3838 process . env [ value . key ] = value . token
3939 const wellknown = await fetch ( `${ key } /.well-known/opencode` ) . then ( ( x ) => x . json ( ) )
40- result = mergeDeep ( result , await loadRaw ( JSON . stringify ( wellknown . config ?? { } ) , process . cwd ( ) ) )
40+ result = mergeDeep ( result , await load ( JSON . stringify ( wellknown . config ?? { } ) , process . cwd ( ) ) )
4141 }
4242 }
4343
@@ -223,6 +223,7 @@ export namespace Config {
223223 $schema : z . string ( ) . optional ( ) . describe ( "JSON schema reference for configuration validation" ) ,
224224 theme : z . string ( ) . optional ( ) . describe ( "Theme name to use for the interface" ) ,
225225 keybinds : Keybinds . optional ( ) . describe ( "Custom keybind configurations" ) ,
226+ plugin : z . string ( ) . array ( ) . optional ( ) ,
226227 share : z
227228 . enum ( [ "manual" , "auto" , "disabled" ] )
228229 . optional ( )
@@ -352,9 +353,9 @@ export namespace Config {
352353 export const global = lazy ( async ( ) => {
353354 let result : Info = pipe (
354355 { } ,
355- mergeDeep ( await load ( path . join ( Global . Path . config , "config.json" ) ) ) ,
356- mergeDeep ( await load ( path . join ( Global . Path . config , "opencode.json" ) ) ) ,
357- mergeDeep ( await load ( path . join ( Global . Path . config , "opencode.jsonc" ) ) ) ,
356+ mergeDeep ( await loadFile ( path . join ( Global . Path . config , "config.json" ) ) ) ,
357+ mergeDeep ( await loadFile ( path . join ( Global . Path . config , "opencode.json" ) ) ) ,
358+ mergeDeep ( await loadFile ( path . join ( Global . Path . config , "opencode.jsonc" ) ) ) ,
358359 )
359360
360361 await import ( path . join ( Global . Path . config , "config" ) , {
@@ -375,25 +376,26 @@ export namespace Config {
375376 return result
376377 } )
377378
378- async function load ( configPath : string ) : Promise < Info > {
379- let text = await Bun . file ( configPath )
379+ async function loadFile ( filepath : string ) : Promise < Info > {
380+ log . info ( "loading" , { path : filepath } )
381+ let text = await Bun . file ( filepath )
380382 . text ( )
381383 . catch ( ( err ) => {
382384 if ( err . code === "ENOENT" ) return
383- throw new JsonError ( { path : configPath } , { cause : err } )
385+ throw new JsonError ( { path : filepath } , { cause : err } )
384386 } )
385387 if ( ! text ) return { }
386- return loadRaw ( text , configPath )
388+ return load ( text , filepath )
387389 }
388390
389- async function loadRaw ( text : string , configPath : string ) {
391+ async function load ( text : string , filepath : string ) {
390392 text = text . replace ( / \{ e n v : ( [ ^ } ] + ) \} / g, ( _ , varName ) => {
391393 return process . env [ varName ] || ""
392394 } )
393395
394396 const fileMatches = text . match ( / \{ f i l e : [ ^ } ] + \} / g)
395397 if ( fileMatches ) {
396- const configDir = path . dirname ( configPath )
398+ const configDir = path . dirname ( filepath )
397399 const lines = text . split ( "\n" )
398400
399401 for ( const match of fileMatches ) {
@@ -428,7 +430,7 @@ export namespace Config {
428430 . join ( "\n" )
429431
430432 throw new JsonError ( {
431- path : configPath ,
433+ path : filepath ,
432434 message : `\n--- JSONC Input ---\n${ text } \n--- Errors ---\n${ errorDetails } \n--- End ---` ,
433435 } )
434436 }
@@ -437,11 +439,21 @@ export namespace Config {
437439 if ( parsed . success ) {
438440 if ( ! parsed . data . $schema ) {
439441 parsed . data . $schema = "https://opencode.ai/config.json"
440- await Bun . write ( configPath , JSON . stringify ( parsed . data , null , 2 ) )
442+ await Bun . write ( filepath , JSON . stringify ( parsed . data , null , 2 ) )
441443 }
442- return parsed . data
444+ const data = parsed . data
445+ if ( data . plugin ) {
446+ for ( let i = 0 ; i < data . plugin ?. length ; i ++ ) {
447+ const plugin = data . plugin [ i ]
448+ if ( typeof plugin === "string" ) {
449+ data . plugin [ i ] = path . resolve ( path . dirname ( filepath ) , plugin )
450+ }
451+ }
452+ }
453+ return data
443454 }
444- throw new InvalidError ( { path : configPath , issues : parsed . error . issues } )
455+
456+ throw new InvalidError ( { path : filepath , issues : parsed . error . issues } )
445457 }
446458 export const JsonError = NamedError . create (
447459 "ConfigJsonError" ,
0 commit comments