11import type { Argv } from "yargs"
22import { UI } from "../ui"
33import { VERSION } from "../version"
4- import path from "path"
5- import fs from "fs/promises"
6- import os from "os"
74import * as prompts from "@clack/prompts"
8- import { Global } from "../../global"
9-
10- const API = "https://api.github.com/repos/sst/opencode"
11-
12- interface Release {
13- tag_name : string
14- name : string
15- assets : Array < {
16- name : string
17- browser_download_url : string
18- } >
19- }
20-
21- function asset ( ) : string {
22- const platform = os . platform ( )
23- const arch = os . arch ( )
24-
25- if ( platform === "darwin" ) {
26- return arch === "arm64"
27- ? "opencode-darwin-arm64.zip"
28- : "opencode-darwin-x64.zip"
29- }
30- if ( platform === "linux" ) {
31- return arch === "arm64"
32- ? "opencode-linux-arm64.zip"
33- : "opencode-linux-x64.zip"
34- }
35- if ( platform === "win32" ) {
36- return "opencode-windows-x64.zip"
37- }
38-
39- throw new Error ( `Unsupported platform: ${ platform } -${ arch } ` )
40- }
41-
42- function compare ( current : string , latest : string ) : number {
43- const a = current . replace ( / ^ v / , "" )
44- const b = latest . replace ( / ^ v / , "" )
45-
46- const aParts = a . split ( "." ) . map ( Number )
47- const bParts = b . split ( "." ) . map ( Number )
48-
49- for ( let i = 0 ; i < Math . max ( aParts . length , bParts . length ) ; i ++ ) {
50- const aPart = aParts [ i ] || 0
51- const bPart = bParts [ i ] || 0
52-
53- if ( aPart < bPart ) return - 1
54- if ( aPart > bPart ) return 1
55- }
56-
57- return 0
58- }
59-
60- async function latest ( ) : Promise < Release > {
61- const response = await fetch ( `${ API } /releases/latest` )
62- if ( ! response . ok ) {
63- throw new Error ( `Failed to fetch latest release: ${ response . statusText } ` )
64- }
65- return response . json ( )
66- }
67-
68- async function specific ( version : string ) : Promise < Release > {
69- const tag = version . startsWith ( "v" ) ? version : `v${ version } `
70- const response = await fetch ( `${ API } /releases/tags/${ tag } ` )
71- if ( ! response . ok ) {
72- throw new Error ( `Failed to fetch release ${ tag } : ${ response . statusText } ` )
73- }
74- return response . json ( )
75- }
76-
77- async function download ( url : string ) : Promise < string > {
78- const response = await fetch ( url )
79- if ( ! response . ok ) {
80- throw new Error ( `Failed to download: ${ response . statusText } ` )
81- }
82-
83- const buffer = await response . arrayBuffer ( )
84- const temp = path . join ( Global . Path . cache , `opencode-update-${ Date . now ( ) } .zip` )
85-
86- await Bun . write ( temp , buffer )
87-
88- const extractDir = path . join (
89- Global . Path . cache ,
90- `opencode-extract-${ Date . now ( ) } ` ,
91- )
92- await fs . mkdir ( extractDir , { recursive : true } )
93-
94- const proc = Bun . spawn ( [ "unzip" , "-o" , temp , "-d" , extractDir ] , {
95- stdout : "pipe" ,
96- stderr : "pipe" ,
97- } )
98-
99- const result = await proc . exited
100- if ( result !== 0 ) {
101- throw new Error ( "Failed to extract update" )
102- }
103-
104- await fs . unlink ( temp )
105-
106- const binary = path . join ( extractDir , "opencode" )
107- await fs . chmod ( binary , 0o755 )
108-
109- return binary
110- }
5+ import { Installation } from "../../installation"
1116
1127export const UpgradeCommand = {
1138 command : "upgrade [target]" ,
@@ -123,14 +18,35 @@ export const UpgradeCommand = {
12318 UI . println ( UI . logo ( " " ) )
12419 UI . empty ( )
12520 prompts . intro ( "Upgrade" )
126-
127- if ( ! process . execPath . includes ( path . join ( ".opencode" , "bin" ) ) && false ) {
21+ const method = await Installation . method ( )
22+ if ( method === "unknown" ) {
12823 prompts . log . error (
12924 `opencode is installed to ${ process . execPath } and seems to be managed by a package manager` ,
13025 )
13126 prompts . outro ( "Done" )
13227 return
13328 }
29+ const target = args . target ?? ( await Installation . latest ( ) )
30+ prompts . log . info ( `From ${ VERSION } → ${ target } ` )
31+ const spinner = prompts . spinner ( )
32+ spinner . start ( "Upgrading..." )
33+ const err = await Installation . upgrade ( method , target ) . catch ( ( err ) => err )
34+ if ( err ) {
35+ spinner . stop ( "Upgrade failed" )
36+ if ( err instanceof Installation . UpgradeFailedError )
37+ prompts . log . error ( err . data . stderr )
38+ else if ( err instanceof Error ) prompts . log . error ( err . message )
39+ prompts . outro ( "Done" )
40+ return
41+ }
42+ spinner . stop ( "Upgrade complete" )
43+ prompts . outro ( "Done" )
44+ return
45+
46+ /*
47+ if (!process.execPath.includes(path.join(".opencode", "bin")) && false) {
48+ return
49+ }
13450
13551 const release = args.target
13652 ? await specific(args.target).catch(() => {})
@@ -188,5 +104,6 @@ export const UpgradeCommand = {
188104
189105 prompts.log.success(`Successfully upgraded to ${target}`)
190106 prompts.outro("Done")
107+ */
191108 } ,
192109}
0 commit comments