@westbayberry/dg 1.0.22 → 1.0.23

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 (2) hide show
  1. package/dist/index.mjs +261 -141
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1874,14 +1874,14 @@ var require_templates = __commonJS({
1874
1874
  }
1875
1875
  return results;
1876
1876
  }
1877
- function buildStyle(chalk9, styles8) {
1877
+ function buildStyle(chalk8, styles8) {
1878
1878
  const enabled = {};
1879
1879
  for (const layer of styles8) {
1880
1880
  for (const style of layer.styles) {
1881
1881
  enabled[style[0]] = layer.inverse ? null : style.slice(1);
1882
1882
  }
1883
1883
  }
1884
- let current = chalk9;
1884
+ let current = chalk8;
1885
1885
  for (const [styleName, styles9] of Object.entries(enabled)) {
1886
1886
  if (!Array.isArray(styles9)) {
1887
1887
  continue;
@@ -1893,7 +1893,7 @@ var require_templates = __commonJS({
1893
1893
  }
1894
1894
  return current;
1895
1895
  }
1896
- module.exports = (chalk9, temporary) => {
1896
+ module.exports = (chalk8, temporary) => {
1897
1897
  const styles8 = [];
1898
1898
  const chunks = [];
1899
1899
  let chunk = [];
@@ -1903,13 +1903,13 @@ var require_templates = __commonJS({
1903
1903
  } else if (style) {
1904
1904
  const string = chunk.join("");
1905
1905
  chunk = [];
1906
- chunks.push(styles8.length === 0 ? string : buildStyle(chalk9, styles8)(string));
1906
+ chunks.push(styles8.length === 0 ? string : buildStyle(chalk8, styles8)(string));
1907
1907
  styles8.push({ inverse, styles: parseStyle(style) });
1908
1908
  } else if (close) {
1909
1909
  if (styles8.length === 0) {
1910
1910
  throw new Error("Found extraneous } in Chalk template literal");
1911
1911
  }
1912
- chunks.push(buildStyle(chalk9, styles8)(chunk.join("")));
1912
+ chunks.push(buildStyle(chalk8, styles8)(chunk.join("")));
1913
1913
  chunk = [];
1914
1914
  styles8.pop();
1915
1915
  } else {
@@ -1957,16 +1957,16 @@ var require_source = __commonJS({
1957
1957
  }
1958
1958
  };
1959
1959
  var chalkFactory2 = (options) => {
1960
- const chalk10 = {};
1961
- applyOptions2(chalk10, options);
1962
- chalk10.template = (...arguments_) => chalkTag(chalk10.template, ...arguments_);
1963
- Object.setPrototypeOf(chalk10, Chalk.prototype);
1964
- Object.setPrototypeOf(chalk10.template, chalk10);
1965
- chalk10.template.constructor = () => {
1960
+ const chalk9 = {};
1961
+ applyOptions2(chalk9, options);
1962
+ chalk9.template = (...arguments_) => chalkTag(chalk9.template, ...arguments_);
1963
+ Object.setPrototypeOf(chalk9, Chalk.prototype);
1964
+ Object.setPrototypeOf(chalk9.template, chalk9);
1965
+ chalk9.template.constructor = () => {
1966
1966
  throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
1967
1967
  };
1968
- chalk10.template.Instance = ChalkClass;
1969
- return chalk10.template;
1968
+ chalk9.template.Instance = ChalkClass;
1969
+ return chalk9.template;
1970
1970
  };
1971
1971
  function Chalk(options) {
1972
1972
  return chalkFactory2(options);
@@ -2077,7 +2077,7 @@ var require_source = __commonJS({
2077
2077
  return openAll + string + closeAll;
2078
2078
  };
2079
2079
  var template;
2080
- var chalkTag = (chalk10, ...strings) => {
2080
+ var chalkTag = (chalk9, ...strings) => {
2081
2081
  const [firstString] = strings;
2082
2082
  if (!isArray(firstString) || !isArray(firstString.raw)) {
2083
2083
  return strings.join(" ");
@@ -2093,14 +2093,14 @@ var require_source = __commonJS({
2093
2093
  if (template === void 0) {
2094
2094
  template = require_templates();
2095
2095
  }
2096
- return template(chalk10, parts.join(""));
2096
+ return template(chalk9, parts.join(""));
2097
2097
  };
2098
2098
  Object.defineProperties(Chalk.prototype, styles8);
2099
- var chalk9 = Chalk();
2100
- chalk9.supportsColor = stdoutColor2;
2101
- chalk9.stderr = Chalk({ level: stderrColor2 ? stderrColor2.level : 0 });
2102
- chalk9.stderr.supportsColor = stderrColor2;
2103
- module.exports = chalk9;
2099
+ var chalk8 = Chalk();
2100
+ chalk8.supportsColor = stdoutColor2;
2101
+ chalk8.stderr = Chalk({ level: stderrColor2 ? stderrColor2.level : 0 });
2102
+ chalk8.stderr.supportsColor = stderrColor2;
2103
+ module.exports = chalk8;
2104
2104
  }
2105
2105
  });
2106
2106
 
@@ -33012,10 +33012,10 @@ var init_source = __esm({
33012
33012
  object.level = options.level === void 0 ? colorLevel : options.level;
33013
33013
  };
33014
33014
  chalkFactory = (options) => {
33015
- const chalk9 = (...strings) => strings.join(" ");
33016
- applyOptions(chalk9, options);
33017
- Object.setPrototypeOf(chalk9, createChalk.prototype);
33018
- return chalk9;
33015
+ const chalk8 = (...strings) => strings.join(" ");
33016
+ applyOptions(chalk8, options);
33017
+ Object.setPrototypeOf(chalk8, createChalk.prototype);
33018
+ return chalk8;
33019
33019
  };
33020
33020
  Object.setPrototypeOf(createChalk.prototype, Function.prototype);
33021
33021
  for (const [styleName, style] of Object.entries(ansi_styles_default3)) {
@@ -38943,15 +38943,16 @@ async function handleTrialExhausted(response) {
38943
38943
  }
38944
38944
  }
38945
38945
  async function callAnalyzeAPI(packages, config, onProgress) {
38946
- if (packages.length <= BATCH_SIZE) {
38946
+ const batchSize = config.apiKey ? BATCH_SIZE : ANON_BATCH_SIZE;
38947
+ if (packages.length <= batchSize) {
38947
38948
  if (onProgress) onProgress(0, packages.length, packages.map((p) => p.name));
38948
38949
  const result = await callBatchWithRetry(packages, config);
38949
38950
  if (onProgress) onProgress(packages.length, packages.length, packages.map((p) => p.name));
38950
38951
  return result;
38951
38952
  }
38952
38953
  const batches = [];
38953
- for (let i = 0; i < packages.length; i += BATCH_SIZE) {
38954
- batches.push(packages.slice(i, i + BATCH_SIZE));
38954
+ for (let i = 0; i < packages.length; i += batchSize) {
38955
+ batches.push(packages.slice(i, i + batchSize));
38955
38956
  }
38956
38957
  const results = [];
38957
38958
  let completed = 0;
@@ -39062,12 +39063,13 @@ async function callAnalyzeBatch(packages, config) {
39062
39063
  return await response.json();
39063
39064
  }
39064
39065
  async function callPyPIAnalyzeAPI(packages, config, onProgress) {
39065
- if (packages.length <= BATCH_SIZE) {
39066
+ const batchSize = config.apiKey ? BATCH_SIZE : ANON_BATCH_SIZE;
39067
+ if (packages.length <= batchSize) {
39066
39068
  return callPyPIBatch(packages, config);
39067
39069
  }
39068
39070
  const batches = [];
39069
- for (let i = 0; i < packages.length; i += BATCH_SIZE) {
39070
- batches.push(packages.slice(i, i + BATCH_SIZE));
39071
+ for (let i = 0; i < packages.length; i += batchSize) {
39072
+ batches.push(packages.slice(i, i + batchSize));
39071
39073
  }
39072
39074
  const results = [];
39073
39075
  let completed = 0;
@@ -39134,7 +39136,7 @@ async function callPyPIBatch(packages, config) {
39134
39136
  }
39135
39137
  return await response.json();
39136
39138
  }
39137
- var APIError, TrialExhaustedError, BATCH_SIZE, MAX_RETRIES, RETRY_DELAY_MS;
39139
+ var APIError, TrialExhaustedError, BATCH_SIZE, ANON_BATCH_SIZE, MAX_RETRIES, RETRY_DELAY_MS;
39138
39140
  var init_api = __esm({
39139
39141
  "src/api.ts"() {
39140
39142
  "use strict";
@@ -39155,6 +39157,7 @@ var init_api = __esm({
39155
39157
  }
39156
39158
  };
39157
39159
  BATCH_SIZE = 75;
39160
+ ANON_BATCH_SIZE = 50;
39158
39161
  MAX_RETRIES = 2;
39159
39162
  RETRY_DELAY_MS = 5e3;
39160
39163
  }
@@ -41069,7 +41072,7 @@ function reducer3(_state, action) {
41069
41072
  case "SCAN_PROGRESS":
41070
41073
  return { phase: "scanning", done: action.done, total: action.total, currentBatch: action.currentBatch };
41071
41074
  case "SCAN_COMPLETE":
41072
- return { phase: "results", result: action.result, durationMs: action.durationMs, skippedCount: action.skippedCount };
41075
+ return { phase: "results", result: action.result, durationMs: action.durationMs, skippedCount: action.skippedCount, discoveredTotal: action.discoveredTotal };
41073
41076
  case "ERROR":
41074
41077
  return { phase: "error", error: action.error };
41075
41078
  case "TRIAL_EXHAUSTED":
@@ -41174,6 +41177,13 @@ async function scanProjects(projects, config, dispatch) {
41174
41177
  } catch {
41175
41178
  }
41176
41179
  }
41180
+ const discoveredTotal = npmPackages.length + pypiPackages.length;
41181
+ if (!config.apiKey) {
41182
+ const anonLimit = 50;
41183
+ if (npmPackages.length > anonLimit) npmPackages.length = anonLimit;
41184
+ const pypiSlots = Math.max(0, anonLimit - npmPackages.length);
41185
+ if (pypiPackages.length > pypiSlots) pypiPackages.length = pypiSlots;
41186
+ }
41177
41187
  const totalPackages = npmPackages.length + pypiPackages.length;
41178
41188
  if (totalPackages === 0) {
41179
41189
  dispatch({ type: "DISCOVERY_EMPTY", message: "No packages to scan." });
@@ -41218,7 +41228,7 @@ async function scanProjects(projects, config, dispatch) {
41218
41228
  safeVersions,
41219
41229
  durationMs: Date.now() - startMs
41220
41230
  };
41221
- dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0 });
41231
+ dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0, discoveredTotal });
41222
41232
  } catch (error) {
41223
41233
  if (error instanceof TrialExhaustedError) {
41224
41234
  dispatch({ type: "TRIAL_EXHAUSTED", scansUsed: error.scansUsed, maxScans: error.maxScans });
@@ -41240,12 +41250,12 @@ var init_useScan = __esm({
41240
41250
  });
41241
41251
 
41242
41252
  // src/ui/components/ProgressBar.tsx
41243
- var import_chalk9, import_jsx_runtime9, ProgressBar;
41253
+ var import_jsx_runtime9, ProgressBar;
41244
41254
  var init_ProgressBar = __esm({
41245
41255
  async "src/ui/components/ProgressBar.tsx"() {
41246
41256
  "use strict";
41247
41257
  await init_build2();
41248
- import_chalk9 = __toESM(require_source());
41258
+ await init_build3();
41249
41259
  import_jsx_runtime9 = __toESM(require_jsx_runtime());
41250
41260
  ProgressBar = ({
41251
41261
  value,
@@ -41253,21 +41263,33 @@ var init_ProgressBar = __esm({
41253
41263
  label
41254
41264
  }) => {
41255
41265
  const termWidth = process.stdout.columns || 80;
41256
- const counter = `${value}/${total}`;
41257
- const barWidth = Math.max(10, termWidth - 20);
41266
+ const percent = total > 0 ? Math.round(value / total * 100) : 0;
41267
+ const counter = `${value}/${total} (${percent}%)`;
41268
+ const barWidth = Math.max(10, termWidth - counter.length - 8);
41258
41269
  const fraction = total > 0 ? Math.min(1, value / total) : 0;
41259
41270
  const filled = Math.round(fraction * barWidth);
41260
41271
  const empty = barWidth - filled;
41261
- const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
41262
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
41263
- import_chalk9.default.cyan("["),
41264
- import_chalk9.default.green(bar.slice(0, filled)),
41265
- import_chalk9.default.gray(bar.slice(filled)),
41266
- import_chalk9.default.cyan("]"),
41267
- " ",
41268
- counter,
41269
- label ? ` ${label}` : ""
41270
- ] }) });
41272
+ const filledBar = "\u2501".repeat(filled);
41273
+ const emptyBar = "\u2501".repeat(empty);
41274
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
41275
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
41276
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(build_default, { type: "dots" }) }),
41277
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " Scanning packages..." })
41278
+ ] }),
41279
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
41280
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
41281
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "green", children: filledBar }),
41282
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { dimColor: true, children: emptyBar }),
41283
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
41284
+ " ",
41285
+ counter
41286
+ ] })
41287
+ ] }),
41288
+ label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { dimColor: true, children: [
41289
+ " ",
41290
+ label
41291
+ ] }) })
41292
+ ] });
41271
41293
  };
