11/**
22 * Background preflight downloads for optional dependencies.
33 *
4- * Silently downloads @coana-tech/cli, @cyclonedx/cdxgen, and @socketbin/cli-ai
5- * in the background on first CLI run to ensure they're cached for future use.
4+ * Silently downloads dependencies in the background on first CLI run:
5+ * 1. @coana-tech/cli
6+ * 2. @cyclonedx/cdxgen
7+ * 3. @socketbin/cli-ai
8+ * 4. Python + socketsecurity (socket-python-cli)
69 *
10+ * Downloads are staggered sequentially to avoid resource contention.
711 * This runs asynchronously and never blocks the main CLI execution.
812 */
913
@@ -14,6 +18,7 @@ import { downloadPackage } from '@socketsecurity/lib/dlx-package'
1418
1519import ENV from '../../constants/env.mts'
1620import { getSocketHomePath } from '../dlx/binary.mts'
21+ import { ensurePython , ensureSocketCli } from '../python/standalone.mts'
1722
1823/**
1924 * Check if a package is already cached by the package manager.
@@ -43,40 +48,46 @@ export function runPreflightDownloads(): void {
4348
4449 // Run asynchronously in the background.
4550 void ( async ( ) => {
46- const downloads : Array < { packageSpec : string ; binaryName ?: string } > = [ ]
51+ try {
52+ // Stagger downloads sequentially to avoid resource contention.
53+ // Order: coana → cdxgen → cli-ai → Python → socketsecurity.
4754
48- // @coana -tech/cli preflight.
49- const coanaVersion = ENV . INLINED_SOCKET_CLI_COANA_VERSION
50- const coanaSpec = `@coana-tech/cli@~${ coanaVersion } `
51- if ( ! isPackageCached ( coanaSpec ) ) {
52- downloads . push ( { packageSpec : coanaSpec , binaryName : 'coana' } )
53- }
55+ // 1. @coana-tech/cli preflight.
56+ const coanaVersion = ENV . INLINED_SOCKET_CLI_COANA_VERSION
57+ const coanaSpec = `@coana-tech/cli@~${ coanaVersion } `
58+ if ( ! isPackageCached ( coanaSpec ) ) {
59+ await downloadPackage ( {
60+ package : coanaSpec ,
61+ binaryName : 'coana' ,
62+ force : false ,
63+ } )
64+ }
5465
55- // @cyclonedx /cdxgen preflight.
56- const cdxgenVersion = ENV . INLINED_SOCKET_CLI_CYCLONEDX_CDXGEN_VERSION
57- const cdxgenSpec = `@cyclonedx/cdxgen@~${ cdxgenVersion } `
58- if ( ! isPackageCached ( cdxgenSpec ) ) {
59- downloads . push ( { packageSpec : cdxgenSpec , binaryName : 'cdxgen' } )
60- }
66+ // 2. @cyclonedx/cdxgen preflight.
67+ const cdxgenVersion = ENV . INLINED_SOCKET_CLI_CYCLONEDX_CDXGEN_VERSION
68+ const cdxgenSpec = `@cyclonedx/cdxgen@~${ cdxgenVersion } `
69+ if ( ! isPackageCached ( cdxgenSpec ) ) {
70+ await downloadPackage ( {
71+ package : cdxgenSpec ,
72+ binaryName : 'cdxgen' ,
73+ force : false ,
74+ } )
75+ }
6176
62- // @socketbin /cli-ai preflight.
63- const cliAiVersion = ENV . INLINED_SOCKET_CLI_AI_VERSION
64- const cliAiSpec = `@socketbin/cli-ai@^${ cliAiVersion } `
65- if ( ! isPackageCached ( cliAiSpec ) ) {
66- downloads . push ( { packageSpec : cliAiSpec , binaryName : 'cli-ai' } )
67- }
77+ // 3. @socketbin/cli-ai preflight.
78+ const cliAiVersion = ENV . INLINED_SOCKET_CLI_AI_VERSION
79+ const cliAiSpec = `@socketbin/cli-ai@^${ cliAiVersion } `
80+ if ( ! isPackageCached ( cliAiSpec ) ) {
81+ await downloadPackage ( {
82+ package : cliAiSpec ,
83+ binaryName : 'cli-ai' ,
84+ force : false ,
85+ } )
86+ }
6887
69- try {
70- // Download in background (fire and forget).
71- await Promise . all (
72- downloads . map ( p =>
73- downloadPackage ( {
74- package : p . packageSpec ,
75- binaryName : p . binaryName ,
76- force : false ,
77- } ) ,
78- ) ,
79- )
88+ // 4. Python + socketsecurity (socket-python-cli) preflight.
89+ const pythonBin = await ensurePython ( )
90+ await ensureSocketCli ( pythonBin )
8091 } catch { }
8192 } ) ( )
8293}
0 commit comments