@socketsecurity/cli-with-sentry 1.1.50 → 1.1.52

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/cli.js +213 -554
  3. package/dist/cli.js.map +1 -1
  4. package/dist/constants.js +6 -4
  5. package/dist/constants.js.map +1 -1
  6. package/dist/tsconfig.dts.tsbuildinfo +1 -1
  7. package/dist/types/commands/ci/fetch-default-org-slug.d.mts +1 -1
  8. package/dist/types/commands/ci/fetch-default-org-slug.d.mts.map +1 -1
  9. package/dist/types/commands/ci/handle-ci.d.mts.map +1 -1
  10. package/dist/types/commands/fix/cmd-fix.d.mts.map +1 -1
  11. package/dist/types/commands/fix/coana-fix.d.mts.map +1 -1
  12. package/dist/types/commands/fix/handle-fix.d.mts +6 -2
  13. package/dist/types/commands/fix/handle-fix.d.mts.map +1 -1
  14. package/dist/types/commands/fix/types.d.mts +1 -0
  15. package/dist/types/commands/fix/types.d.mts.map +1 -1
  16. package/dist/types/commands/organization/fetch-organization-list.d.mts +1 -0
  17. package/dist/types/commands/organization/fetch-organization-list.d.mts.map +1 -1
  18. package/dist/types/commands/patch/cmd-patch.d.mts +1 -1
  19. package/dist/types/commands/patch/cmd-patch.d.mts.map +1 -1
  20. package/dist/types/commands/scan/cmd-scan-create.d.mts.map +1 -1
  21. package/dist/types/commands/scan/cmd-scan-reach.d.mts.map +1 -1
  22. package/dist/types/commands/scan/fetch-supported-scan-file-names.d.mts +1 -0
  23. package/dist/types/commands/scan/fetch-supported-scan-file-names.d.mts.map +1 -1
  24. package/dist/types/commands/scan/perform-reachability-analysis.d.mts +1 -0
  25. package/dist/types/commands/scan/perform-reachability-analysis.d.mts.map +1 -1
  26. package/dist/types/commands/scan/reachability-flags.d.mts.map +1 -1
  27. package/dist/types/commands.d.mts +1 -1
  28. package/dist/types/constants.d.mts +1 -0
  29. package/dist/types/constants.d.mts.map +1 -1
  30. package/dist/types/utils/api.d.mts +1 -0
  31. package/dist/types/utils/api.d.mts.map +1 -1
  32. package/dist/types/utils/config.d.mts +6 -0
  33. package/dist/types/utils/config.d.mts.map +1 -1
  34. package/dist/types/utils/editable-json.d.mts +63 -0
  35. package/dist/types/utils/editable-json.d.mts.map +1 -0
  36. package/dist/types/utils/meow-with-subcommands.d.mts.map +1 -1
  37. package/dist/types/utils/package-environment.d.mts.map +1 -1
  38. package/dist/utils.js +512 -67
  39. package/dist/utils.js.map +1 -1
  40. package/dist/vendor.js +13495 -3663
  41. package/package.json +3 -2
  42. package/dist/types/commands/patch/handle-patch.d.mts +0 -12
  43. package/dist/types/commands/patch/handle-patch.d.mts.map +0 -1
  44. package/dist/types/commands/patch/manifest-schema.d.mts +0 -34
  45. package/dist/types/commands/patch/manifest-schema.d.mts.map +0 -1
  46. package/dist/types/commands/patch/output-patch-result.d.mts +0 -5
  47. package/dist/types/commands/patch/output-patch-result.d.mts.map +0 -1
package/dist/utils.js CHANGED
@@ -16,9 +16,9 @@ var path = require('node:path');
16
16
  var regexps = require('../external/@socketsecurity/registry/lib/regexps');
17
17
  var prompts = require('../external/@socketsecurity/registry/lib/prompts');
18
18
  var spawn = require('../external/@socketsecurity/registry/lib/spawn');
19
- var fs = require('../external/@socketsecurity/registry/lib/fs');
19
+ var fs$1 = require('../external/@socketsecurity/registry/lib/fs');
20
20
  var require$$5 = require('node:module');
21
- var fs$1 = require('node:fs');
21
+ var fs = require('node:fs');
22
22
  var require$$13 = require('../external/@socketsecurity/registry/lib/url');
23
23
  var agent = require('../external/@socketsecurity/registry/lib/agent');
24
24
  var bin = require('../external/@socketsecurity/registry/lib/bin');
@@ -27,6 +27,7 @@ var require$$0$1 = require('node:url');
27
27
  var globs = require('../external/@socketsecurity/registry/lib/globs');
28
28
  var streams = require('../external/@socketsecurity/registry/lib/streams');
29
29
  var promises = require('node:timers/promises');
30
+ var require$$1 = require('node:util');
30
31
  var os = require('node:os');
31
32
  var process$1 = require('node:process');
32
33
  var require$$0 = require('node:crypto');
@@ -163,6 +164,324 @@ function debugGit(operation, success, details) {
163
164
  }
164
165
  }
165
166
 