41272
41294
  }
41273
41295
  });
@@ -41356,7 +41378,7 @@ var init_useTerminalSize = __esm({
41356
41378
  function groupPackages3(packages) {
41357
41379
  const map = /* @__PURE__ */ new Map();
41358
41380
  for (const pkg of packages) {
41359
- const fingerprint = pkg.findings.length === 0 ? `__clean_${pkg.score}` : pkg.findings.map((f) => `${f.id}:${f.severity}`).sort().join("|") + `|score:${pkg.score}`;
41381
+ const fingerprint = pkg.findings.length === 0 ? `__clean_${pkg.score}` : pkg.findings.map((f) => `${f.id ?? f.category ?? "unknown"}:${f.severity}`).sort().join("|") + `|score:${pkg.score}`;
41360
41382
  const group = map.get(fingerprint) ?? [];
41361
41383
  group.push(pkg);
41362
41384
  map.set(fingerprint, group);
@@ -41365,10 +41387,10 @@ function groupPackages3(packages) {
41365
41387
  }
41366
41388
  function actionBadge4(score, config) {
41367
41389
  if (score >= config.blockThreshold)
41368
- return { label: "BLOCK", color: import_chalk10.default.red };
41390
+ return { label: "BLOCK", color: import_chalk9.default.red };
41369
41391
  if (score >= config.warnThreshold)
41370
- return { label: "WARN", color: import_chalk10.default.yellow };
41371
- return { label: "pass", color: import_chalk10.default.green };
41392
+ return { label: "WARN", color: import_chalk9.default.yellow };
41393
+ return { label: "pass", color: import_chalk9.default.green };
41372
41394
  }
41373
41395
  function truncate3(s, max) {
41374
41396
  return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
@@ -41378,7 +41400,12 @@ function pad3(s, len) {
41378
41400
  }
41379
41401
  function findingsSummaryHeight(group) {
41380
41402
  const rep = group.packages[0];
41381
- let h = rep.findings.filter((f) => f.severity > 1 || f.critical).length;
41403
+ const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical);
41404
+ let h = visibleFindings.length;
41405
+ if (visibleFindings.length === 0 && rep.score > 0) {
41406
+ h += (rep.reasons ?? []).length;
41407
+ h += 1;
41408
+ }
41382
41409
  if (group.packages.length > 3) h += 1;
41383
41410
  return h;
41384
41411
  }
@@ -41387,12 +41414,20 @@ function findingsDetailHeight(group, safeVersions) {
41387
41414
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
41388
41415
  let h = 0;
41389
41416
  if (group.packages.length > 3) h += 1;
41417
+ if (visibleFindings.length === 0 && rep.score > 0) {
41418
+ h += (rep.reasons ?? []).length;
41419
+ h += 1;
41420
+ }
41421
+ const hasEvidence = visibleFindings.some((f) => f.evidence && f.evidence.length > 0);
41390
41422
  for (const finding of visibleFindings) {
41391
41423
  h += 1;
41392
41424
  h += 1;
41393
- h += Math.min(finding.evidence.length, EVIDENCE_LIMIT2);
41394
- if (finding.evidence.length > EVIDENCE_LIMIT2) h += 1;
41425
+ const evidence = finding.evidence ?? [];
41426
+ h += Math.min(evidence.length, EVIDENCE_LIMIT2);
41427
+ if (evidence.length > EVIDENCE_LIMIT2) h += 1;
41395
41428
  }
41429
+ if (visibleFindings.length > 0 && !hasEvidence) h += 1;
41430
+ if (rep.recommendation) h += 1;
41396
41431
  if (safeVersions[rep.name]) h += 1;
41397
41432
  return h;
41398
41433
  }
@@ -41422,13 +41457,13 @@ function viewReducer(_state, action) {
41422
41457
  return { cursor: action.cursor, expandedIndex: action.expandedIndex, expandLevel: action.expandLevel, viewport: action.viewport };
41423
41458
  }
41424
41459
  }
41425
- var import_react30, import_chalk10, import_jsx_runtime10, SEVERITY_LABELS3, SEVERITY_COLORS, EVIDENCE_LIMIT2, FIXED_CHROME, InteractiveResultsView, T, FindingsSummary, FindingsDetail;
41460
+ var import_react30, import_chalk9, import_jsx_runtime10, SEVERITY_LABELS3, SEVERITY_COLORS, EVIDENCE_LIMIT2, FIXED_CHROME, InteractiveResultsView, T, FindingsSummary, FindingsDetail;
41426
41461
  var init_InteractiveResultsView = __esm({
41427
41462
  async "src/ui/components/InteractiveResultsView.tsx"() {
41428
41463
  "use strict";
41429
41464
  import_react30 = __toESM(require_react());
41430
41465
  await init_build2();
41431
- import_chalk10 = __toESM(require_source());
41466
+ import_chalk9 = __toESM(require_source());
41432
41467
  await init_ScoreHeader();
41433
41468
  init_useExpandAnimation();
41434
41469
  await init_useTerminalSize();
@@ -41441,11 +41476,11 @@ var init_InteractiveResultsView = __esm({
41441
41476
  1: "INFO"
41442
41477
  };
41443
41478
  SEVERITY_COLORS = {
41444
- 5: (s) => import_chalk10.default.red.bold(s),
41445
- 4: (s) => import_chalk10.default.redBright(s),
41446
- 3: (s) => import_chalk10.default.yellow(s),
41447
- 2: (s) => import_chalk10.default.cyan(s),
41448
- 1: (s) => import_chalk10.default.gray(s)
41479
+ 5: (s) => import_chalk9.default.red.bold(s),
41480
+ 4: (s) => import_chalk9.default.redBright(s),
41481
+ 3: (s) => import_chalk9.default.yellow(s),
41482
+ 2: (s) => import_chalk9.default.cyan(s),
41483
+ 1: (s) => import_chalk9.default.gray(s)
41449
41484
  };
41450
41485
  EVIDENCE_LIMIT2 = 2;
41451
41486
  FIXED_CHROME = 16;
@@ -41454,7 +41489,8 @@ var init_InteractiveResultsView = __esm({
41454
41489
  config,
41455
41490
  durationMs,
41456
41491
  onExit,
41457
- onBack
41492
+ onBack,
41493
+ discoveredTotal
41458
41494
  }) => {
41459
41495
  const flagged = (0, import_react30.useMemo)(
41460
41496
  () => result.packages.filter((p) => p.score > 0),
@@ -41609,7 +41645,7 @@ var init_InteractiveResultsView = __esm({
41609
41645
  ] })
41610
41646
  ] }),
41611
41647
  aboveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41612
- import_chalk10.default.cyan(" \u2191"),
41648
+ import_chalk9.default.cyan(" \u2191"),
41613
41649
  " ",
41614
41650
  aboveCount,
41615
41651
  " more above"
@@ -41624,8 +41660,8 @@ var init_InteractiveResultsView = __esm({
41624
41660
  const chevron = level !== null ? "\u25BE" : "\u25B8";
41625
41661
  const rowContent = ` ${chevron} ` + pad3(label, 7) + pad3(truncate3(names, nameCol - 2), nameCol) + `score ${rep.score}`;
41626
41662
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
41627
- isCursor ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: import_chalk10.default.bgGray.white.bold(rowContent) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41628
- import_chalk10.default.dim(` ${chevron} `),
41663
+ isCursor ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: import_chalk9.default.bgGray.white.bold(rowContent) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41664
+ import_chalk9.default.dim(` ${chevron} `),
41629
41665
  color(pad3(label, 7)),
41630
41666
  pad3(truncate3(names, nameCol - 2), nameCol),
41631
41667
  color(`score ${rep.score}`)
@@ -41650,7 +41686,7 @@ var init_InteractiveResultsView = __esm({
41650
41686
  ] }, group.key);
41651
41687
  }),
41652
41688
  belowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41653
- import_chalk10.default.cyan(" \u2193"),
41689
+ import_chalk9.default.cyan(" \u2193"),
41654
41690
  " ",
41655
41691
  belowCount,
41656
41692
  " more below"
@@ -41669,17 +41705,32 @@ var init_InteractiveResultsView = __esm({
41669
41705
  width: "100%",
41670
41706
  children: [
41671
41707
  clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41672
- import_chalk10.default.green("\u2713"),
41708
+ import_chalk9.default.green("\u2713"),
41673
41709
  " ",
41674
41710
  clean.length,
41675
41711
  " package",
41676
41712
  clean.length !== 1 ? "s" : "",
41677
41713
  " passed with score 0"
41678
41714
  ] }),
41715
+ discoveredTotal !== void 0 && discoveredTotal > total && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41716
+ "Scanned ",
41717
+ total,
41718
+ " of ",
41719
+ discoveredTotal,
41720
+ " packages ",
41721
+ import_chalk9.default.dim("\u2014 dg login for full scans")
41722
+ ] }),
41679
41723
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41680
41724
  "Completed in ",
41681
41725
  (durationMs / 1e3).toFixed(1),
41682
- "s"
41726
+ "s",
41727
+ result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41728
+ import_chalk9.default.dim(" \u2502 "),
41729
+ result.trialScansRemaining,
41730
+ " free scan",
41731
+ result.trialScansRemaining !== 1 ? "s" : "",
41732
+ " remaining"
41733
+ ] })
41683
41734
  ] })
