@@ -180,6 +180,9 @@ export function createSettingsRoutes(db: Database) {
180180 const body = await c . req . json ( )
181181 const validated = UpdateOpenCodeConfigSchema . parse ( body )
182182
183+ const existingConfig = settingsService . getOpenCodeConfigByName ( configName , userId )
184+ const existingAgents = existingConfig ?. content ?. agent
185+
183186 const config = settingsService . updateOpenCodeConfig ( configName , validated , userId )
184187 if ( ! config ) {
185188 return c . json ( { error : 'Config not found' } , 404 )
@@ -190,9 +193,17 @@ export function createSettingsRoutes(db: Database) {
190193 await writeFileContent ( configPath , config . rawContent )
191194 logger . info ( `Wrote default config to: ${ configPath } ` )
192195
193- const patchResult = await patchOpenCodeConfig ( config . content )
194- if ( ! patchResult . success ) {
195- return c . json ( { error : 'Config saved but failed to apply' , details : patchResult . error } , 500 )
196+ const newAgents = config . content ?. agent
197+ const agentsChanged = JSON . stringify ( existingAgents ) !== JSON . stringify ( newAgents )
198+
199+ if ( agentsChanged ) {
200+ logger . info ( 'Agent configuration changed, restarting OpenCode server' )
201+ await opencodeServerManager . restart ( )
202+ } else {
203+ const patchResult = await patchOpenCodeConfig ( config . content )
204+ if ( ! patchResult . success ) {
205+ return c . json ( { error : 'Config saved but failed to apply' , details : patchResult . error } , 500 )
206+ }
196207 }
197208 }
198209
@@ -415,6 +426,92 @@ export function createSettingsRoutes(db: Database) {
415426 }
416427 } )
417428
429+ app . get ( '/opencode-versions' , async ( c ) => {
430+ try {
431+ logger . info ( 'Fetching available OpenCode versions from GitHub' )
432+
433+ const response = await fetch ( 'https://api.github.com/repos/sst/opencode/releases?per_page=20' , {
434+ headers : {
435+ 'Accept' : 'application/vnd.github.v3+json' ,
436+ 'User-Agent' : 'opencode-manager'
437+ }
438+ } )
439+
440+ if ( ! response . ok ) {
441+ throw new Error ( `GitHub API returned ${ response . status } ` )
442+ }
443+
444+ const releases = await response . json ( ) as Array < {
445+ tag_name : string
446+ name : string
447+ published_at : string
448+ prerelease : boolean
449+ } >
450+
451+ const versions = releases
452+ . filter ( r => ! r . prerelease )
453+ . map ( r => ( {
454+ version : r . tag_name . replace ( / ^ v / , '' ) ,
455+ tag : r . tag_name ,
456+ name : r . name ,
457+ publishedAt : r . published_at
458+ } ) )
459+
460+ const currentVersion = opencodeServerManager . getVersion ( )
461+
462+ return c . json ( {
463+ versions,
464+ currentVersion
465+ } )
466+ } catch ( error ) {
467+ logger . error ( 'Failed to fetch OpenCode versions:' , error )
468+ return c . json ( {
469+ error : 'Failed to fetch versions' ,
470+ details : error instanceof Error ? error . message : 'Unknown error'
471+ } , 500 )
472+ }
473+ } )
474+
475+ app . post ( '/opencode-install-version' , async ( c ) => {
476+ try {
477+ const body = await c . req . json ( )
478+ const { version } = z . object ( { version : z . string ( ) . min ( 1 ) } ) . parse ( body )
479+
480+ logger . info ( `Installing OpenCode version: ${ version } ` )
481+
482+ const oldVersion = opencodeServerManager . getVersion ( )
483+ logger . info ( `Current OpenCode version: ${ oldVersion } ` )
484+
485+ const versionArg = version . startsWith ( 'v' ) ? version : `v${ version } `
486+ logger . info ( `Running opencode upgrade ${ versionArg } ...` )
487+
488+ const upgradeOutput = execSync ( `opencode upgrade ${ versionArg } 2>&1` , { encoding : 'utf8' } )
489+ logger . info ( `Upgrade output: ${ upgradeOutput } ` )
490+
491+ await new Promise ( r => setTimeout ( r , 2000 ) )
492+
493+ const newVersion = await opencodeServerManager . fetchVersion ( )
494+ logger . info ( `New OpenCode version: ${ newVersion } ` )
495+
496+ opencodeServerManager . clearStartupError ( )
497+ await opencodeServerManager . restart ( )
498+ logger . info ( 'OpenCode server restarted after version change' )
499+
500+ return c . json ( {
501+ success : true ,
502+ message : `OpenCode ${ oldVersion ? `changed from v${ oldVersion } to` : 'installed as' } v${ newVersion } ` ,
503+ oldVersion,
504+ newVersion
505+ } )
506+ } catch ( error ) {
507+ logger . error ( 'Failed to install OpenCode version:' , error )
508+ return c . json ( {
509+ error : 'Failed to install OpenCode version' ,
510+ details : error instanceof Error ? error . message : 'Unknown error'
511+ } , 500 )
512+ }
513+ } )
514+
418515 // Custom Commands routes
419516 app . get ( '/custom-commands' , async ( c ) => {
420517 try {
@@ -540,8 +637,8 @@ export function createSettingsRoutes(db: Database) {
540637 await writeFileContent ( agentsMdPath , content )
541638 logger . info ( `Updated AGENTS.md at: ${ agentsMdPath } ` )
542639
543- await opencodeServerManager . reloadConfig ( )
544- logger . info ( 'Reloaded OpenCode configuration after AGENTS.md update' )
640+ await opencodeServerManager . restart ( )
641+ logger . info ( 'Restarted OpenCode server after AGENTS.md update' )
545642
546643 return c . json ( { success : true } )
547644 } catch ( error ) {
0 commit comments