1515 */
1616
1717import { spawn } from 'node:child_process'
18- import { existsSync } from 'node:fs'
18+ import { existsSync , promises as fs } from 'node:fs'
19+ import path from 'node:path'
1920
20- import { getCliEntryPoint , getCliPackageDir } from './shared/paths.mjs'
21+ import {
22+ getCliEntryPoint ,
23+ getCliPackageDir ,
24+ getCliPackageName ,
25+ getDlxDir ,
26+ } from './shared/paths.mjs'
2127
2228/**
2329 * Check if CLI is installed.
@@ -28,18 +34,94 @@ function isCliInstalled(): boolean {
2834 return existsSync ( entryPoint ) && existsSync ( packageJson )
2935}
3036
37+ /**
38+ * Download CLI using npm pack command.
39+ * This delegates to npm which handles downloading and extracting the latest version.
40+ */
41+ async function downloadCli ( ) : Promise < void > {
42+ const packageName = getCliPackageName ( )
43+ const dlxDir = getDlxDir ( )
44+ const cliDir = getCliPackageDir ( )
45+
46+ await fs . mkdir ( dlxDir , { recursive : true } )
47+
48+ console . error ( `Downloading ${ packageName } ...` )
49+
50+ return new Promise ( ( resolve , reject ) => {
51+ const npmPackProcess = spawn (
52+ 'npm' ,
53+ [ 'pack' , packageName , '--pack-destination' , dlxDir ] ,
54+ {
55+ stdio : [ 'ignore' , 'pipe' , 'inherit' ] ,
56+ } ,
57+ )
58+
59+ let tarballName = ''
60+ npmPackProcess . stdout ?. on ( 'data' , data => {
61+ tarballName += data . toString ( )
62+ } )
63+
64+ npmPackProcess . on ( 'error' , e => {
65+ reject ( new Error ( `Failed to run npm pack: ${ e } ` ) )
66+ } )
67+
68+ npmPackProcess . on ( 'exit' , async code => {
69+ if ( code !== 0 ) {
70+ reject ( new Error ( `npm pack exited with code ${ code } ` ) )
71+ return
72+ }
73+
74+ try {
75+ const tarballPath = path . join ( dlxDir , tarballName . trim ( ) )
76+
77+ await fs . mkdir ( cliDir , { recursive : true } )
78+
79+ const tarExtractProcess = spawn (
80+ 'tar' ,
81+ [ '-xzf' , tarballPath , '-C' , cliDir , '--strip-components=1' ] ,
82+ {
83+ stdio : 'inherit' ,
84+ } ,
85+ )
86+
87+ tarExtractProcess . on ( 'error' , e => {
88+ reject ( new Error ( `Failed to extract tarball: ${ e } ` ) )
89+ } )
90+
91+ tarExtractProcess . on ( 'exit' , async extractCode => {
92+ if ( extractCode !== 0 ) {
93+ reject ( new Error ( `tar extraction exited with code ${ extractCode } ` ) )
94+ return
95+ }
96+
97+ await fs . unlink ( tarballPath ) . catch ( ( ) => {
98+ // Ignore cleanup errors.
99+ } )
100+
101+ console . error ( 'Socket CLI installed successfully' )
102+ resolve ( )
103+ } )
104+ } catch ( e ) {
105+ reject ( e )
106+ }
107+ } )
108+ } )
109+ }
110+
31111/**
32112 * Main entry point.
33113 */
34114async function main ( ) : Promise < void > {
35115 // Check if CLI is already installed.
36116 if ( ! isCliInstalled ( ) ) {
37- // TODO: Implement download logic using shared utilities.
38117 console . error ( 'Socket CLI not installed yet.' )
39- console . error ( 'Installing from npm...' )
40- console . error ( 'TODO: Implement download from npm registry' )
41- // eslint-disable-next-line n/no-process-exit
42- process . exit ( 1 )
118+ try {
119+ await downloadCli ( )
120+ } catch ( error ) {
121+ console . error ( 'Failed to download Socket CLI:' , error )
122+ // eslint-disable-next-line n/no-process-exit
123+ process . exit ( 1 )
124+ }
43125 }
44126
45127 // CLI is installed, delegate to it.
0 commit comments