41684
41735
  ]
41685
41736
  }
@@ -41687,36 +41738,36 @@ var init_InteractiveResultsView = __esm({
41687
41738
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41688
41739
  " ",
41689
41740
  groups.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41690
- import_chalk10.default.cyan("\u2191\u2193"),
41741
+ import_chalk9.default.cyan("\u2191\u2193"),
41691
41742
  " navigate",
41692
41743
  " ",
41693
- import_chalk10.default.cyan("\u23CE"),
41744
+ import_chalk9.default.cyan("\u23CE"),
41694
41745
  " toggle",
41695
41746
  " ",
41696
- import_chalk10.default.cyan("e"),
41747
+ import_chalk9.default.cyan("e"),
41697
41748
  " expand/collapse",
41698
41749
  " ",
41699
41750
  onBack && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41700
- import_chalk10.default.cyan("b"),
41751
+ import_chalk9.default.cyan("b"),
41701
41752
  " back",
41702
41753
  " "
41703
41754
  ] }),
41704
- import_chalk10.default.cyan("q"),
41755
+ import_chalk9.default.cyan("q"),
41705
41756
  " quit"
41706
41757
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41707
41758
  "Press ",
41708
- import_chalk10.default.cyan("q"),
41759
+ import_chalk9.default.cyan("q"),
41709
41760
  " or ",
