@socketsecurity/cli-with-sentry 1.1.101 → 1.1.102

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,11 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
-
9
- ### Added
10
8
  - **`socket manifest bazel [beta]`** — Generate Bazel JVM SBOM manifests by running `bazel query` against discovered Maven repos in a Bazel workspace. Closes the inline-Maven-declaration gap that lockfile-only parsing misses for repos like envoy, ray, tensorflow, tink-java, and or-tools. Auto-detects Bzlmod and legacy `WORKSPACE`.
11
9
  - **`socket scan create --auto-manifest`** now covers Bazel workspaces in addition to Gradle/Scala/Kotlin/Conda. Repos with `MODULE.bazel`, `WORKSPACE`, or `WORKSPACE.bazel` are detected automatically and their Maven dependencies extracted as part of the standard scan-create flow.
12
10
 
11
+ ## [1.1.98](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.98) - 2026-05-22
12
+
13
+ ### Added
14
+ - **`socket manifest gradle --facts [beta]`** (and its `socket manifest kotlin --facts` alias) — Emit a `.socket.facts.json` dependency graph from a Gradle build, consumable by `socket scan create --reach` as pregenerated SBOM input for Tier 1 reachability. Toggle also exposed via the `socket manifest setup` wizard for use with `--auto-manifest`.
15
+
16
+ ### Changed
17
+ - Updated the Coana CLI to v `15.3.8`.
18
+
13
19
  ## [1.1.101](https://github.com/SocketDev/socket-cli/releases/tag/v1.1.101) - 2026-05-22
14
20
 
15
21
  ### Changed
package/dist/cli.js CHANGED
@@ -1763,14 +1763,16 @@ async function performReachabilityAnalysis(options) {
1763
1763
  return sockSdkCResult;
1764
1764
  }
1765
1765
  const sockSdk = sockSdkCResult.data;
1766
-
1767
- // Exclude any .socket.facts.json files that happen to be in the scan
1768
- // folder before the analysis was run.
1769
- const filepathsToUpload = packagePaths.filter(p => path.basename(p).toLowerCase() !== constants.default.DOT_SOCKET_DOT_FACTS_JSON);
1770
1766
  spinner?.start('Uploading manifests for reachability analysis...');
1771
1767
 
1772
1768
  // Ensure uploaded manifest files are relative to analysis target as coana resolves SBOM manifest files relative to this path