167
+ /**
168
+ * @fileoverview EditableJson utility for non-destructive JSON file manipulation.
169
+ * Preserves formatting (indentation and line endings) when updating JSON files.
170
+ * This is a standalone implementation copied from @socketsecurity/lib/json/edit.
171
+ */
172
+
173
+
174
+ // Symbols used to store formatting metadata in JSON objects.
175
+ const INDENT_SYMBOL = Symbol.for('indent');
176
+ const NEWLINE_SYMBOL = Symbol.for('newline');
177
+
178
+ /**
179
+ * Formatting metadata for JSON files.
180
+ */
181
+
182
+ /**
183
+ * Options for saving editable JSON files.
184
+ */
185
+
186
+ /**
187
+ * Detect indentation from a JSON string.
188
+ * Supports space-based indentation (returns count) or mixed indentation (returns string).
189
+ */
190
+ function detectIndent(json) {
191
+ const match = json.match(/^[{[][\r\n]+(\s+)/m);
192
+ if (!match || !match[1]) {
193
+ return 2;
194
+ }
195
+ const indent = match[1];
196
+ if (/^ +$/.test(indent)) {
197
+ return indent.length;
198
+ }
199
+ return indent;
200
+ }
201
+
202
+ /**
203
+ * Detect newline character(s) from a JSON string.
204
+ * Supports LF (\n) and CRLF (\r\n) line endings.
205
+ */
206
+ function detectNewline(json) {
207
+ const match = json.match(/\r?\n/);
208
+ return match ? match[0] : '\n';
209
+ }
210
+
211
+ /**
212
+ * Sort object keys alphabetically.
213
+ * Creates a new object with sorted keys (does not mutate input).
214
+ */
215
+ function sortKeys(obj) {
216
+ const sorted = {
217
+ __proto__: null
218
+ };
219
+ const keys = Object.keys(obj).sort();
220
+ for (const key of keys) {
221
+ sorted[key] = obj[key];
222
+ }
223
+ return sorted;
224
+ }
225
+
226
+ /**
227
+ * Stringify JSON with specific formatting.
228
+ * Applies indentation and line ending preferences.
229
+ */
230
+ function stringifyWithFormatting(content, formatting) {
231
+ const {
232
+ indent,
233
+ newline
234
+ } = formatting;
235
+ const format = indent === undefined || indent === null ? ' ' : indent;
236
+ const eol = newline === undefined || newline === null ? '\n' : newline;
237
+ return `${JSON.stringify(content, undefined, format)}\n`.replace(/\n/g, eol);
238
+ }
239
+
240
+ /**
241
+ * Strip formatting symbols from content object.
242
+ * Removes Symbol.for('indent') and Symbol.for('newline') from the object.
243
+ */
244
+ function stripFormattingSymbols(content) {
245
+ const {
246
+ [INDENT_SYMBOL]: _indent,
247
+ [NEWLINE_SYMBOL]: _newline,
248
+ ...rest
249
+ } = content;
250
+ return rest;
251
+ }
252
+
253
+ /**
254
+ * Extract formatting from content object that has symbol-based metadata.
255
+ */
256
+ function getFormattingFromContent(content) {
257
+ const indent = content[INDENT_SYMBOL];
258
+ const newline = content[NEWLINE_SYMBOL];
259
+ return {
260
+ indent: indent === undefined || indent === null ? 2 : indent,
261
+ newline: newline === undefined || newline === null ? '\n' : newline
262
+ };
263
+ }
264
+
265
+ /**
266
+ * Determine if content should be saved based on changes and options.
267
+ */
268
+ function shouldSave(currentContent, originalContent, originalFileContent, options = {}) {
269
+ const {
270
+ ignoreWhitespace = false,
271
+ sort = false
272
+ } = options;
273
+ const content = stripFormattingSymbols(currentContent);
274
+ const sortedContent = sort ? sortKeys(content) : content;
275
+ const origContent = originalContent ? stripFormattingSymbols(originalContent) : {};
276
+ if (ignoreWhitespace) {
277
+ return !require$$1.isDeepStrictEqual(sortedContent, origContent);
278
+ }
279
+ const formatting = getFormattingFromContent(currentContent);
280
+ const newFileContent = stringifyWithFormatting(sortedContent, formatting);
281
+ return newFileContent.trim() !== originalFileContent.trim();
282
+ }
283
+
284
+ /**
285
+ * Retry write operation with exponential backoff for file system issues.
286
+ */
287
+ async function retryWrite(filepath, content, retries = 3, baseDelay = 10) {
288
+ for (let attempt = 0; attempt <= retries; attempt++) {
289
+ try {
290
+ // eslint-disable-next-line no-await-in-loop
291
+ await fs.promises.writeFile(filepath, content);
292
+ if (process.platform === 'win32') {
293
+ // eslint-disable-next-line no-await-in-loop
294
+ await promises.setTimeout(50);
295
+ let accessRetries = 0;
296
+ const maxAccessRetries = 5;
297
+ while (accessRetries < maxAccessRetries) {
298
+ try {
299
+ // eslint-disable-next-line no-await-in-loop
300
+ await fs.promises.access(filepath);
301
+ // eslint-disable-next-line no-await-in-loop
302
+ await promises.setTimeout(10);
303
+ break;
304
+ } catch {
305
+ const delay = 20 * (accessRetries + 1);
306
+ // eslint-disable-next-line no-await-in-loop
307
+ await promises.setTimeout(delay);
308
+ accessRetries++;
309
+ }
310
+ }
311
+ }
312
+ return;
313
+ } catch (err) {
314
+ const isLastAttempt = attempt === retries;
315
+ const isRetriableError = err instanceof Error && 'code' in err && (err.code === 'EPERM' || err.code === 'EBUSY' || err.code === 'ENOENT');
316
+ if (!isRetriableError || isLastAttempt) {
317
+ throw err;
318
+ }
319
+ const delay = baseDelay * 2 ** attempt;
320
+ // eslint-disable-next-line no-await-in-loop
321
+ await promises.setTimeout(delay);
322
+ }
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Parse JSON string.
328
+ */
329
+ function parseJson(content) {
330
+ return JSON.parse(content);
331
+ }
332
+
333
+ /**
334
+ * Read file with retry logic for file system issues.
335
+ */
336
+ async function readFile(filepath) {
337
+ const maxRetries = process.platform === 'win32' ? 5 : 1;
338
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
339
+ try {
340
+ // eslint-disable-next-line no-await-in-loop
341
+ return await fs.promises.readFile(filepath, 'utf8');
342
+ } catch (err) {
343
+ const isLastAttempt = attempt === maxRetries;
344
+ const isEnoent = err instanceof Error && 'code' in err && err.code === 'ENOENT';
345
+ if (!isEnoent || isLastAttempt) {
346
+ throw err;
347
+ }
348
+ const delay = process.platform === 'win32' ? 50 * (attempt + 1) : 20;
349
+ // eslint-disable-next-line no-await-in-loop
350
+ await promises.setTimeout(delay);
351
+ }
352
+ }
353
+ throw new Error('Unreachable code');
354
+ }
355
+
356
+ /**
357
+ * EditableJson class for non-destructive JSON file manipulation.
358
+ * Preserves formatting when updating JSON files.
359
+ */
360
+ class EditableJson {
361
+ _canSave = true;
362
+ _content = {};
363
+ _path = undefined;
364
+ _readFileContent = '';
365
+ _readFileJson = undefined;
366
+ get content() {
367
+ return this._content;
368
+ }
369
+ get filename() {
370
+ const path = this._path;
371
+ if (!path) {
372
+ return '';
373
+ }
374
+ return path;
375
+ }
376
+ get path() {
377
+ return this._path;
378
+ }
379
+
380
+ /**
381
+ * Create a new JSON file instance.
382
+ */
383
+ create(path) {
384
+ this._path = path;
385
+ this._content = {};
386
+ this._canSave = true;
387
+ return this;
388
+ }
389
+
390
+ /**
391
+ * Initialize from content object (disables saving).
392
+ */
393
+ fromContent(data) {
394
+ this._content = data;
395
+ this._canSave = false;
396
+ return this;
397
+ }
398
+
399
+ /**
400
+ * Initialize from JSON string.
401
+ */
402
+ fromJSON(data) {
403
+ const parsed = parseJson(data);
404
+ const indent = detectIndent(data);
405
+ const newline = detectNewline(data)
406
+ // Use type assertion to allow symbol indexing.
407
+ ;
408
+ parsed[INDENT_SYMBOL] = indent;
409
+ parsed[NEWLINE_SYMBOL] = newline;
410
+ this._content = parsed;
411
+ return this;
412
+ }
413
+
414
+ /**
415
+ * Load JSON file from disk.
416
+ */
417
+ async load(path, create) {
418
+ this._path = path;
419
+ try {
420
+ this._readFileContent = await readFile(this.filename);
421
+ this.fromJSON(this._readFileContent);
422
+ this._readFileJson = parseJson(this._readFileContent);
423
+ } catch (err) {
424
+ if (!create) {
425
+ throw err;
426
+ }
427
+ // File doesn't exist and create is true - initialize empty.
428
+ this._content = {};
429
+ this._readFileContent = '';
430
+ this._readFileJson = undefined;
431
+ this._canSave = true;
432
+ }
433
+ return this;
434
+ }
435
+
436
+ /**
437
+ * Update content with new values.
438
+ */
439
+ update(content) {
440
+ this._content = {
441
+ ...this._content,
442
+ ...content
443
+ };
444
+ return this;
445
+ }
446
+
447
+ /**
448
+ * Save JSON file to disk asynchronously.
449
+ */
450
+ async save(options) {
451
+ if (!this._canSave || this.content === undefined) {
452
+ throw new Error('No file path to save to');
453
+ }
454
+ if (!shouldSave(this._content, this._readFileJson, this._readFileContent, options)) {
455
+ return false;
456
+ }
457
+ const content = stripFormattingSymbols(this._content);
458
+ const sortedContent = options?.sort ? sortKeys(content) : content;
459
+ const formatting = getFormattingFromContent(this._content);
460
+ const fileContent = stringifyWithFormatting(sortedContent, formatting);
461
+ await retryWrite(this.filename, fileContent);
462
+ this._readFileContent = fileContent;
463
+ this._readFileJson = parseJson(fileContent);
464
+ return true;
465
+ }
466
+
467
+ /**
468
+ * Check if save will occur based on current changes.
469
+ */
470
+ willSave(options) {
471
+ if (!this._canSave || this.content === undefined) {
472
+ return false;
473
+ }
474
+ return shouldSave(this._content, this._readFileJson, this._readFileContent, options);
475
+ }
476
+ }
477
+
478
+ /**
479
+ * Get the EditableJson class for JSON file manipulation.
480
+ */
481
+ function getEditableJsonClass() {
482
+ return EditableJson;
483
+ }
484
+
166
485
  /**
167
486
  * Error utilities for Socket CLI.
168
487
  * Provides consistent error handling, formatting, and message extraction.
@@ -307,14 +626,15 @@ function getConfigValues() {
307
626
  socketAppDataPath
308
627
  } = constants.default;
309
628
  if (socketAppDataPath) {
310
- const raw = fs.safeReadFileSync(socketAppDataPath);
629
+ const configFilePath = path.join(socketAppDataPath, 'config.json');
630
+ const raw = fs$1.safeReadFileSync(configFilePath);
311
631
  if (raw) {
312
632
  try {
313
633
  Object.assign(_cachedConfig, JSON.parse(Buffer.from(raw, 'base64').toString()));
314
- debugConfig(socketAppDataPath, true);
634
+ debugConfig(configFilePath, true);
315
635
  } catch (e) {
316
- logger.logger.warn(`Failed to parse config at ${socketAppDataPath}`);
317
- debugConfig(socketAppDataPath, false, e);
636
+ logger.logger.warn(`Failed to parse config at ${configFilePath}`);
637
+ debugConfig(configFilePath, false, e);
318
638
  }
319
639
  // Normalize apiKey to apiToken and persist it.
320
640
  // This is a one time migration per user.
@@ -324,7 +644,7 @@ function getConfigValues() {
324
644
  updateConfigValue(constants.CONFIG_KEY_API_TOKEN, token);
325
645
  }
326
646
  } else {
327
- fs$1.mkdirSync(path.dirname(socketAppDataPath), {
647
+ fs.mkdirSync(socketAppDataPath, {
328
648
  recursive: true
329
649
  });
330
650
  }
@@ -353,10 +673,10 @@ function findSocketYmlSync(dir = process.cwd()) {
353
673
  let prevDir = null;
354
674
  while (dir !== prevDir) {
355
675
  let ymlPath = path.join(dir, constants.SOCKET_YML);
356
- let yml = fs.safeReadFileSync(ymlPath);
676
+ let yml = fs$1.safeReadFileSync(ymlPath);
357
677
  if (yml === undefined) {
358
678
  ymlPath = path.join(dir, constants.SOCKET_YAML);
359
- yml = fs.safeReadFileSync(ymlPath);
679
+ yml = fs$1.safeReadFileSync(ymlPath);
360
680
  }
361
681
  if (typeof yml === 'string') {
362
682
  try {
@@ -519,11 +839,68 @@ function updateConfigValue(configKey, value) {
519
839
  _pendingSave = true;
520
840
  process.nextTick(() => {
521
841
  _pendingSave = false;
842
+ // Capture the config state at write time, not at schedule time.
843
+ // This ensures all updates in the same tick are included.
844
+ const configToSave = {
845
+ ...localConfig
846
+ };
522
847
  const {
523
848
  socketAppDataPath
524
849
  } = constants.default;
525
850
  if (socketAppDataPath) {
526
- fs$1.writeFileSync(socketAppDataPath, Buffer.from(JSON.stringify(localConfig)).toString('base64'));
851
+ fs.mkdirSync(socketAppDataPath, {
852
+ recursive: true
853
+ });
854
+ const configFilePath = path.join(socketAppDataPath, 'config.json');
855
+ // Read existing file to preserve formatting, then update with new values.
856
+ const existingRaw = fs$1.safeReadFileSync(configFilePath);
857
+ const EditableJson = getEditableJsonClass();
858
+ const editor = new EditableJson();
859
+ if (existingRaw !== undefined) {
860
+ const rawString = Buffer.isBuffer(existingRaw) ? existingRaw.toString('utf8') : existingRaw;
861
+ try {
862
+ const decoded = Buffer.from(rawString, 'base64').toString('utf8');
863
+ editor.fromJSON(decoded);
864
+ } catch {
865
+ // If decoding fails, start fresh.
866
+ }
867
+ } else {
868
+ // Initialize empty editor for new file.
869
+ editor.create(configFilePath);
870
+ }
871
+ // Update with the captured config state.
872
+ // Note: We need to handle deletions explicitly since editor.update() only merges.
873
+ // First, get all keys from the existing content.
874
+ const existingKeys = new Set(Object.keys(editor.content).filter(k => typeof k === 'string'));
875
+ const newKeys = new Set(Object.keys(configToSave));
876
+
877
+ // Delete keys that are in existing but not in new config.
878
+ for (const key of existingKeys) {
879
+ if (!newKeys.has(key)) {
880
+ delete editor.content[key];
881
+ }
882
+ }
883
+
884
+ // Now update with new values.
885
+ editor.update(configToSave);
886
+ // Use the editor's internal stringify which preserves formatting.
887
+ // Extract the formatting symbols from the content.
888
+ const INDENT_SYMBOL = Symbol.for('indent');
889
+ const NEWLINE_SYMBOL = Symbol.for('newline');
890
+ const indent = editor.content[INDENT_SYMBOL] ?? 2;
891
+ const newline = editor.content[NEWLINE_SYMBOL] ?? '\n';
892
+
893
+ // Strip formatting symbols from content.
894
+ const contentToSave = {};
895
+ for (const [key, val] of Object.entries(editor.content)) {
896
+ if (typeof key === 'string') {
897
+ contentToSave[key] = val;
898
+ }
899
+ }
900
+
901
+ // Stringify with formatting preserved.
902
+ const jsonContent = JSON.stringify(contentToSave, undefined, indent).replace(/\n/g, newline);
903
+ fs.writeFileSync(configFilePath, Buffer.from(jsonContent + newline).toString('base64'));
527
904
  }
528
905
  });
529
906
  }
@@ -1662,26 +2039,34 @@ async function handleApiCall(value, options) {
1662
2039
  const {
1663
2040
  commandPath,
1664
2041
  description,
1665
- spinner
2042
+ spinner,
2043
+ silence = false
1666
2044
  } = {
1667
2045
  __proto__: null,
1668
2046
  ...options
1669
2047
  };
1670
- if (description) {
1671
- spinner?.start(`Requesting ${description} from API...`);
1672
- } else {
1673
- spinner?.start();
2048
+ if (!silence) {
2049
+ if (description) {
2050
+ spinner?.start(`Requesting ${description} from API...`);
2051
+ } else {
2052
+ spinner?.start();
2053
+ }
1674
2054
  }
1675
2055
  let sdkResult;
1676
2056
  try {
1677
2057
  sdkResult = await value;
1678
- spinner?.stop();
1679
- if (description) {
2058
+ if (!silence) {
2059
+ spinner?.stop();
2060
+ }
2061
+ // Only log the message if spinner is provided (silence mode passes undefined).
2062
+ if (description && !silence) {
1680
2063
  const message = `Received Socket API response (after requesting ${description}).`;
1681
- if (sdkResult.success) {
1682
- logger.logger.success(message);
1683
- } else {
1684
- logger.logger.info(message);
2064
+ if (!silence) {
2065
+ if (sdkResult.success) {
2066
+ logger.logger.success(message);
2067
+ } else {
2068
+ logger.logger.info(message);
2069
+ }
1685
2070
  }
1686
2071
  }
1687
2072
  } catch (e) {
@@ -1691,7 +2076,8 @@ async function handleApiCall(value, options) {
1691
2076
  message: 'Socket API error',
1692
2077
  cause: vendor.messageWithCauses(e)
1693
2078
  };
1694
- if (description) {
2079
+ // Only log the message if spinner is provided (silence mode passes undefined).
2080
+ if (description && !silence) {
1695
2081
  logger.logger.fail(`An error was thrown while requesting ${description}`);
1696
2082
  }
1697
2083
  require$$9.debugDir('inspect', {
@@ -2570,7 +2956,7 @@ function levenshteinDistance(a, b) {
2570
2956
  * Determine if the banner should be suppressed based on output flags.
2571
2957
  */
2572
2958
  function shouldSuppressBanner(flags) {
2573
- return Boolean(flags['json'] || flags['markdown'] || flags['banner'] === false);
2959
+ return Boolean(flags['json'] || flags['markdown'] || flags['banner'] === false || flags['silence']);
2574
2960
  }
2575
2961
 
2576
2962
  /**
@@ -3054,7 +3440,8 @@ async function fetchOrganization(options) {
3054
3440
  const {
3055
3441
  description = 'organization list',
3056
3442
  sdk,
3057
- sdkOpts
3443
+ sdkOpts,
3444
+ silence = false
3058
3445
  } = {
3059
3446
  __proto__: null,
3060
3447
  ...options
@@ -3068,7 +3455,8 @@ async function fetchOrganization(options) {
3068
3455
  sockSdk = sockSdkCResult.data;
3069
3456
  }
3070
3457
  const orgsCResult = await handleApiCall(sockSdk.getOrganizations(), {
3071
- description
3458
+ description,
3459
+ silence
3072
3460
  });
3073
3461
  if (!orgsCResult.ok) {
3074
3462
  return orgsCResult;
@@ -3189,7 +3577,7 @@ async function determineOrgSlug(orgFlag, interactive, dryRun) {
3189
3577
  }
3190
3578
 
3191
3579
  // Use the config defaultOrg when set, otherwise discover from remote.
3192
- async function getDefaultOrgSlug() {
3580
+ async function getDefaultOrgSlug(silence) {
3193
3581
  const defaultOrgResult = getConfigValueOrUndef('defaultOrg');
3194
3582
  if (defaultOrgResult) {
3195
3583
  require$$9.debugFn('notice', 'use: org from "defaultOrg" value of socket/settings local app data', defaultOrgResult);
@@ -3206,7 +3594,9 @@ async function getDefaultOrgSlug() {
3206
3594
  data: envOrgSlug
3207
3595
  };
3208
3596
  }
3209
- const orgsCResult = await fetchOrganization();
3597
+ const orgsCResult = await fetchOrganization({
3598
+ silence
3599
+ });
3210
3600
  if (!orgsCResult.ok) {
3211
3601
  return orgsCResult;
3212
3602
  }
@@ -3894,7 +4284,7 @@ function* walkNestedMap(map, keys = []) {
3894
4284
  */
3895
4285
 
3896
4286
  function extractTier1ReachabilityScanId(socketFactsFile) {
3897
- const json = fs.readJsonSync(socketFactsFile, {
4287
+ const json = fs$1.readJsonSync(socketFactsFile, {
3898
4288
  throws: false
3899
4289
  });
3900
4290
  const tier1ReachabilityScanId = String(json?.['tier1ReachabilityScanId'] ?? '').trim();
@@ -3952,7 +4342,7 @@ async function findUp(name, options) {
3952
4342
  const thePath = path.join(dir, name);
3953
4343
  try {
3954
4344
  // eslint-disable-next-line no-await-in-loop
3955
- const stats = await fs$1.promises.stat(thePath);
4345
+ const stats = await fs.promises.stat(thePath);
3956
4346
  if (!onlyDirectories && stats.isFile()) {
3957
4347
  return thePath;
3958
4348
  }
@@ -3994,7 +4384,7 @@ async function getWorkspaceGlobs(agent, cwd = process.cwd()) {
3994
4384
  let workspacePatterns;
3995
4385
  if (agent === constants.PNPM) {
3996
4386
  const workspacePath = path.join(cwd, 'pnpm-workspace.yaml');
3997
- const yml = await fs.safeReadFile(workspacePath);
4387
+ const yml = await fs$1.safeReadFile(workspacePath);
3998
4388
  if (yml) {
3999
4389
  try {
4000
4390
  workspacePatterns = vendor.distExports$1.parse(yml)?.packages;
@@ -4104,7 +4494,7 @@ async function globWithGitIgnore(patterns, options) {
4104
4494
  cwd,
4105
4495
  ignore: DEFAULT_IGNORE_FOR_GIT_IGNORE
4106
4496
  });
4107
- for await (const ignorePatterns of streams.transform(gitIgnoreStream, async filepath => ignoreFileToGlobPatterns((await fs.safeReadFile(filepath)) ?? '', filepath, cwd), {
4497
+ for await (const ignorePatterns of streams.transform(gitIgnoreStream, async filepath => ignoreFileToGlobPatterns((await fs$1.safeReadFile(filepath)) ?? '', filepath, cwd), {
4108
4498
  concurrency: 8
4109
4499
  })) {
4110
4500
  for (const p of ignorePatterns) {
@@ -4166,7 +4556,7 @@ function pathsToGlobPatterns(paths, cwd) {
4166
4556
  }
4167
4557
  const absolutePath = path.isAbsolute(p) ? p : path.resolve(cwd ?? process.cwd(), p);
4168
4558
  // If the path is a directory, scan it recursively for all files.
4169
- if (fs.isDirSync(absolutePath)) {
4559
+ if (fs$1.isDirSync(absolutePath)) {
4170
4560
  return `${p}/**/*`;
4171
4561
  }
4172
4562
  return p;
@@ -4219,11 +4609,11 @@ function findNpmDirPathSync(npmBinPath) {
4219
4609
  // Use existsSync here because statsSync, even with { throwIfNoEntry: false },
4220
4610
  // will throw an ENOTDIR error for paths like ./a-file-that-exists/a-directory-that-does-not.
4221
4611
  // See https://github.com/nodejs/node/issues/56993.
4222
- fs.isDirSync(libNmNpmPath)) {
4612
+ fs$1.isDirSync(libNmNpmPath)) {
4223
4613
  thePath = libNmNpmPath;
4224
4614
  }
4225
- const hasNmInCurrPath = fs.isDirSync(path.join(thePath, constants.NODE_MODULES));
4226
- const hasNmInParentPath = !hasNmInCurrPath && fs.isDirSync(path.join(thePath, `../${constants.NODE_MODULES}`));
4615
+ const hasNmInCurrPath = fs$1.isDirSync(path.join(thePath, constants.NODE_MODULES));
4616
+ const hasNmInParentPath = !hasNmInCurrPath && fs$1.isDirSync(path.join(thePath, `../${constants.NODE_MODULES}`));
4227
4617
  if (
4228
4618
  // npm bin paths may look like:
4229
4619
  // /usr/local/share/npm/bin/npm
@@ -4241,7 +4631,7 @@ function findNpmDirPathSync(npmBinPath) {
4241
4631
  // Optimistically look for the default location.
4242
4632
  path.basename(thePath) === constants.NPM ||
4243
4633
  // Chocolatey installs npm bins in the same directory as node bins.
4244
- WIN32 && fs$1.existsSync(path.join(thePath, `${constants.NPM}.cmd`)))) {
4634
+ WIN32 && fs.existsSync(path.join(thePath, `${constants.NPM}.cmd`)))) {
4245
4635
  return hasNmInParentPath ? path.dirname(thePath) : thePath;
4246
4636
  }
4247
4637
  const parent = path.dirname(thePath);
@@ -4635,7 +5025,7 @@ function getDefaultSocketJson() {
4635
5025
  }
4636
5026
  function readSocketJsonSync(cwd, defaultOnError = false) {
4637
5027
  const sockJsonPath = path.join(cwd, constants.SOCKET_JSON);
4638
- if (!fs$1.existsSync(sockJsonPath)) {
5028
+ if (!fs.existsSync(sockJsonPath)) {
4639
5029
  require$$9.debugFn('notice', `miss: ${constants.SOCKET_JSON} not found at ${cwd}`);
4640
5030
  return {
4641
5031
  ok: true,
@@ -4644,7 +5034,7 @@ function readSocketJsonSync(cwd, defaultOnError = false) {
4644
5034
  }
4645
5035
  let jsonContent = null;
4646
5036
  try {
4647
- jsonContent = fs$1.readFileSync(sockJsonPath, 'utf8');
5037
+ jsonContent = fs.readFileSync(sockJsonPath, 'utf8');
4648
5038
  } catch (e) {
4649
5039
  if (defaultOnError) {
4650
5040
  logger.logger.warn(`Failed to read ${constants.SOCKET_JSON}, using default`);
@@ -4718,7 +5108,7 @@ async function writeSocketJson(cwd, sockJson) {
4718
5108
  };
4719
5109
  }
4720
5110
  const filepath = path.join(cwd, constants.SOCKET_JSON);
4721
- await fs$1.promises.writeFile(filepath, `${jsonContent}\n`, 'utf8');
5111
+ await fs.promises.writeFile(filepath, `${jsonContent}\n`, 'utf8');
4722
5112
  return {
4723
5113
  ok: true,
4724
5114
  data: undefined
@@ -4755,11 +5145,11 @@ async function readCache(key,
4755
5145
  // 5 minute in milliseconds time to live (TTL).
4756
5146
  ttlMs = 5 * 60 * 1000) {
4757
5147
  const cacheJsonPath = path.join(constants.default.githubCachePath, `${key}.json`);
4758
- const stat = fs.safeStatsSync(cacheJsonPath);
5148
+ const stat = fs$1.safeStatsSync(cacheJsonPath);
4759
5149
  if (stat) {
4760
5150
  const isExpired = Date.now() - stat.mtimeMs > ttlMs;
4761
5151
  if (!isExpired) {
4762
- return await fs.readJson(cacheJsonPath);
5152
+ return await fs$1.readJson(cacheJsonPath);
4763
5153
  }
4764
5154
  }
4765
5155
  return undefined;
@@ -4769,12 +5159,12 @@ async function writeCache(key, data) {
4769
5159
  githubCachePath
4770
5160
  } = constants.default;
4771
5161
  const cacheJsonPath = path.join(githubCachePath, `${key}.json`);
4772
- if (!fs$1.existsSync(githubCachePath)) {
4773
- await fs$1.promises.mkdir(githubCachePath, {
5162
+ if (!fs.existsSync(githubCachePath)) {
5163
+ await fs.promises.mkdir(githubCachePath, {
4774
5164
  recursive: true
4775
5165
  });
4776
5166
  }
4777
- await fs.writeJson(cacheJsonPath, data);
5167
+ await fs$1.writeJson(cacheJsonPath, data);
4778
5168
  }
4779
5169
  async function cacheFetch(key, fetcher, ttlMs) {
4780
5170
  // Optionally disable cache.
@@ -5251,7 +5641,7 @@ const COMPLETION_CMD_PREFIX = 'complete -F _socket_completion';
5251
5641
  function getCompletionSourcingCommand() {
5252
5642
  // Note: this is exported to distPath in .config/rollup.dist.config.mjs
5253
5643
  const completionScriptExportPath = path.join(constants.default.distPath, 'socket-completion.bash');
5254
- if (!fs$1.existsSync(completionScriptExportPath)) {
5644
+ if (!fs.existsSync(completionScriptExportPath)) {
5255
5645
  return {
5256
5646
  ok: false,
5257
5647
  message: 'Tab Completion script not found',
@@ -5372,7 +5762,7 @@ function getNpmRequire() {
5372
5762
  if (_npmRequire === undefined) {
5373
5763
  const npmDirPath = getNpmDirPath();
5374
5764
  const npmNmPath = path.join(npmDirPath, `${constants.NODE_MODULES}/npm`);
5375
- _npmRequire = require$$5.createRequire(path.join(fs$1.existsSync(npmNmPath) ? npmNmPath : npmDirPath, '<dummy-basename>'));
5765
+ _npmRequire = require$$5.createRequire(path.join(fs.existsSync(npmNmPath) ? npmNmPath : npmDirPath, '<dummy-basename>'));
5376
5766
  }
5377
5767
  return _npmRequire;
5378
5768
  }
@@ -5588,8 +5978,8 @@ const readLockFileByAgent = (() => {
5588
5978
  return undefined;
5589
5979
  };
5590
5980
  }
5591
- const binaryReader = wrapReader(fs.readFileBinary);
5592
- const defaultReader = wrapReader(async lockPath => await fs.readFileUtf8(lockPath));
5981
+ const binaryReader = wrapReader(fs$1.readFileBinary);
5982
+ const defaultReader = wrapReader(async lockPath => await fs$1.readFileUtf8(lockPath));
5593
5983
  return new Map([[BUN, wrapReader(async (lockPath, agentExecPath, cwd = process.cwd()) => {
5594
5984
  const ext = path.extname(lockPath);
5595
5985
  if (ext === EXT_LOCK) {
@@ -5637,20 +6027,54 @@ const LOCKS = {
5637
6027
  // it has to be handled differently.
5638
6028
  [`${NODE_MODULES}/${DOT_PACKAGE_LOCK_JSON}`]: NPM
5639
6029
  };
6030
+ function preferWindowsCmdShim(binPath, binName) {
6031
+ // Only Windows uses .cmd shims
6032
+ if (!constants.default.WIN32) {
6033
+ return binPath;
6034
+ }
6035
+
6036
+ // Relative paths might be shell commands or aliases, not file paths with potential shims
6037
+ if (!path.isAbsolute(binPath)) {
6038
+ return binPath;
6039
+ }
6040
+
6041
+ // If the path already has an extension (.exe, .bat, etc.), it is probably a Windows executable
6042
+ if (path.extname(binPath) !== '') {
6043
+ return binPath;
6044
+ }
6045
+
6046
+ // Ensures binPath actually points to the expected binary, not a parent directory that happens to match `binName`
6047
+ // For example, if binPath is C:\foo\npm\something and binName is npm, we shouldn't replace it
6048
+ if (path.basename(binPath).toLowerCase() !== binName.toLowerCase()) {
6049
+ return binPath;
6050
+ }
6051
+
6052
+ // Finally attempt to construct a .cmd shim from binPAth
6053
+ const cmdShim = path.join(path.dirname(binPath), `${binName}.cmd`);
6054
+
6055
+ // Ensure shim exists, otherwise failback to binPath
6056
+ return fs.existsSync(cmdShim) ? cmdShim : binPath;
6057
+ }
5640
6058
  async function getAgentExecPath(agent) {
5641
6059
  const binName = binByAgent.get(agent);
5642
6060
  if (binName === NPM) {
5643
6061
  // Try to use constants.npmExecPath first, but verify it exists.
5644
- const npmPath = constants.default.npmExecPath;
5645
- if (fs$1.existsSync(npmPath)) {
6062
+ const npmPath = preferWindowsCmdShim(constants.default.npmExecPath, NPM);
6063
+ if (fs.existsSync(npmPath)) {
5646
6064
  return npmPath;
5647
6065
  }
5648
6066
  // If npmExecPath doesn't exist, try common locations.
5649
6067
  // Check npm in the same directory as node.
5650
6068
  const nodeDir = path.dirname(process.execPath);
6069
+ if (constants.default.WIN32) {
6070
+ const npmCmdInNodeDir = path.join(nodeDir, `${NPM}.cmd`);
6071
+ if (fs.existsSync(npmCmdInNodeDir)) {
6072
+ return npmCmdInNodeDir;
6073
+ }
6074
+ }
5651
6075
  const npmInNodeDir = path.join(nodeDir, NPM);
5652
- if (fs$1.existsSync(npmInNodeDir)) {
5653
- return npmInNodeDir;
6076
+ if (fs.existsSync(npmInNodeDir)) {
6077
+ return preferWindowsCmdShim(npmInNodeDir, NPM);
5654
6078
  }
5655
6079
  // Fall back to whichBin.
5656
6080
  return (await bin.whichBin(binName, {
@@ -5660,7 +6084,7 @@ async function getAgentExecPath(agent) {
5660
6084
  if (binName === PNPM) {
5661
6085
  // Try to use constants.pnpmExecPath first, but verify it exists.
5662
6086
  const pnpmPath = constants.default.pnpmExecPath;
5663
- if (fs$1.existsSync(pnpmPath)) {
6087
+ if (fs.existsSync(pnpmPath)) {
5664
6088
  return pnpmPath;
5665
6089
  }
5666
6090
  // Fall back to whichBin.
@@ -5677,19 +6101,42 @@ async function getAgentVersion(agent, agentExecPath, cwd) {
5677
6101
  const quotedCmd = `\`${agent} ${constants.FLAG_VERSION}\``;
5678
6102
  require$$9.debugFn('stdio', `spawn: ${quotedCmd}`);
5679
6103
  try {
6104
+ let stdout;
6105
+
6106
+ // Some package manager "executables" may resolve to non-executable wrapper scripts
6107
+ // (e.g. the extensionless `npm` shim on Windows). Resolve the underlying entrypoint
6108
+ // and run it with Node when it is a JS file.
6109
+ let shouldRunWithNode = null;
6110
+ if (constants.default.WIN32) {
6111
+ try {
6112
+ const resolved = bin.resolveBinPathSync(agentExecPath);
6113
+ const ext = path.extname(resolved).toLowerCase();
6114
+ if (ext === '.js' || ext === '.cjs' || ext === '.mjs') {
6115
+ shouldRunWithNode = resolved;
6116
+ }
6117
+ } catch (e) {
6118
+ require$$9.debugFn('warn', `Failed to resolve bin path for ${agentExecPath}, falling back to direct spawn.`);
6119
+ require$$9.debugDir('error', e);
6120
+ }
6121
+ }
6122
+ if (shouldRunWithNode) {
6123
+ stdout = (await spawn.spawn(constants.default.execPath, [...constants.default.nodeNoWarningsFlags, shouldRunWithNode, constants.FLAG_VERSION], {
6124
+ cwd
6125
+ })).stdout;
6126
+ } else {
6127
+ stdout = (await spawn.spawn(agentExecPath, [constants.FLAG_VERSION], {
6128
+ cwd,
6129
+ // On Windows, package managers are often .cmd files that require shell execution.
6130
+ // The spawn function from @socketsecurity/registry will handle this properly
6131
+ // when shell is true.
6132
+ shell: constants.default.WIN32
6133
+ })).stdout;
6134
+ }
5680
6135
  result =
5681
6136
  // Coerce version output into a valid semver version by passing it through
5682
6137
  // semver.coerce which strips leading v's, carets (^), comparators (<,<=,>,>=,=),
5683
6138
  // and tildes (~).
5684
- vendor.semverExports.coerce(
5685
- // All package managers support the "--version" flag.
5686
- (await spawn.spawn(agentExecPath, [constants.FLAG_VERSION], {
5687
- cwd,
5688
- // On Windows, package managers are often .cmd files that require shell execution.
5689
- // The spawn function from @socketsecurity/registry will handle this properly
5690
- // when shell is true.
5691
- shell: constants.default.WIN32
5692
- })).stdout) ?? undefined;
6139
+ vendor.semverExports.coerce(stdout) ?? undefined;
5693
6140
  } catch (e) {
5694
6141
  require$$9.debugFn('error', `Package manager command failed: ${quotedCmd}`);
5695
6142
  require$$9.debugDir('inspect', {
@@ -5711,7 +6158,7 @@ async function detectPackageEnvironment({
5711
6158
  const pkgJsonPath = lockPath ? path.resolve(lockPath, `${isHiddenLockFile ? '../' : ''}../${PACKAGE_JSON}`) : await findUp(PACKAGE_JSON, {
5712
6159
  cwd
5713
6160
  });
5714
- const pkgPath = pkgJsonPath && fs$1.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
6161
+ const pkgPath = pkgJsonPath && fs.existsSync(pkgJsonPath) ? path.dirname(pkgJsonPath) : undefined;
5715
6162
  const editablePkgJson = pkgPath ? await packages.readPackageJson(pkgPath, {
5716
6163
  editable: true
5717
6164
  }) : undefined;
@@ -6266,7 +6713,7 @@ function parsePnpmLockfile(lockfileContent) {
6266
6713
  return require$$11.isObjectObject(result) ? result : null;
6267
6714
  }
6268
6715
  async function readPnpmLockfile(lockfilePath) {
6269
- return fs$1.existsSync(lockfilePath) ? await fs.readFileUtf8(lockfilePath) : undefined;
6716
+ return fs.existsSync(lockfilePath) ? await fs$1.readFileUtf8(lockfilePath) : undefined;
6270
6717
  }
6271
6718
  function stripLeadingPnpmDepPathSlash(depPath) {
6272
6719
  return isPnpmDepPath(depPath) ? depPath.slice(1) : depPath;
@@ -7041,7 +7488,6 @@ exports.getOrgSlugs = getOrgSlugs;
7041
7488
  exports.getOutputKind = getOutputKind;
7042
7489
  exports.getPackageFilesForScan = getPackageFilesForScan;
7043
7490
  exports.getPublicApiToken = getPublicApiToken;
7044
- exports.getPurlObject = getPurlObject;
7045
7491
  exports.getRepoInfo = getRepoInfo;
7046
7492
  exports.getRepoName = getRepoName;
7047
7493
  exports.getSocketDevPackageOverviewUrlFromPurl = getSocketDevPackageOverviewUrlFromPurl;
@@ -7085,7 +7531,6 @@ exports.mdTableStringNumber = mdTableStringNumber;
7085
7531
  exports.meowOrExit = meowOrExit;
7086
7532
  exports.meowWithSubcommands = meowWithSubcommands;
7087
7533
  exports.msAtHome = msAtHome;
7088
- exports.normalizePurl = normalizePurl;
7089
7534
  exports.parsePnpmLockfile = parsePnpmLockfile;
7090
7535
  exports.queryApiSafeJson = queryApiSafeJson;
7091
7536
  exports.queryApiSafeText = queryApiSafeText;
@@ -7120,5 +7565,5 @@ exports.updateConfigValue = updateConfigValue;
7120
7565
  exports.walkNestedMap = walkNestedMap;
7121
7566
  exports.webLink = webLink;
7122
7567
  exports.writeSocketJson = writeSocketJson;
7123
- //# debugId=a083299b-d999-403d-b54b-00740d629c69
7568
+ //# debugId=72040538-3948-4bbe-81a1-d87ef399d5eb
7124
7569
  //# sourceMappingURL=utils.js.map