41710
- import_chalk10.default.cyan("Enter"),
41761
+ import_chalk9.default.cyan("Enter"),
41711
41762
  " to exit"
41712
41763
  ] })
41713
41764
  ] })
41714
41765
  ] });
41715
41766
  };
41716
41767
  T = {
41717
- branch: import_chalk10.default.dim("\u251C\u2500\u2500"),
41718
- last: import_chalk10.default.dim("\u2514\u2500\u2500"),
41719
- pipe: import_chalk10.default.dim("\u2502"),
41768
+ branch: import_chalk9.default.dim("\u251C\u2500\u2500"),
41769
+ last: import_chalk9.default.dim("\u2514\u2500\u2500"),
41770
+ pipe: import_chalk9.default.dim("\u2502"),
41720
41771
  blank: " "
41721
41772
  };
41722
41773
  FindingsSummary = ({ group, maxWidth, maxLines }) => {
@@ -41724,6 +41775,27 @@ var init_InteractiveResultsView = __esm({
41724
41775
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
41725
41776
  const hasAffects = group.packages.length > 3;
41726
41777
  const allLines = [];
41778
+ if (visibleFindings.length === 0 && rep.score > 0) {
41779
+ const reasons = rep.reasons ?? [];
41780
+ for (let i = 0; i < reasons.length; i++) {
41781
+ allLines.push(
41782
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41783
+ i < reasons.length - 1 || hasAffects ? T.branch : T.branch,
41784
+ " ",
41785
+ truncate3(reasons[i], maxWidth - 8)
41786
+ ] }, `reason-${i}`)
41787
+ );
41788
+ }
41789
+ allLines.push(
41790
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41791
+ hasAffects ? T.branch : T.last,
41792
+ " ",
41793
+ import_chalk9.default.yellow("Upgrade to Pro"),
41794
+ " to see finding details ",
41795
+ import_chalk9.default.dim("\u2014 dg login")
41796
+ ] }, "upgrade")
41797
+ );
41798
+ }
41727
41799
  for (let idx = 0; idx < visibleFindings.length; idx++) {
41728
41800
  const f = visibleFindings[idx];
41729
41801
  const isLast = !hasAffects && idx === visibleFindings.length - 1;
@@ -41736,8 +41808,8 @@ var init_InteractiveResultsView = __esm({
41736
41808
  " ",
41737
41809
  sevColor(pad3(sevLabel, 4)),
41738
41810
  " ",
41739
- import_chalk10.default.dim(f.id)
41740
- ] }, `${f.id}-${idx}`)
41811
+ import_chalk9.default.dim(f.id ?? f.category ?? "")
41812
+ ] }, `${f.id ?? f.category}-${idx}`)
41741
41813
  );
