preship 2.0.2 → 2.0.6

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/dist/cli.js CHANGED
@@ -109,8 +109,12 @@ async function unifiedScan(options) {
109
109
  }
110
110
  const mode = config.mode ?? "auto";
111
111
  const policy = config.policy ?? "commercial-safe";
112
+ const progress = options?.onProgress ?? (() => {
113
+ });
114
+ progress("Detecting project...");
112
115
  const projects = (0, import_core.detectProjects)(projectPath);
113
116
  const project = projects[0];
117
+ progress(`Parsing ${project.type} lockfile...`);
114
118
  const packageJsonPath = path.join(project.path, "package.json");
115
119
  let parsedDeps;
116
120
  switch (project.type) {
@@ -136,6 +140,7 @@ async function unifiedScan(options) {
136
140
  if (modules.license) {
137
141
  promises.push(
138
142
  (async () => {
143
+ progress("Scanning licenses...");
139
144
  const licenseStart = Date.now();
140
145
  const dependencies = await (0, import_license.resolveLicenses)(parsedDeps, projectPath, {
141
146
  mode,
@@ -169,6 +174,7 @@ async function unifiedScan(options) {
169
174
  if (modules.security) {
170
175
  promises.push(
171
176
  (async () => {
177
+ progress("Checking security vulnerabilities...");
172
178
  const securityConfig = (0, import_security.mergeSecurityConfig)(config.security);
173
179
  securityResult = await (0, import_security.scanSecurity)(parsedDeps, projectPath, securityConfig, mode);
174
180
  })()
@@ -177,6 +183,7 @@ async function unifiedScan(options) {
177
183
  if (modules.secrets) {
178
184
  promises.push(
179
185
  (async () => {
186
+ progress("Scanning for leaked secrets...");
180
187
  secretsResult = await (0, import_secrets.scanSecrets)(projectPath, config.secrets);
181
188
  })()
182
189
  );
@@ -303,12 +310,12 @@ function formatTerminalUnified(result, warnOnly = false) {
303
310
  if (warnOnly) {
304
311
  return formatWarnOnlyUnified(result);
305
312
  }
313
+ const totalTime = (result.totalScanDurationMs / 1e3).toFixed(1);
306
314
  lines.push("");
307
315
  lines.push(import_chalk.default.bold("\u{1F50D} PreShip: Pre-ship verification"));
308
316
  lines.push(` Project: ${import_chalk.default.cyan(getProjectName(result.projectPath))}${result.framework ? ` (${result.framework})` : ""}`);
309
317
  lines.push(` Lock file: ${import_chalk.default.cyan(getLockFileName(result.projectType))} (${result.projectType})`);
310
- lines.push(` Policy: ${import_chalk.default.cyan(result.policy)}`);
311
- lines.push(` Mode: ${import_chalk.default.cyan(result.mode)}`);
318
+ lines.push(` Policy: ${import_chalk.default.cyan(result.policy)} ${import_chalk.default.dim("|")} Mode: ${import_chalk.default.cyan(result.mode)}`);
312
319
  const enabledModules = [];
313
320
  if (result.modules.license) enabledModules.push("license");
314
321
  if (result.modules.security) enabledModules.push("security");
@@ -326,89 +333,172 @@ function formatTerminalUnified(result, warnOnly = false) {
326
333
  }
327
334
  lines.push(` Modules: ${import_chalk.default.cyan(enabledModules.join(", "))}`);
328
335
  lines.push("");
336
+ lines.push(import_chalk.default.bold(`\u{1F4CA} Scan Summary`) + import_chalk.default.dim(` Total time: ${totalTime}s`));
337
+ const summaryTable = new import_cli_table3.default({
338
+ head: ["Module", "Scanned", "Passed", "Issues", "Warnings", "Status", "Time"],
339
+ colWidths: [12, 12, 9, 9, 10, 9, 8],
340
+ style: { head: ["cyan"] }
341
+ });
329
342
  if (result.modules.license) {
330
- const license = result.modules.license;
331
- lines.push(import_chalk.default.bold.underline("\u{1F4DC} License Compliance"));
332
- lines.push(` Scanned ${import_chalk.default.bold(String(license.totalPackages))} packages in ${(license.scanDurationMs / 1e3).toFixed(1)}s`);
333
- lines.push("");
334
- if (license.rejected.length === 0 && license.warned.length === 0 && license.unknown.length === 0) {
335
- lines.push(import_chalk.default.green(` \u2705 All ${license.totalPackages} packages passed license check`));
343
+ const lic = result.modules.license;
344
+ const issues = lic.rejected.length;
345
+ const warnings = lic.warned.length + lic.unknown.length;
346
+ summaryTable.push([
347
+ "License",
348
+ `${lic.totalPackages} pkgs`,
349
+ String(lic.allowed.length),
350
+ issues > 0 ? import_chalk.default.red(String(issues)) : "0",
351
+ warnings > 0 ? import_chalk.default.yellow(String(warnings)) : "0",
352
+ lic.passed ? import_chalk.default.green("PASS") : import_chalk.default.red("FAIL"),
353
+ `${(lic.scanDurationMs / 1e3).toFixed(1)}s`
354
+ ]);
355
+ }
356
+ if (result.modules.security) {
357
+ const sec = result.modules.security;
358
+ const issues = sec.findings.filter((f) => f.severity === "critical" || f.severity === "high").length;
359
+ const warnings = sec.findings.filter((f) => f.severity === "medium" || f.severity === "low").length;
360
+ summaryTable.push([
361
+ "Security",
362
+ `${sec.totalPackages} pkgs`,
363
+ import_chalk.default.dim("--"),
364
+ issues > 0 ? import_chalk.default.red(String(issues)) : "0",
365
+ warnings > 0 ? import_chalk.default.yellow(String(warnings)) : "0",
366
+ sec.passed ? import_chalk.default.green("PASS") : import_chalk.default.red("FAIL"),
367
+ `${(sec.scanDurationMs / 1e3).toFixed(1)}s`
368
+ ]);
369
+ }
370
+ if (result.modules.secrets) {
371
+ const sec = result.modules.secrets;
372
+ const issues = sec.stats.critical + sec.stats.high;
373
+ const warnings = sec.stats.medium + sec.stats.low;
374
+ summaryTable.push([
375
+ "Secrets",
376
+ `${sec.filesScanned} files`,
377
+ import_chalk.default.dim("--"),
378
+ issues > 0 ? import_chalk.default.red(String(issues)) : "0",
379
+ warnings > 0 ? import_chalk.default.yellow(String(warnings)) : "0",
380
+ sec.passed ? import_chalk.default.green("PASS") : import_chalk.default.red("FAIL"),
381
+ `${(sec.scanDurationMs / 1e3).toFixed(1)}s`
382
+ ]);
383
+ }
384
+ lines.push(summaryTable.toString());
385
+ lines.push("");
386
+ if (result.modules.license && result.modules.license.passed) {
387
+ const lic = result.modules.license;
388
+ const warnings = lic.warned.length + lic.unknown.length;
389
+ if (warnings > 0) {
390
+ lines.push(import_chalk.default.green(`\u{1F4DC} License Compliance \u2014 \u2705 ${lic.allowed.length} passed`) + import_chalk.default.yellow(`, ${warnings} warning${warnings > 1 ? "s" : ""}`));
336
391
  } else {
337
- if (license.allowed.length > 0) {
338
- lines.push(import_chalk.default.green(` \u2705 ${license.allowed.length} packages \u2014 Allowed`));
339
- }
340
- if (license.warned.length > 0) {
341
- lines.push(import_chalk.default.yellow(` \u26A0\uFE0F ${license.warned.length} package${license.warned.length > 1 ? "s" : ""} \u2014 Warning (weak copyleft)`));
342
- formatPolicyResultsIndented(license.warned, lines, import_chalk.default.yellow);
343
- }
344
- if (license.rejected.length > 0) {
345
- lines.push(import_chalk.default.red(` \u274C ${license.rejected.length} package${license.rejected.length > 1 ? "s" : ""} \u2014 Rejected`));
346
- formatPolicyResultsIndented(license.rejected, lines, import_chalk.default.red);
347
- }
348
- if (license.unknown.length > 0) {
349
- lines.push(import_chalk.default.yellow(` \u26A0\uFE0F ${license.unknown.length} package${license.unknown.length > 1 ? "s" : ""} \u2014 Unknown License`));
350
- formatPolicyResultsIndented(license.unknown, lines, import_chalk.default.yellow);
351
- }
392
+ lines.push(import_chalk.default.green(`\u{1F4DC} License Compliance \u2014 \u2705 All ${lic.totalPackages} packages passed`));
352
393
  }
353
- lines.push("");
354
394
  }
355
- if (result.modules.security) {
356
- const security = result.modules.security;
357
- lines.push(import_chalk.default.bold.underline("\u{1F6E1}\uFE0F Security Vulnerabilities"));
358
- lines.push(` Scanned ${import_chalk.default.bold(String(security.totalPackages))} packages in ${(security.scanDurationMs / 1e3).toFixed(1)}s`);
359
- lines.push("");
360
- if (security.findings.length === 0) {
361
- lines.push(import_chalk.default.green(" \u2705 No security issues found"));
395
+ if (result.modules.security && result.modules.security.passed) {
396
+ const sec = result.modules.security;
397
+ if (sec.findings.length === 0) {
398
+ lines.push(import_chalk.default.green(`\u{1F6E1}\uFE0F Security Vulnerabilities \u2014 \u2705 No issues found`));
362
399
  } else {
363
- const statParts = [];
364
- if (security.stats.critical > 0) statParts.push(import_chalk.default.red(`${security.stats.critical} critical`));
365
- if (security.stats.high > 0) statParts.push(import_chalk.default.red(`${security.stats.high} high`));
366
- if (security.stats.medium > 0) statParts.push(import_chalk.default.yellow(`${security.stats.medium} medium`));
367
- if (security.stats.low > 0) statParts.push(import_chalk.default.dim(`${security.stats.low} low`));
368
- if (security.stats.deprecated > 0) statParts.push(import_chalk.default.yellow(`${security.stats.deprecated} deprecated`));
369
- if (security.stats.outdated > 0) statParts.push(import_chalk.default.yellow(`${security.stats.outdated} outdated`));
370
- if (security.stats.unmaintained > 0) statParts.push(import_chalk.default.yellow(`${security.stats.unmaintained} unmaintained`));
371
- lines.push(` ${statParts.join(" \u2502 ")}`);
372
- lines.push("");
373
- const vulnFindings = security.findings.filter((f) => f.type === "vulnerability");
374
- const healthFindings = security.findings.filter((f) => f.type !== "vulnerability");
375
- if (vulnFindings.length > 0) {
376
- formatSecurityFindings(vulnFindings, lines, "Vulnerabilities");
377
- }
378
- if (healthFindings.length > 0) {
379
- formatSecurityFindings(healthFindings, lines, "Health Issues");
380
- }
400
+ lines.push(import_chalk.default.green(`\u{1F6E1}\uFE0F Security Vulnerabilities \u2014 \u2705 Passed`) + import_chalk.default.yellow(` (${sec.findings.length} low-severity finding${sec.findings.length > 1 ? "s" : ""})`));
381
401
  }
382
- lines.push("");
383
402
  }
384
- if (result.modules.secrets) {
385
- const secrets = result.modules.secrets;
386
- lines.push(import_chalk.default.bold.underline("\u{1F511} Secret Detection"));
387
- lines.push(` Scanned ${import_chalk.default.bold(String(secrets.filesScanned))} files in ${(secrets.scanDurationMs / 1e3).toFixed(1)}s`);
388
- lines.push("");
389
- if (secrets.findings.length === 0) {
390
- lines.push(import_chalk.default.green(" \u2705 No leaked secrets found"));
403
+ if (result.modules.secrets && result.modules.secrets.passed) {
404
+ const sec = result.modules.secrets;
405
+ if (sec.findings.length === 0) {
406
+ lines.push(import_chalk.default.green(`\u{1F511} Secret Detection \u2014 \u2705 No issues found`));
391
407
  } else {
392
- const statParts = [];
393
- if (secrets.stats.critical > 0) statParts.push(import_chalk.default.red(`${secrets.stats.critical} critical`));
394
- if (secrets.stats.high > 0) statParts.push(import_chalk.default.red(`${secrets.stats.high} high`));
395
- if (secrets.stats.medium > 0) statParts.push(import_chalk.default.yellow(`${secrets.stats.medium} medium`));
396
- if (secrets.stats.low > 0) statParts.push(import_chalk.default.dim(`${secrets.stats.low} low`));
397
- lines.push(` ${statParts.join(" \u2502 ")}`);
408
+ lines.push(import_chalk.default.green(`\u{1F511} Secret Detection \u2014 \u2705 Passed`) + import_chalk.default.yellow(` (${sec.findings.length} low-severity finding${sec.findings.length > 1 ? "s" : ""})`));
409
+ }
410
+ }
411
+ const hasLicenseFailures = (result.modules.license?.rejected.length ?? 0) > 0;
412
+ const hasSecurityFailures = result.modules.security ? result.modules.security.findings.filter((f) => f.severity === "critical" || f.severity === "high").length > 0 : false;
413
+ const hasSecretFailures = result.modules.secrets ? result.modules.secrets.findings.filter((f) => f.severity === "critical" || f.severity === "high").length > 0 : false;
414
+ if (hasLicenseFailures || hasSecurityFailures || hasSecretFailures) {
415
+ lines.push("");
416
+ lines.push(import_chalk.default.red.bold("\u274C Failures"));
417
+ lines.push("");
418
+ if (hasLicenseFailures) {
419
+ const lic = result.modules.license;
420
+ lines.push(import_chalk.default.red(` \u{1F4DC} License Compliance \u2014 ${lic.rejected.length} rejected`));
421
+ formatPolicyResultsTruncated(lic.rejected, lines, import_chalk.default.red, 10);
422
+ lines.push("");
423
+ }
424
+ if (hasSecurityFailures) {
425
+ const sec = result.modules.security;
426
+ const critHighFindings = sec.findings.filter((f) => f.severity === "critical" || f.severity === "high");
427
+ const parts = [];
428
+ const critCount = critHighFindings.filter((f) => f.severity === "critical").length;
429
+ const highCount = critHighFindings.filter((f) => f.severity === "high").length;
430
+ if (critCount > 0) parts.push(`${critCount} critical`);
431
+ if (highCount > 0) parts.push(`${highCount} high`);
432
+ lines.push(import_chalk.default.red(` \u{1F6E1}\uFE0F Security Vulnerabilities \u2014 ${parts.join(", ")}`));
433
+ const vulnFails = critHighFindings.filter((f) => f.type === "vulnerability");
434
+ const healthFails = critHighFindings.filter((f) => f.type !== "vulnerability");
435
+ if (vulnFails.length > 0) formatSecurityFindings(vulnFails, lines, "Vulnerabilities");
436
+ if (healthFails.length > 0) formatSecurityFindings(healthFails, lines, "Health Issues");
398
437
  lines.push("");
399
- formatSecretFindings(secrets.findings, lines);
400
438
  }
439
+ if (hasSecretFailures) {
440
+ const sec = result.modules.secrets;
441
+ const critHighFindings = sec.findings.filter((f) => f.severity === "critical" || f.severity === "high");
442
+ const parts = [];
443
+ const critCount = critHighFindings.filter((f) => f.severity === "critical").length;
444
+ const highCount = critHighFindings.filter((f) => f.severity === "high").length;
445
+ if (critCount > 0) parts.push(`${critCount} critical`);
446
+ if (highCount > 0) parts.push(`${highCount} high`);
447
+ lines.push(import_chalk.default.red(` \u{1F511} Secret Detection \u2014 ${parts.join(", ")}`));
448
+ formatSecretFindings(critHighFindings, lines);
449
+ lines.push("");
450
+ }
451
+ }
452
+ const licenseWarnings = result.modules.license ? [...result.modules.license.warned, ...result.modules.license.unknown] : [];
453
+ const securityWarnings = result.modules.security ? result.modules.security.findings.filter((f) => f.severity === "medium" || f.severity === "low") : [];
454
+ const secretWarnings = result.modules.secrets ? result.modules.secrets.findings.filter((f) => f.severity === "medium" || f.severity === "low") : [];
455
+ const hasWarnings = licenseWarnings.length > 0 || securityWarnings.length > 0 || secretWarnings.length > 0;
456
+ if (hasWarnings) {
457
+ lines.push(import_chalk.default.yellow.bold("\u26A0\uFE0F Warnings"));
401
458
  lines.push("");
459
+ if (licenseWarnings.length > 0) {
460
+ const warnedCount = result.modules.license.warned.length;
461
+ const unknownCount = result.modules.license.unknown.length;
462
+ const parts = [];
463
+ if (warnedCount > 0) parts.push(`${warnedCount} weak copyleft`);
464
+ if (unknownCount > 0) parts.push(`${unknownCount} unknown`);
465
+ lines.push(import_chalk.default.yellow(` \u{1F4DC} License Compliance \u2014 ${parts.join(", ")}`));
466
+ formatPolicyResultsTruncated(licenseWarnings, lines, import_chalk.default.yellow, 10);
467
+ lines.push("");
468
+ }
469
+ if (securityWarnings.length > 0) {
470
+ const medCount = securityWarnings.filter((f) => f.severity === "medium").length;
471
+ const lowCount = securityWarnings.filter((f) => f.severity === "low").length;
472
+ const parts = [];
473
+ if (medCount > 0) parts.push(`${medCount} medium`);
474
+ if (lowCount > 0) parts.push(`${lowCount} low`);
475
+ lines.push(import_chalk.default.yellow(` \u{1F6E1}\uFE0F Security Vulnerabilities \u2014 ${parts.join(", ")}`));
476
+ const vulnWarns = securityWarnings.filter((f) => f.type === "vulnerability");
477
+ const healthWarns = securityWarnings.filter((f) => f.type !== "vulnerability");
478
+ if (vulnWarns.length > 0) formatSecurityFindings(vulnWarns, lines, "Vulnerabilities");
479
+ if (healthWarns.length > 0) formatSecurityFindings(healthWarns, lines, "Health Issues");
480
+ lines.push("");
481
+ }
482
+ if (secretWarnings.length > 0) {
483
+ const medCount = secretWarnings.filter((f) => f.severity === "medium").length;
484
+ const lowCount = secretWarnings.filter((f) => f.severity === "low").length;
485
+ const parts = [];
486
+ if (medCount > 0) parts.push(`${medCount} medium`);
487
+ if (lowCount > 0) parts.push(`${lowCount} low`);
488
+ lines.push(import_chalk.default.yellow(` \u{1F511} Secret Detection \u2014 ${parts.join(", ")}`));
489
+ formatSecretFindings(secretWarnings, lines);
490
+ lines.push("");
491
+ }
402
492
  }
403
- lines.push("\u2501".repeat(60));
493
+ lines.push("\u2501".repeat(62));
404
494
  if (result.passed) {
405
- lines.push(import_chalk.default.green.bold(`\u2705 RESULT: All checks passed (${(result.totalScanDurationMs / 1e3).toFixed(1)}s)`));
495
+ lines.push(import_chalk.default.green.bold(`\u2705 RESULT: All checks passed`));
406
496
  } else {
407
497
  const failedModules = [];
408
498
  if (result.modules.license && !result.modules.license.passed) failedModules.push("license");
409
499
  if (result.modules.security && !result.modules.security.passed) failedModules.push("security");
410
500
  if (result.modules.secrets && !result.modules.secrets.passed) failedModules.push("secrets");
411
- lines.push(import_chalk.default.red.bold(`\u274C RESULT: Failed \u2014 ${failedModules.join(", ")} check${failedModules.length > 1 ? "s" : ""} did not pass`));
501
+ lines.push(import_chalk.default.red.bold(`\u274C RESULT: ${failedModules.length} of ${enabledModules.length} check${enabledModules.length > 1 ? "s" : ""} failed`));
412
502
  lines.push("");
413
503
  lines.push(import_chalk.default.dim("\u{1F4A1} To fix:"));
414
504
  if (result.modules.license && !result.modules.license.passed) {
@@ -486,15 +576,21 @@ function formatPolicyResults(results, lines, colorFn) {
486
576
  lines.push(import_chalk.default.dim(`${reasonPrefix}Reason: ${getShortReason(r)}`));
487
577
  }
488
578
  }
489
- function formatPolicyResultsIndented(results, lines, colorFn) {
490
- for (let i = 0; i < results.length; i++) {
579
+ function formatPolicyResultsTruncated(results, lines, colorFn, maxItems) {
580
+ const showCount = Math.min(results.length, maxItems);
581
+ for (let i = 0; i < showCount; i++) {
491
582
  const r = results[i];
492
- const isLast = i === results.length - 1;
583
+ const isLast = i === showCount - 1 && results.length <= maxItems;
493
584
  const prefix = isLast ? " \u2514\u2500\u2500 " : " \u251C\u2500\u2500 ";
494
585
  const reasonPrefix = isLast ? " " : " \u2502 ";
495
586
  lines.push(colorFn(`${prefix}${r.dependency.name}@${r.dependency.version} \u2014 ${r.dependency.license}`));
496
587
  lines.push(import_chalk.default.dim(`${reasonPrefix}Reason: ${getShortReason(r)}`));
497
588
  }
589
+ if (results.length > maxItems) {
590
+ const remaining = results.length - maxItems;
591
+ lines.push(import_chalk.default.dim(` \u2514\u2500\u2500 ... and ${remaining} more`));
592
+ lines.push(import_chalk.default.dim(" Run with --format json for full details"));
593
+ }
498
594
  }
499
595
  function formatSecurityFindings(findings, lines, heading) {
500
596
  const MAX_FINDINGS = 15;
@@ -810,8 +906,13 @@ function registerScanCommand(program2) {
810
906
  }
811
907
  return;
812
908
  }
909
+ const showProgress = !options.silent && options.format === "table";
910
+ const onProgress = showProgress ? (msg) => {
911
+ process.stderr.write(`\r\x1B[K\x1B[2m \u23F3 ${msg}\x1B[0m`);
912
+ } : void 0;
813
913
  const result = await unifiedScan({
814
914
  projectPath: options.project,
915
+ onProgress,
815
916
  config: {
816
917
  scanDevDependencies: options.dev || void 0,
817
918
  output: options.format !== "table" ? options.format : void 0,
@@ -835,6 +936,9 @@ function registerScanCommand(program2) {
835
936
  }
836
937
  }
837
938
  });
939
+ if (showProgress) {
940
+ process.stderr.write("\r\x1B[K");
941
+ }
838
942
  if (!options.silent) {
839
943
  switch (options.format) {
840
944
  case "json":
@@ -3914,7 +4018,7 @@ function registerAllowCommand(program2) {
3914
4018
 
3915
4019
  // src/cli.ts
3916
4020
  var program = new import_commander.Command();
3917
- program.name("preship").description("Pre-ship verification: license compliance, security scanning, and secret detection \u2014 all before you ship.").version("2.0.2");
4021
+ program.name("preship").description("Pre-ship verification: license compliance, security scanning, and secret detection \u2014 all before you ship.").version("2.0.6");
3918
4022
  registerScanCommand(program);
3919
4023
  registerInitCommand(program);
3920
4024
  registerListCommand(program);
package/dist/index.d.ts CHANGED
@@ -4,6 +4,8 @@ export { Dependency, DetectedProject, ExceptionEntry, LicenseSource, ModuleConfi
4
4
  interface ScanOptions {
5
5
  projectPath?: string;
6
6
  config?: Partial<PreshipConfig>;
7
+ /** Optional progress callback for CLI status updates */
8
+ onProgress?: (message: string) => void;
7
9
  }
8
10
  /**
9
11
  * Legacy scan function — license-only scan for backwards compatibility.
package/dist/index.js CHANGED
@@ -119,8 +119,12 @@ async function unifiedScan(options) {
119
119
  }
120
120
  const mode = config.mode ?? "auto";
121
121
  const policy = config.policy ?? "commercial-safe";
122
+ const progress = options?.onProgress ?? (() => {
123
+ });
124
+ progress("Detecting project...");
122
125
  const projects = (0, import_core.detectProjects)(projectPath);
123
126
  const project = projects[0];
127
+ progress(`Parsing ${project.type} lockfile...`);
124
128
  const packageJsonPath = path.join(project.path, "package.json");
125
129
  let parsedDeps;
126
130
  switch (project.type) {
@@ -146,6 +150,7 @@ async function unifiedScan(options) {
146
150
  if (modules.license) {
147
151
  promises.push(
148
152
  (async () => {
153
+ progress("Scanning licenses...");
149
154
  const licenseStart = Date.now();
150
155
  const dependencies = await (0, import_license.resolveLicenses)(parsedDeps, projectPath, {
151
156
  mode,
@@ -179,6 +184,7 @@ async function unifiedScan(options) {
179
184
  if (modules.security) {
180
185
  promises.push(
181
186
  (async () => {
187
+ progress("Checking security vulnerabilities...");
182
188
  const securityConfig = (0, import_security.mergeSecurityConfig)(config.security);
183
189
  securityResult = await (0, import_security.scanSecurity)(parsedDeps, projectPath, securityConfig, mode);
184
190
  })()
@@ -187,6 +193,7 @@ async function unifiedScan(options) {
187
193
  if (modules.secrets) {
188
194
  promises.push(
189
195
  (async () => {
196
+ progress("Scanning for leaked secrets...");
190
197
  secretsResult = await (0, import_secrets.scanSecrets)(projectPath, config.secrets);
191
198
  })()
192
199
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "preship",
3
- "version": "2.0.2",
3
+ "version": "2.0.6",
4
4
  "description": "Pre-ship verification for modern dev teams. License compliance, security vulnerability scanning, and secret detection — all in one CLI. Zero config. Fully offline. Free forever.",
5
5
  "keywords": [
6
6
  "license",
@@ -56,9 +56,9 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@preship/core": "2.0.1",
59
- "@preship/license": "2.0.0",
60
- "@preship/security": "1.0.1",
61
- "@preship/secrets": "1.0.2",
59
+ "@preship/license": "2.0.1",
60
+ "@preship/security": "1.0.2",
61
+ "@preship/secrets": "1.0.4",
62
62
  "chalk": "^4.1.2",
63
63
  "cli-table3": "^0.6.5",
64
64
  "commander": "^12.1.0"