1773
- const uploadCResult = await utils.handleApiCall(sockSdk.uploadManifestFiles(orgSlug, filepathsToUpload, path.resolve(cwd, analysisTarget)), {
1769
+ // NOTE: previously stripped any `.socket.facts.json` from packagePaths
1770
+ // here to avoid uploading leftover post-reachability output. With the
1771
+ // producer flow (`socket manifest gradle --facts`) those files are
1772
+ // legitimate INPUT to compute-artifacts, so we now upload them. Stale
1773
+ // facts files are cleaned up downstream — see the post-success
1774
+ // deletion in handle-create-new-scan.mts.
1775
+ const uploadCResult = await utils.handleApiCall(sockSdk.uploadManifestFiles(orgSlug, packagePaths, path.resolve(cwd, analysisTarget)), {
1774
1776
  description: 'upload manifests',
1775
1777
  spinner
1776
1778
  });
@@ -3057,6 +3059,130 @@ async function extractBazelToMaven(opts) {
3057
3059
  }
3058
3060
  }
3059
3061
 
3062
+ async function convertGradleToFacts({
3063
+ bin,
3064
+ cwd,
3065
+ gradleOpts,
3066
+ verbose
3067
+ }) {
3068
+ const rBin = path.resolve(cwd, bin);
3069
+ const binExists = fs$1.existsSync(rBin);
3070
+ const cwdExists = fs$1.existsSync(cwd);
3071
+ logger.logger.group('gradle2facts:');
3072
+ logger.logger.info(`- executing: \`${rBin}\``);
3073
+ if (!binExists) {
3074
+ logger.logger.warn(`Warning: It appears the executable could not be found. An error might be printed later because of that.`);
3075
+ }
3076
+ logger.logger.info(`- src dir: \`${cwd}\``);
3077
+ if (!cwdExists) {
3078
+ logger.logger.warn(`Warning: It appears the src dir could not be found. An error might be printed later because of that.`);
3079
+ }
3080
+ logger.logger.groupEnd();
3081
+ try {
3082
+ // The init script is bundled alongside the existing pom-generating one.
3083
+ // See .config/rollup.dist.config.mjs:copySocketFactsInitGradle.
3084
+ const initLocation = path.join(constants.default.distPath, 'socket-facts.init.gradle');
3085
+ const commandArgs = ['--init-script', initLocation, ...gradleOpts, 'socketFacts'];
3086
+ if (verbose) {
3087
+ logger.logger.log('[VERBOSE] Executing:', [bin], ', args:', commandArgs);
3088
+ }
3089
+ logger.logger.log(`Generating Socket facts from \`${bin}\` on \`${cwd}\` ...`);
3090
+ const output = await execGradle$1(rBin, commandArgs, cwd, verbose);
3091
+ if (output.code) {
3092
+ process.exitCode = 1;
3093
+ logger.logger.fail(`Gradle exited with exit code ${output.code}`);
3094
+ if (!verbose) {
3095
+ logger.logger.group('stderr:');
3096
+ logger.logger.error(output.stderr);
3097
+ logger.logger.groupEnd();
3098
+ }
3099
+ return;
3100
+ }
3101
+ logger.logger.success('Executed gradle successfully');
3102
+ if (verbose) {
3103
+ // Output already streamed; the "Reported exports:" summary lines were
3104
+ // visible inline. No need to repeat them from a captured stdout.
3105
+ logger.logger.log('');
3106
+ logger.logger.log('Next step is to generate a Scan by running the `socket scan create` command on the same directory.');
3107
+ return;
3108
+ }
3109
+ const exports = Array.from(output.stdout.matchAll(/^Socket facts file written to: (.*)/gm), m => m[1]);
3110
+ if (exports.length) {
3111
+ logger.logger.log('Reported exports:');
3112
+ for (const fn of exports) {
3113
+ logger.logger.log('- ', fn);
3114
+ }
3115
+ } else {
3116
+ // Gradle script may have skipped emission when no resolvable
3117
+ // dependencies were found (see the `components.isEmpty()` branch in
3118
+ // socket-facts.init.gradle). Surface the skip reason if present so
3119
+ // the user understands why nothing was written.
3120
+ const skipMatch = output.stdout.match(/^\[socket-facts\] no resolvable dependencies.*/m);
3121
+ if (skipMatch) {
3122
+ logger.logger.warn(skipMatch[0]);
3123
+ }
3124
+ }
3125
+ logger.logger.log('');
3126
+ logger.logger.log('Next step is to generate a Scan by running the `socket scan create` command on the same directory.');
3127
+ } catch (e) {
3128
+ process.exitCode = 1;
3129
+ logger.logger.fail('There was an unexpected error while generating Socket facts' + (verbose ? '' : ' (use --verbose for details)'));
3130
+ if (verbose) {
3131
+ logger.logger.group('[VERBOSE] error:');
3132
+ logger.logger.log(e);
3133
+ logger.logger.groupEnd();
3134
+ }
3135
+ }
3136
+ }
3137
+ async function execGradle$1(bin, commandArgs, cwd, verbose) {
3138
+ // When verbose, stream gradle stdout/stderr directly to the user's
3139
+ // terminal — no spinner, no capture. The trade-off is that the post-run
3140
+ // "Reported exports:" summary is skipped (the lines were already visible
3141
+ // inline). For huge builds where the user wants to see progress, this is
3142
+ // the right default. Non-verbose runs still get the spinner + summary.
3143
+ if (verbose) {
3144
+ logger.logger.info('(Running gradle with output streaming. This can take a while.)');
3145
+ const output = await spawn.spawn(bin, commandArgs, {
3146
+ cwd,
3147
+ stdio: 'inherit'
3148
+ });
3149
+ return {
3150
+ code: output.code,
3151
+ stdout: '',
3152
+ stderr: ''
3153
+ };
3154
+ }
3155
+ const {
3156
+ spinner
3157
+ } = constants.default;
3158
+ let pass = false;
3159
+ try {
3160
+ logger.logger.info('(Running gradle can take a while, depending on the size of the project)');
3161
+ logger.logger.info('(No live output. Pass --verbose to stream gradle output instead.)');
3162
+ spinner.start(`Running gradlew...`);
3163
+ const output = await spawn.spawn(bin, commandArgs, {
3164
+ cwd
3165
+ });
3166
+ pass = true;
3167
+ const {
3168
+ code,
3169
+ stderr,
3170
+ stdout
3171
+ } = output;
3172
+ return {
3173
+ code,
3174
+ stdout,
3175
+ stderr
3176
+ };
3177
+ } finally {
3178
+ if (pass) {
3179
+ spinner.successAndStop('Gracefully completed gradlew execution.');
3180
+ } else {
3181
+ spinner.failAndStop('There was an error while trying to run gradlew.');
3182
+ }
3183
+ }
3184
+ }
3185
+
3060
3186
  async function convertGradleToMaven({
3061
3187
  bin,
3062
3188
  cwd,
@@ -3093,16 +3219,10 @@ async function convertGradleToMaven({
3093
3219
  logger.logger.log('[VERBOSE] Executing:', [bin], ', args:', commandArgs);
3094
3220
  }
3095
3221
  logger.logger.log(`Converting gradle to maven from \`${bin}\` on \`${cwd}\` ...`);
3096
- const output = await execGradleWithSpinner(rBin, commandArgs, cwd);
3097
- if (verbose) {
3098
- logger.logger.group('[VERBOSE] gradle stdout:');
3099
- logger.logger.log(output);
3100
- logger.logger.groupEnd();
3101
- }
3222
+ const output = await execGradle(rBin, commandArgs, cwd, verbose);
3102
3223
  if (output.code) {
3103
3224
  process.exitCode = 1;
3104
3225
  logger.logger.fail(`Gradle exited with exit code ${output.code}`);
3105
- // (In verbose mode, stderr was printed above, no need to repeat it)
3106
3226
  if (!verbose) {
3107
3227
  logger.logger.group('stderr:');
3108
3228
  logger.logger.error(output.stderr);
@@ -3111,6 +3231,13 @@ async function convertGradleToMaven({
3111
3231
  return;
3112
3232
  }
3113
3233
  logger.logger.success('Executed gradle successfully');
3234
+ if (verbose) {
3235
+ // Output already streamed; "POM file copied to:" lines were visible
3236
+ // inline. Skip the captured-stdout summary.
3237
+ logger.logger.log('');
3238
+ logger.logger.log('Next step is to generate a Scan by running the `socket scan create` command on the same directory');
3239
+ return;
3240
+ }
3114
3241
  logger.logger.log('Reported exports:');
3115
3242
  output.stdout.replace(/^POM file copied to: (.*)/gm, (_all, fn) => {
3116
3243
  logger.logger.log('- ', fn);
@@ -3128,20 +3255,32 @@ async function convertGradleToMaven({
3128
3255
  }
3129
3256
  }
3130
3257
  }
3131
- async function execGradleWithSpinner(bin, commandArgs, cwd) {
3258
+ async function execGradle(bin, commandArgs, cwd, verbose) {
3259
+ // When verbose, stream gradle stdout/stderr directly to the user's
3260
+ // terminal — no spinner, no capture. The trade-off is that the post-run
3261
+ // "Reported exports:" summary is skipped (the lines were already visible
3262
+ // inline). Non-verbose runs still get the spinner + summary.
3263
+ if (verbose) {
3264
+ logger.logger.info('(Running gradle with output streaming. This can take a while.)');
3265
+ const output = await spawn.spawn(bin, commandArgs, {
3266
+ cwd,
3267
+ stdio: 'inherit'
3268
+ });
3269
+ return {
3270
+ code: output.code,
3271
+ stdout: '',
3272
+ stderr: ''
3273
+ };
3274
+ }
3132
3275
  const {
3133
3276
  spinner
3134
3277
  } = constants.default;
3135
3278
  let pass = false;
3136
3279
  try {
3137
- logger.logger.info('(Running gradle can take a while, it depends on how long gradlew has to run)');
3138
- logger.logger.info('(It will show no output, you can use --verbose to see its output)');
3280
+ logger.logger.info('(Running gradle can take a while, depending on the size of the project)');
3281
+ logger.logger.info('(No live output. Pass --verbose to stream gradle output instead.)');
3139
3282
  spinner.start(`Running gradlew...`);
3140
3283
  const output = await spawn.spawn(bin, commandArgs, {
3141
- // We can pipe the output through to have the user see the result
3142
- // of running gradlew, but then we can't (easily) gather the output
3143
- // to discover the generated files... probably a flag we should allow?
3144
- // stdio: isDebug() ? 'inherit' : undefined,
3145
3284
  cwd
3146
3285
  });
3147
3286
  pass = true;
@@ -3512,8 +3651,7 @@ async function generateAutoManifest({
3512
3651
  });
3513
3652
  }
3514
3653
  if (!sockJson?.defaults?.manifest?.gradle?.disabled && detected.gradle) {
3515
- logger.logger.log('Detected a gradle build (Gradle, Kotlin, Scala), running default gradle generator...');
3516
- await convertGradleToMaven({
3654
+ const gradleArgs = {
3517
3655
  // Note: `gradlew` is more likely to be resolved against cwd.
3518
3656
  // Note: .resolve() won't butcher an absolute path.
3519
3657
  // TODO: `gradlew` (or anything else given) may want to resolve against PATH.
@@ -3521,7 +3659,14 @@ async function generateAutoManifest({
3521
3659
  cwd,
3522
3660
  verbose: Boolean(sockJson.defaults?.manifest?.gradle?.verbose),
3523
3661
  gradleOpts: sockJson.defaults?.manifest?.gradle?.gradleOpts?.split(' ').map(s => s.trim()).filter(Boolean) ?? []
3524
- });
3662
+ };
3663
+ if (sockJson.defaults?.manifest?.gradle?.facts) {
3664
+ logger.logger.log('Detected a gradle build (Gradle, Kotlin, Scala), generating Socket facts...');
3665
+ await convertGradleToFacts(gradleArgs);
3666
+ } else {
3667
+ logger.logger.log('Detected a gradle build (Gradle, Kotlin, Scala), running default gradle generator...');
3668
+ await convertGradleToMaven(gradleArgs);
3669
+ }
3525
3670
  }
3526
3671
  if (!sockJson?.defaults?.manifest?.conda?.disabled && detected.conda) {
3527
3672
  logger.logger.log('Detected an environment.yml file, running default Conda generator...');
@@ -3575,19 +3720,11 @@ function getCdxSpdxPatterns(supportedFiles) {
3575
3720
  }
3576
3721
  return patterns;
3577
3722
  }
3578
- function filterToCdxSpdxAndFactsFiles(filepaths, supportedFiles) {
3723
+ function filterToCdxSpdxOnly(filepaths, supportedFiles) {
3579
3724
  const patterns = getCdxSpdxPatterns(supportedFiles);
3580
- return filepaths.filter(filepath => {
3581
- const basename = path.basename(filepath).toLowerCase();
3582
- // Include .socket.facts.json files.
3583
- if (basename === constants.default.DOT_SOCKET_DOT_FACTS_JSON) {
3584
- return true;
3585
- }
3586
- // Include CDX and SPDX files.
3587
- return vendor.micromatchExports.some(filepath, patterns, {
3588
- nocase: true
3589
- });
3590
- });
3725
+ return filepaths.filter(filepath => vendor.micromatchExports.some(filepath, patterns, {
3726
+ nocase: true
3727
+ }));
3591
3728
  }
3592
3729
  async function handleCreateNewScan({
3593
3730
  autoManifest,
@@ -3706,6 +3843,7 @@ async function handleCreateNewScan({
3706
3843
  }
3707
3844
  let scanPaths = packagePaths;
3708
3845
  let tier1ReachabilityScanId;
3846
+ let reachabilityReport;
3709
3847
 
3710
3848
  // If reachability is enabled, perform reachability analysis.
3711
3849
  if (reach.runReachabilityAnalysis) {
@@ -3735,14 +3873,14 @@ async function handleCreateNewScan({
3735
3873
  return;
3736
3874
  }
3737
3875
  logger.logger.success('Reachability analysis completed successfully');
3738
- const reachabilityReport = reachResult.data?.reachabilityReport;
3876
+ reachabilityReport = reachResult.data?.reachabilityReport;
3739
3877
 
3740
3878
  // Ensure the .socket.facts.json isn't duplicated in case it happened
3741
3879
  // to be in the scan folder before the analysis was run.
3742
- const filteredPackagePaths = packagePaths.filter(p => path.basename(p).toLowerCase() !== constants.default.DOT_SOCKET_DOT_FACTS_JSON);
3880
+ const filteredPackagePaths = packagePaths.filter(p => path.basename(p) !== constants.default.DOT_SOCKET_DOT_FACTS_JSON);
3743
3881
 
3744
3882
  // When using pregenerated SBOMs only, filter to CDX/SPDX files.
3745
- const pathsForScan = reach.reachUseOnlyPregeneratedSboms ? filterToCdxSpdxAndFactsFiles(filteredPackagePaths, supportedFiles) : filteredPackagePaths;
3883
+ const pathsForScan = reach.reachUseOnlyPregeneratedSboms ? filterToCdxSpdxOnly(filteredPackagePaths, supportedFiles) : filteredPackagePaths;
3746
3884
  scanPaths = [...pathsForScan, ...(reachabilityReport ? [reachabilityReport] : [])];
3747
3885
  tier1ReachabilityScanId = reachResult.data?.tier1ReachabilityScanId;
3748
3886
  }
@@ -3778,6 +3916,22 @@ async function handleCreateNewScan({
3778
3916
  if (reach && scanId && tier1ReachabilityScanId) {
3779
3917
  await finalizeTier1Scan(tier1ReachabilityScanId, scanId);
3780
3918
  }
3919
+
3920
+ // On a successful scan, clean up the `.socket.facts.json` coana wrote at
3921
+ // the path we instructed it to write to (via `--socket-mode`). Failed
3922
+ // scans leave the file in place for debugging. Producer-written files
3923
+ // (e.g. from `socket manifest gradle --facts`) are NOT touched here —
3924
+ // those are user-owned input that the user can clean up themselves; in
3925
+ // the --reach path coana overwrites that file with its enriched output
3926
+ // anyway, so it's the same path that gets removed.
3927
+ if (fullScanCResult.ok && scanId && reachabilityReport) {
3928
+ try {
3929
+ await fs.unlink(path.resolve(cwd, reachabilityReport));
3930
+ require$$9.debugFn('notice', `[socket-facts] removed coana output after successful scan: ${reachabilityReport}`);
3931
+ } catch {
3932
+ // Best-effort — file may already be gone or unwritable.
3933
+ }
3934
+ }
3781
3935
  if (report && fullScanCResult.ok) {
3782
3936
  if (scanId) {
3783
3937
  await handleScanReport({
@@ -7583,6 +7737,10 @@ const config$b = {
7583
7737
  type: 'string',
7584
7738
  description: 'Location of gradlew binary to use, default: CWD/gradlew'
7585
7739
  },
7740
+ facts: {
7741
+ type: 'boolean',
7742
+ description: 'Emit a Socket facts JSON file (`.socket.facts.json`) describing the resolved dependency graph instead of generating `pom.xml` files'
7743
+ },
7586
7744
  gradleOpts: {
7587
7745
  type: 'string',
7588
7746
  description: 'Additional options to pass on to ./gradlew, see `./gradlew --help`'
@@ -7655,6 +7813,7 @@ async function run$C(argv, importMeta, {
7655
7813
  require$$9.debugFn('inspect', `override: ${constants.SOCKET_JSON} gradle`, sockJson?.defaults?.manifest?.gradle);
7656
7814
  let {
7657
7815
  bin,
7816
+ facts,
7658
7817
  gradleOpts,
7659
7818
  verbose
7660
7819
  } = cli.flags;
@@ -7684,6 +7843,14 @@ async function run$C(argv, importMeta, {
7684
7843
  verbose = false;
7685
7844
  }
7686
7845
  }
7846
+ if (facts === undefined) {
7847
+ if (sockJson.defaults?.manifest?.gradle?.facts !== undefined) {
7848
+ facts = sockJson.defaults?.manifest?.gradle?.facts;
7849
+ logger.logger.info(`Using default --facts from ${constants.SOCKET_JSON}:`, facts);
7850
+ } else {
7851
+ facts = false;
7852
+ }
7853
+ }
7687
7854
  if (verbose) {
7688
7855
  logger.logger.group('- ', parentName, config$b.commandName, ':');
7689
7856
  logger.logger.group('- flags:', cli.flags);
@@ -7715,10 +7882,20 @@ async function run$C(argv, importMeta, {
7715
7882
  logger.logger.log(constants.default.DRY_RUN_BAILING_NOW);
7716
7883
  return;
7717
7884
  }
7885
+ const parsedGradleOpts = String(gradleOpts || '').split(' ').map(s => s.trim()).filter(Boolean);
7886
+ if (facts) {
7887
+ await convertGradleToFacts({
7888
+ bin: String(bin),
7889
+ cwd,
7890
+ gradleOpts: parsedGradleOpts,
7891
+ verbose: Boolean(verbose)
7892
+ });
7893
+ return;
7894
+ }
7718
7895
  await convertGradleToMaven({
7719
7896
  bin: String(bin),
7720
7897
  cwd,
7721
- gradleOpts: String(gradleOpts || '').split(' ').map(s => s.trim()).filter(Boolean),
7898
+ gradleOpts: parsedGradleOpts,
7722
7899
  verbose: Boolean(verbose)
7723
7900
  });
7724
7901
  }
@@ -7738,6 +7915,10 @@ const config$a = {
7738
7915
  type: 'string',
7739
7916
  description: 'Location of gradlew binary to use, default: CWD/gradlew'
7740
7917
  },
7918
+ facts: {
7919
+ type: 'boolean',
7920
+ description: 'Emit a Socket facts JSON file (`.socket.facts.json`) describing the resolved dependency graph instead of generating `pom.xml` files'
7921
+ },
7741
7922
  gradleOpts: {
7742
7923
  type: 'string',
7743
7924
  description: 'Additional options to pass on to ./gradlew, see `./gradlew --help`'
@@ -7810,6 +7991,7 @@ async function run$B(argv, importMeta, {
7810
7991
  require$$9.debugFn('inspect', `override: ${constants.SOCKET_JSON} gradle`, sockJson?.defaults?.manifest?.gradle);
7811
7992
  let {
7812
7993
  bin,
7994
+ facts,
7813
7995
  gradleOpts,
7814
7996
  verbose
7815
7997
  } = cli.flags;
@@ -7839,6 +8021,14 @@ async function run$B(argv, importMeta, {
7839
8021
  verbose = false;
7840
8022
  }
7841
8023
  }
8024
+ if (facts === undefined) {
8025
+ if (sockJson.defaults?.manifest?.gradle?.facts !== undefined) {
8026
+ facts = sockJson.defaults?.manifest?.gradle?.facts;
8027
+ logger.logger.info(`Using default --facts from ${constants.SOCKET_JSON}:`, facts);
8028
+ } else {
8029
+ facts = false;
8030
+ }
8031
+ }
7842
8032
  if (verbose) {
7843
8033
  logger.logger.group('- ', parentName, config$a.commandName, ':');
7844
8034
  logger.logger.group('- flags:', cli.flags);
@@ -7870,10 +8060,20 @@ async function run$B(argv, importMeta, {
7870
8060
  logger.logger.log(constants.default.DRY_RUN_BAILING_NOW);
7871
8061
  return;
7872
8062
  }
8063
+ const parsedGradleOpts = String(gradleOpts || '').split(' ').map(s => s.trim()).filter(Boolean);
8064
+ if (facts) {
8065
+ await convertGradleToFacts({
8066
+ bin: String(bin),
8067
+ cwd,
8068
+ gradleOpts: parsedGradleOpts,
8069
+ verbose: Boolean(verbose)
8070
+ });
8071
+ return;
8072
+ }
7873
8073
  await convertGradleToMaven({
7874
8074
  bin: String(bin),
7875
8075
  cwd,
7876
- gradleOpts: String(gradleOpts || '').split(' ').map(s => s.trim()).filter(Boolean),
8076
+ gradleOpts: parsedGradleOpts,
7877
8077
  verbose: Boolean(verbose)
7878
8078
  });
7879
8079
  }
@@ -8291,6 +8491,14 @@ async function setupGradle(config) {
8291
8491
  } else {
8292
8492
  delete config.gradleOpts;
8293
8493
  }
8494
+ const facts = await askForFactsFlag(config.facts);
8495
+ if (facts === undefined) {
8496
+ return canceledByUser$1();
8497
+ } else if (facts === 'yes' || facts === 'no') {
8498
+ config.facts = facts === 'yes';
8499
+ } else {
8500
+ delete config.facts;
8501
+ }
8294
8502
  const verbose = await askForVerboseFlag(config.verbose);
8295
8503
  if (verbose === undefined) {
8296
8504
  return canceledByUser$1();
@@ -8439,6 +8647,25 @@ async function askForVerboseFlag(current) {
8439
8647
  default: current === true ? 'yes' : current === false ? 'no' : ''
8440
8648
  });
8441
8649
  }
8650
+ async function askForFactsFlag(current) {
8651
+ return await prompts.select({
8652
+ message: '(--facts) Emit a Socket facts JSON file instead of generating pom.xml?',
8653
+ choices: [{
8654
+ name: 'no',
8655
+ value: 'no',
8656
+ description: 'Generate pom.xml files (default behavior)'
8657
+ }, {
8658
+ name: 'yes',
8659
+ value: 'yes',
8660
+ description: 'Generate a .socket.facts.json file describing the resolved dependency graph'
8661
+ }, {
8662
+ name: '(leave default)',
8663
+ value: '',
8664
+ description: 'Do not store a setting for this'
8665
+ }],
8666
+ default: current === true ? 'yes' : current === false ? 'no' : ''
8667
+ });
8668
+ }
8442
8669
  function canceledByUser$1() {
8443
8670
  logger.logger.log('');
8444
8671
  logger.logger.info('User canceled');
@@ -17255,5 +17482,5 @@ process.on('unhandledRejection', async (reason, promise) => {
17255
17482
  // eslint-disable-next-line n/no-process-exit
17256
17483
  process.exit(1);
17257
17484
  });
17258
- //# debugId=70895ae2-8c82-49e4-a1fb-3cbc0ccb2c57
17485
+ //# debugId=d1f4c235-f351-4ff4-9652-79299095458b
17259
17486
  //# sourceMappingURL=cli.js.map