41742
41814
  }
41743
41815
  if (hasAffects) {
@@ -41760,40 +41832,65 @@ var init_InteractiveResultsView = __esm({
41760
41832
  const trailingItems = (hasAffects ? 1 : 0) + (hasSafe ? 1 : 0);
41761
41833
  const evidenceWidth = Math.max(30, maxWidth - 12);
41762
41834
  const allLines = [];
41835
+ const hasRecommendation = !!rep.recommendation;
41836
+ if (visibleFindings.length === 0 && rep.score > 0) {
41837
+ const reasons = rep.reasons ?? [];
41838
+ for (let i = 0; i < reasons.length; i++) {
41839
+ allLines.push(
41840
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41841
+ T.branch,
41842
+ " ",
41843
+ truncate3(reasons[i], maxWidth - 8)
41844
+ ] }, `reason-${i}`)
41845
+ );
41846
+ }
41847
+ allLines.push(
41848
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41849
+ hasSafe || hasAffects || hasRecommendation ? T.branch : T.last,
41850
+ " ",
41851
+ import_chalk9.default.yellow("Upgrade to Pro"),
41852
+ " to see finding details ",
41853
+ import_chalk9.default.dim("\u2014 dg login")
41854
+ ] }, "upgrade")
41855
+ );
41856
+ }
41857
+ const hasEvidence = visibleFindings.some((f) => f.evidence && f.evidence.length > 0);
41763
41858
  for (let idx = 0; idx < visibleFindings.length; idx++) {
41764
41859
  const finding = visibleFindings[idx];
41765
41860
  const isLastFinding = idx === visibleFindings.length - 1 && trailingItems === 0;
41766
- const connector = isLastFinding ? T.last : T.branch;
41767
- const continuation = isLastFinding ? `${T.blank} ` : `${T.pipe} `;
41861
+ const connector = isLastFinding && !(!hasEvidence && visibleFindings.length > 0) ? T.last : T.branch;
41862
+ const continuation = isLastFinding && !(!hasEvidence && visibleFindings.length > 0) ? `${T.blank} ` : `${T.pipe} `;
41768
41863
  const sevLabel = SEVERITY_LABELS3[finding.severity] ?? "INFO";
41769
41864
  const sevColor = SEVERITY_COLORS[finding.severity] ?? SEVERITY_COLORS[1];
41770
- const evidenceSlice = finding.evidence.slice(0, EVIDENCE_LIMIT2);
41771
- const overflow = finding.evidence.length - EVIDENCE_LIMIT2;
41865
+ const evidence = finding.evidence ?? [];
41866
+ const evidenceSlice = evidence.slice(0, EVIDENCE_LIMIT2);
41867
+ const overflow = evidence.length - EVIDENCE_LIMIT2;
41868
+ const findingId = finding.id ?? finding.category ?? "";
41772
41869
  allLines.push(
41773
41870
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41774
41871
  connector,
41775
41872
  " ",
41776
41873
  sevColor(pad3(sevLabel, 4)),
41777
41874
  " ",
41778
- import_chalk10.default.bold(finding.id)
41779
- ] }, `${finding.id}-${idx}-badge`)
41875
+ import_chalk9.default.bold(findingId)
41876
+ ] }, `${findingId}-${idx}-badge`)
41780
41877
  );
