@@ -269,6 +269,21 @@ Examples:
269269 },
270270}
271271
272+ var uninstallCmd = & cobra.Command {
273+ Use : "uninstall" ,
274+ Short : "Uninstall opencode-sync" ,
275+ Long : `Remove opencode-sync and optionally its data.
276+
277+ This will:
278+ - Remove the opencode-sync binary (may require sudo)
279+ - Optionally remove config and sync data
280+
281+ Your OpenCode configurations are NOT affected.` ,
282+ RunE : func (cmd * cobra.Command , args []string ) error {
283+ return runUninstall ()
284+ },
285+ }
286+
272287func init () {
273288 // Add config subcommands
274289 configCmd .AddCommand (configShowCmd )
@@ -1278,3 +1293,71 @@ func runGitCommand(dir string, args ...string) error {
12781293 cmd .Stderr = os .Stderr
12791294 return cmd .Run ()
12801295}
1296+
1297+ func runUninstall () error {
1298+ ui .Warn ("This will uninstall opencode-sync from your system." )
1299+ fmt .Println ()
1300+
1301+ p , err := paths .Get ()
1302+ if err != nil {
1303+ return fmt .Errorf ("failed to get paths: %w" , err )
1304+ }
1305+
1306+ binaryPath , err := os .Executable ()
1307+ if err != nil {
1308+ binaryPath = "opencode-sync (location unknown)"
1309+ }
1310+
1311+ fmt .Println ("The following will be removed:" )
1312+ fmt .Printf (" Binary: %s\n " , binaryPath )
1313+ fmt .Printf (" Config: %s\n " , p .ConfigDir )
1314+ fmt .Printf (" Data: %s\n " , p .DataDir )
1315+ fmt .Println ()
1316+ ui .Info ("Your OpenCode configurations will NOT be affected." )
1317+ fmt .Println ()
1318+
1319+ confirmed , err := ui .Confirm ("Proceed with uninstall?" , "This cannot be undone" )
1320+ if err != nil {
1321+ return err
1322+ }
1323+ if ! confirmed {
1324+ ui .Info ("Uninstall cancelled" )
1325+ return nil
1326+ }
1327+
1328+ removeData , err := ui .Confirm ("Also remove config and sync data?" , "Includes encryption key and local repo" )
1329+ if err != nil {
1330+ return err
1331+ }
1332+
1333+ if removeData {
1334+ if err := os .RemoveAll (p .ConfigDir ); err != nil {
1335+ ui .Warn (fmt .Sprintf ("Failed to remove config dir: %v" , err ))
1336+ } else {
1337+ ui .Success (fmt .Sprintf ("Removed: %s" , p .ConfigDir ))
1338+ }
1339+
1340+ if err := os .RemoveAll (p .DataDir ); err != nil {
1341+ ui .Warn (fmt .Sprintf ("Failed to remove data dir: %v" , err ))
1342+ } else {
1343+ ui .Success (fmt .Sprintf ("Removed: %s" , p .DataDir ))
1344+ }
1345+ }
1346+
1347+ if binaryPath != "" && binaryPath != "opencode-sync (location unknown)" {
1348+ if err := os .Remove (binaryPath ); err != nil {
1349+ if os .IsPermission (err ) {
1350+ ui .Warn ("Cannot remove binary (permission denied). Run with sudo or remove manually:" )
1351+ fmt .Printf (" sudo rm %s\n " , binaryPath )
1352+ } else {
1353+ ui .Warn (fmt .Sprintf ("Failed to remove binary: %v" , err ))
1354+ }
1355+ } else {
1356+ ui .Success (fmt .Sprintf ("Removed: %s" , binaryPath ))
1357+ }
1358+ }
1359+
1360+ fmt .Println ()
1361+ ui .Success ("Uninstall complete!" )
1362+ return nil
1363+ }
0 commit comments