@@ -255,18 +255,26 @@ _install_step :: proc() {
255255 if _yn_default_yes () {
256256 olt_dst := strings.join ([]string {dst_dir, " olt" }, " /" )
257257 defer delete (olt_dst)
258- _ = os.remove (olt_dst)
258+
259+ // Create parent directory if needed
260+ last_slash := strings.last_index (olt_dst, " /" )
261+ if last_slash > 0 {
262+ dir := olt_dst[:last_slash]
263+ _mkdir_p (dir)
264+ }
265+
266+ // Copy with proper error handling
259267 state, _, _, err := os.process_exec (
260- os.Process_Desc{command = []string {" cp" , olt_src, olt_dst}},
268+ os.Process_Desc{command = []string {" cp" , " -f " , olt_src, olt_dst}},
261269 context .allocator,
262270 )
263271 if err != nil || !state.success {
264- fmt.println (" ✗ olt " )
272+ fmt.printfln (" ✗ Failed to copy binary: %v " , err )
265273 } else {
266274 if already_installed {
267275 fmt.println (" ✓ olt updated" )
268276 } else {
269- fmt.println (" ✓ olt" )
277+ fmt.println (" ✓ olt installed " )
270278 }
271279 }
272280 }
@@ -810,29 +818,51 @@ _mcp_codex :: proc(codex_dir, mcp_bin: string) {
810818@ (private = " file" )
811819_mcp_opencode :: proc (opencode_dir, mcp_bin: string ) {
812820 cfg_path := _pjoin (opencode_dir, " opencode.json" )
821+
822+ // Create backup of existing config if it exists
823+ backup_path := " "
813824 if os.is_file (cfg_path) {
814825 existing, err := os.read_entire_file_from_path (cfg_path, context .temp_allocator)
815826 if err == nil && strings.contains (string (existing), " olt" ) {
816827 fmt.println (" Already configured ✓" )
817828 return
818829 }
819- fmt.println (" Config exists — add under the \" mcp\" key:" )
820- _snippet_opencode_entry (mcp_bin)
821- return
830+ backup_path = strings.join ([]string {cfg_path, " .bak" }, " " , allocator = context .temp_allocator)
831+ _ = os.rename (cfg_path, backup_path)
822832 }
833+
823834 fmt.print (" Create opencode.json with olt-mcp entry? [Y/n]: " )
824835 if !_yn_default_yes () {
825836 fmt.println (" Skipped. Create opencode.json with:" )
826837 _snippet_opencode_full (mcp_bin)
827838 return
828839 }
829- if !os.is_dir (opencode_dir) { _mkdir_p (opencode_dir) }
840+
841+ // Create directory if needed
842+ if !os.is_dir (opencode_dir) {
843+ _mkdir_p (opencode_dir)
844+ }
845+
846+ // Create new configuration
830847 content := _snippet_opencode_full_str (mcp_bin)
831848 defer delete (content)
849+
850+ // Debug: print the content
851+ fmt.printfln (" DEBUG: Writing content: %s" , content)
852+
853+ // Write with error handling
832854 if err := os.write_entire_file (cfg_path, transmute ([]u8 )content); err != nil {
855+ // Restore backup if write fails
856+ if backup_path != " " {
857+ _ = os.rename (backup_path, cfg_path)
858+ }
833859 fmt.println (" ✗ Write failed. Create opencode.json with:" )
834860 _snippet_opencode_full (mcp_bin)
835861 } else {
862+ // Remove backup if successful
863+ if backup_path != " " {
864+ _ = os.remove (backup_path)
865+ }
836866 fmt.println (" ✓ Created opencode.json" )
837867 }
838868}
@@ -979,11 +1009,13 @@ _snippet_opencode_full :: proc(mcp_bin: string) {
9791009
9801010@ (private = " file" )
9811011_snippet_opencode_full_str :: proc (mcp_bin: string ) -> string {
1012+ part1 := " {\n \" mcp\" : {\n \" olt-mcp\" : {\n \" type\" : \" local\" ,\n \" command\" : [\" "
1013+ part2 := " \" ]\n }\n }\n }"
9821014 b := strings.builder_make ()
9831015 defer strings.builder_destroy (&b)
984- fmt. sbprintf (&b,
985- " { \n \" mcp \" : { \n \" olt-mcp \" : { \n \" type \" : \" local \" , \n \" command \" : [ \" %s \" ] \n } \n } \n } \n " ,
986- mcp_bin )
1016+ strings. write_string (&b, part1)
1017+ strings. write_string (&b, mcp_bin)
1018+ strings. write_string (&b, part2 )
9871019 return strings.clone (strings.to_string (b))
9881020}
9891021
0 commit comments