41781
41878
  allLines.push(
41782
41879
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41783
41880
  continuation,
41784
41881
  " ",
41785
41882
  finding.title
41786
- ] }, `${finding.id}-${idx}-title`)
41883
+ ] }, `${findingId}-${idx}-title`)
41787
41884
  );
41788
41885
  for (let i = 0; i < evidenceSlice.length; i++) {
41789
41886
  allLines.push(
41790
41887
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41791
41888
  continuation,
41792
41889
  " ",
41793
- import_chalk10.default.dim("\u203A"),
41890
+ import_chalk9.default.dim("\u203A"),
41794
41891
  " ",
41795
41892
  truncate3(evidenceSlice[i], evidenceWidth)
41796
- ] }, `${finding.id}-${idx}-ev-${i}`)
41893
+ ] }, `${findingId}-${idx}-ev-${i}`)
41797
41894
  );
41798
41895
  }
41799
41896
  if (overflow > 0) {
@@ -41801,26 +41898,45 @@ var init_InteractiveResultsView = __esm({
41801
41898
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41802
41899
  continuation,
41803
41900
  " ",
41804
- import_chalk10.default.dim(`+${overflow} more`)
41805
- ] }, `${finding.id}-${idx}-overflow`)
41901
+ import_chalk9.default.dim(`+${overflow} more`)
41902
+ ] }, `${findingId}-${idx}-overflow`)
41806
41903
  );
41807
41904
  }
41808
41905
  }
