@@ -3,7 +3,7 @@ const crypto = require("crypto");
33const fs = require ( "fs" ) ;
44const path = require ( "path" ) ;
55
6- const { loadConfig, addInstallation, hashFile } = require ( "./config" ) ;
6+ const { loadConfig, addInstallation, hashFile, removeInstallation } = require ( "./config" ) ;
77const { parseSource, getGitHubAssets, downloadFromUrl } = require ( "./sources" ) ;
88const { createLogger, confirm, fileSize } = require ( "./utils" ) ;
99
@@ -65,8 +65,8 @@ const checkGitHubUpdate = async (installation) => {
6565 source . repo
6666 ) ;
6767
68- // Check if there's a newer commit/ tag
69- const hasUpdate = commit !== oldCommit ;
68+ // Check if there's a newer tag (more reliable than commit for releases)
69+ const hasUpdate = tag !== installation . version ;
7070
7171 if ( ! hasUpdate ) {
7272 return { name, hasUpdate : false , reason : "Already up to date" } ;
@@ -76,7 +76,8 @@ const checkGitHubUpdate = async (installation) => {
7676 const newAsset = assets . find (
7777 ( asset ) =>
7878 asset . name . includes ( selected . name . split ( "." ) [ 0 ] ) ||
79- asset . extension === selected . extension
79+ asset . extension === selected . extension ||
80+ asset . name . includes ( name ) // Also check if asset name contains the package name
8081 ) ;
8182
8283 if ( ! newAsset ) {
@@ -161,7 +162,18 @@ const checkFileUpdate = async (installation) => {
161162
162163const performUpdate = async ( updateInfo , customFilePath = null ) => {
163164 const log = createLogger ( ) ;
164- const { name, source } = updateInfo ;
165+ const { name } = updateInfo ;
166+
167+ // Ensure we have source info; if missing, fetch from installation history
168+ let source = updateInfo . source ;
169+ if ( ! source ) {
170+ const config = loadConfig ( ) ;
171+ const installation = config . find ( ( item ) => item . name === name ) ;
172+ if ( ! installation ) {
173+ throw new Error ( `No installation record found for '${ name } '` ) ;
174+ }
175+ source = installation . source ;
176+ }
165177
166178 log . log ( `Updating ${ name } ...` ) ;
167179
@@ -173,6 +185,29 @@ const performUpdate = async (updateInfo, customFilePath = null) => {
173185
174186 try {
175187 await performInstallation ( originalArgs , true ) ; // isUpdate = true
188+
189+ // After successful update, refresh the installation record with new version info
190+ if ( updateInfo . newTag ) {
191+ const config = loadConfig ( ) ;
192+ const installation = config . find ( ( item ) => item . name === name ) ;
193+ if ( installation ) {
194+ installation . version = updateInfo . newTag ;
195+ installation . commit = updateInfo . newCommit ;
196+ installation . date = new Date ( ) . toISOString ( ) ;
197+
198+ // Update the selected asset info if we have it
199+ if ( updateInfo . newAsset ) {
200+ installation . selected . name = updateInfo . newAsset . name ;
201+ installation . selected . size = updateInfo . newAsset . size ;
202+ installation . selected . downloadUrl = updateInfo . newAsset . browser_download_url ;
203+ }
204+
205+ const { saveConfig } = require ( "./config" ) ;
206+ saveConfig ( config ) ;
207+ log . debug ( `Updated installation record for ${ name } to version ${ updateInfo . newTag } ` ) ;
208+ }
209+ }
210+
176211 log . log ( `Successfully updated ${ name } ` ) ;
177212 } catch ( error ) {
178213 log . error ( `Failed to update ${ name } : ${ error . message } ` ) ;
@@ -208,9 +243,70 @@ const removePackageHistory = (packageName) => {
208243 removeInstallation ( packageName ) ;
209244} ;
210245
246+ const getPathSize = ( p ) => {
247+ const stat = fs . statSync ( p ) ;
248+ if ( stat . isFile ( ) ) return stat . size ;
249+ if ( stat . isDirectory ( ) ) {
250+ let total = 0 ;
251+ for ( const entry of fs . readdirSync ( p ) ) {
252+ total += getPathSize ( path . join ( p , entry ) ) ;
253+ }
254+ return total ;
255+ }
256+ return 0 ;
257+ } ;
258+
259+ const performUninstall = async ( packageName ) => {
260+ const log = createLogger ( ) ;
261+ const config = loadConfig ( ) ;
262+ const installation = config . find ( ( item ) => item . name === packageName ) ;
263+
264+ if ( ! installation ) {
265+ throw new Error ( `Package '${ packageName } ' not found in installation history` ) ;
266+ }
267+
268+ const destinations = installation . installation ?. destinations || [ ] ;
269+ if ( destinations . length === 0 ) {
270+ throw new Error ( `No recorded destinations for '${ packageName } '` ) ;
271+ }
272+
273+ let totalBytes = 0 ;
274+ for ( const dest of destinations ) {
275+ if ( fs . existsSync ( dest ) ) {
276+ try {
277+ totalBytes += getPathSize ( dest ) ;
278+ } catch ( e ) {
279+ // Ignore size calc errors; proceed with uninstall
280+ }
281+ }
282+ }
283+
284+ const { fileSize, confirm } = require ( "./utils" ) ;
285+ const pretty = fileSize ( totalBytes , true , 1 ) ;
286+ log . log ( `Uninstalling ${ packageName } (${ pretty } )` ) ;
287+ if ( ! ( await confirm ( `Proceed to uninstall ${ packageName } ?` ) ) ) {
288+ throw new Error ( "Uninstall canceled by user" ) ;
289+ }
290+
291+ for ( const dest of destinations ) {
292+ if ( fs . existsSync ( dest ) ) {
293+ try {
294+ fs . rmSync ( dest , { recursive : true , force : true } ) ;
295+ log . debug ( `Removed ${ dest } ` ) ;
296+ } catch ( e ) {
297+ log . warn ( `Failed to remove ${ dest } : ${ e . message } ` ) ;
298+ }
299+ }
300+ }
301+
302+ removeInstallation ( packageName ) ;
303+ log . log ( `Successfully uninstalled ${ packageName } ` ) ;
304+ } ;
305+
211306module . exports = {
212307 checkForUpdates,
213308 performUpdate,
214309 listInstalled,
215310 removePackageHistory,
311+ performUninstall,
216312} ;
0 commit comments