41906
+ if (visibleFindings.length > 0 && !hasEvidence) {
41907
+ allLines.push(
41908
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41909
+ hasSafe || hasAffects ? T.branch : T.last,
41910
+ " ",
41911
+ import_chalk9.default.yellow("Upgrade to Team"),
41912
+ " to see evidence and file locations"
41913
+ ] }, "upgrade-evidence")
41914
+ );
41915
+ }
41809
41916
  if (hasAffects) {
41810
41917
  allLines.push(
41811
41918
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41812
- hasSafe ? T.branch : T.last,
41919
+ hasSafe || hasRecommendation ? T.branch : T.last,
41813
41920
  " ",
41814
41921
  truncate3(affectsLine(group), maxWidth - 8)
41815
41922
  ] }, "affects")
41816
41923
  );
41817
41924
  }
41925
+ if (hasRecommendation) {
41926
+ allLines.push(
41927
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41928
+ hasSafe ? T.branch : T.last,
41929
+ " ",
41930
+ import_chalk9.default.cyan(truncate3(rep.recommendation, maxWidth - 8))
41931
+ ] }, "recommendation")
41932
+ );
41933
+ }
41818
41934
  if (hasSafe) {
41819
41935
  allLines.push(
41820
41936
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41821
41937
  T.last,
41822
41938
  " ",
41823
- import_chalk10.default.green(`Safe: ${rep.name}@${safeVersion}`)
41939
+ import_chalk9.default.green(`Safe: ${rep.name}@${safeVersion}`)
41824
41940
  ] }, "safe")
41825
41941
  );
41826
41942
  }
@@ -41913,12 +42029,17 @@ var init_App2 = __esm({
41913
42029
  const { exit } = use_app_default();
41914
42030
  const { rows: termRows } = useTerminalSize();
41915
42031
  const prevPhaseRef = (0, import_react32.useRef)(state.phase);
42032
+ const altScreenActiveRef = (0, import_react32.useRef)(false);
41916
42033
  (0, import_react32.useEffect)(() => {
41917
42034
  if (!process.stdout.isTTY) return;
41918
42035
  process.stdout.write("\x1B[?1049h");
41919
42036
  process.stdout.write("\x1B[2J\x1B[H");
42037
+ altScreenActiveRef.current = true;
41920
42038
  return () => {
41921
- process.stdout.write("\x1B[?1049l");
42039
+ if (altScreenActiveRef.current) {
42040
+ process.stdout.write("\x1B[?1049l");
42041
+ altScreenActiveRef.current = false;
42042
+ }
41922
42043
  process.stdout.write("\x1B[?25h");
41923
42044
  };
41924
42045
  }, []);
@@ -41941,28 +42062,35 @@ var init_App2 = __esm({
41941
42062
  }
41942
42063
  exit();
41943
42064
  }, [state, config, exit]);
42065
+ const exitWithMessage = (0, import_react32.useCallback)((message, exitCode) => {
42066
+ process.exitCode = exitCode;
42067
+ if (altScreenActiveRef.current && process.stdout.isTTY) {
42068
+ process.stdout.write("\x1B[?1049l");
42069
+ altScreenActiveRef.current = false;
42070
+ }
42071
+ process.stdout.write("\x1B[?25h");
42072
+ process.stderr.write(message);
42073
+ return setTimeout(() => exit(), 0);
42074
+ }, [exit]);
41944
42075
  (0, import_react32.useEffect)(() => {
41945
42076
  if (state.phase === "empty") {
41946
- process.exitCode = 0;
41947
- process.stderr.write(`${state.message}
41948
- `);
41949
- const timer = setTimeout(() => exit(), 0);
42077
+ const timer = exitWithMessage(`${state.message}
42078
+ `, 0);
41950
42079
  return () => clearTimeout(timer);
41951
42080
  }
41952
42081
  if (state.phase === "error") {
41953
- process.exitCode = 3;
41954
- process.stderr.write(`Error: ${state.error.message}
41955
- `);
41956
- const timer = setTimeout(() => exit(), 0);
42082
+ const timer = exitWithMessage(`Error: ${state.error.message}
42083
+ `, 3);
41957
42084
  return () => clearTimeout(timer);
41958
42085
  }
41959
42086
  if (state.phase === "trial_exhausted") {
41960
- process.exitCode = 1;
41961
- process.stderr.write("Free trial scans used up. Run `dg login` to create a free account and continue scanning.\n");
41962
- const timer = setTimeout(() => exit(), 0);
42087
+ const timer = exitWithMessage(
42088
+ "Free trial scans used up. Run `dg login` to create a free account and continue scanning.\n",
42089
+ 1
42090
+ );
41963
42091
  return () => clearTimeout(timer);
41964
42092
  }
41965
- }, [state, config, exit]);
42093
+ }, [state, exitWithMessage]);
41966
42094
  const content = (() => {
41967
42095
  switch (state.phase) {
41968
42096
  case "discovering":
@@ -41980,23 +42108,14 @@ var init_App2 = __esm({
41980
42108
  }
41981
42109
  );
41982
42110
  case "scanning":
41983
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", children: [
41984
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
41985
- ProgressBar,
41986
- {
41987
- value: state.done,
41988
- total: state.total,
41989
- label: state.currentBatch.length > 0 ? state.currentBatch[state.currentBatch.length - 1] : void 0
41990
- }
41991
- ),
41992
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { dimColor: true, children: [
41993
- "Scanning ",
41994
- state.done,
41995
- "/",
41996
- state.total,
41997
- " packages..."
41998
- ] })
41999
- ] });
42111
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
42112
+ ProgressBar,
42113
+ {
42114
+ value: state.done,
42115
+ total: state.total,
42116
+ label: state.currentBatch.length > 0 ? state.currentBatch[state.currentBatch.length - 1] : void 0
42117
+ }
42118
+ );
42000
42119
  case "results":
42001
42120
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
42002
42121
  InteractiveResultsView,
@@ -42005,7 +42124,8 @@ var init_App2 = __esm({
42005
42124
  config,
42006
42125
  durationMs: state.durationMs,
42007
42126
  onExit: handleResultsExit,
42008
- onBack: restartSelection ?? void 0
42127
+ onBack: restartSelection ?? void 0,
42128
+ discoveredTotal: state.discoveredTotal
42009
42129
  }
42010
42130
  );
42011
42131
  case "empty":
@@ -42118,33 +42238,33 @@ async function checkForUpdate(currentVersion) {
42118
42238
  return null;
42119
42239
  }
42120
42240
  async function runUpdate(currentVersion) {
42121
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42122
- process.stderr.write(chalk9.dim(" Checking for updates...\n"));
42241
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42242
+ process.stderr.write(chalk8.dim(" Checking for updates...\n"));
42123
42243
  const latest = await fetchLatestVersion();
42124
42244
  if (!latest) {
42125
- process.stderr.write(chalk9.red(" Could not reach npm registry.\n"));
42245
+ process.stderr.write(chalk8.red(" Could not reach npm registry.\n"));
42126
42246
  process.exit(1);
42127
42247
  }
42128
42248
  if (!isNewer(latest, currentVersion)) {
42129
42249
  process.stderr.write(
42130
- chalk9.green(` Already on latest version (${currentVersion}).
42250
+ chalk8.green(` Already on latest version (${currentVersion}).
42131
42251
  `)
42132
42252
  );
42133
42253
  return;
42134
42254
  }
42135
- process.stderr.write(chalk9.dim(` Installing ${PKG_NAME}@${latest}...
42255
+ process.stderr.write(chalk8.dim(` Installing ${PKG_NAME}@${latest}...
42136
42256
  `));
42137
42257
  try {
42138
42258
  execSync(`npm install -g ${PKG_NAME}@${latest}`, { stdio: "inherit" });
42139
42259
  writeCache({ latest, checkedAt: Date.now() });
42140
42260
  process.stderr.write(
42141
- chalk9.green(`
42261
+ chalk8.green(`
42142
42262
  Updated ${currentVersion} \u2192 ${latest}
42143
42263
  `)
42144
42264
  );
42145
42265
  } catch {
42146
42266
  process.stderr.write(
42147
- chalk9.red(`
42267
+ chalk8.red(`
42148
42268
  Update failed. Try manually: npm i -g ${PKG_NAME}@${latest}
42149
42269
  `)
42150
42270
  );
@@ -42196,8 +42316,8 @@ async function main() {
42196
42316
  if (rawCommand === "logout") {
42197
42317
  const { clearCredentials: clearCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
42198
42318
  clearCredentials2();
42199
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42200
- process.stderr.write(chalk9.green(" Logged out.\n"));
42319
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42320
+ process.stderr.write(chalk8.green(" Logged out.\n"));
42201
42321
  return;
42202
42322
  }
42203
42323
  const config = parseConfig(process.argv);
@@ -42212,8 +42332,8 @@ async function main() {
42212
42332
  }
42213
42333
  const updateMsg2 = await updatePromise;
42214
42334
  if (updateMsg2) {
42215
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42216
- process.stderr.write(chalk9.dim(updateMsg2));
42335
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42336
+ process.stderr.write(chalk8.dim(updateMsg2));
42217
42337
  }
42218
42338
  return;
42219
42339
  }
@@ -42227,8 +42347,8 @@ async function main() {
42227
42347
  await waitUntilExit();
42228
42348
  } else {
42229
42349
  if (config.mode === "off") {
42230
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42231
- process.stderr.write(chalk9.dim(" Dependency Guardian: mode is off \u2014 skipping.\n"));
42350
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42351
+ process.stderr.write(chalk8.dim(" Dependency Guardian: mode is off \u2014 skipping.\n"));
42232
42352
  process.exit(0);
42233
42353
  }
42234
42354
  const { App: App3 } = await init_App2().then(() => App_exports);
@@ -42239,15 +42359,15 @@ async function main() {
42239
42359
  }
42240
42360
  const updateMsg = await updatePromise;
42241
42361
  if (updateMsg) {
42242
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42243
- process.stderr.write(chalk9.dim(updateMsg));
42362
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42363
+ process.stderr.write(chalk8.dim(updateMsg));
42244
42364
  }
42245
42365
  }
42246
42366
  main().catch((err) => {
42247
42367
  try {
42248
- const chalk9 = require_source();
42368
+ const chalk8 = require_source();
42249
42369
  process.stderr.write(`
42250
- ${chalk9.bold.red("Error:")} ${err.message}
42370
+ ${chalk8.bold.red("Error:")} ${err.message}
42251
42371
 
42252
42372
  `);
42253
42373
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@westbayberry/dg",
3
- "version": "1.0.22",
3
+ "version": "1.0.23",
4
4
  "description": "Supply chain security scanner for npm and Python dependencies — detects malicious packages, typosquatting, dependency confusion, and 26+ attack patterns",
5
5
  "bin": {
6
6
  "dependency-guardian": "dist/index.mjs",