@westbayberry/dg 1.0.20 → 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 +280 -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":
@@ -41143,23 +41146,44 @@ async function scanProjects(projects, config, dispatch) {
41143
41146
  try {
41144
41147
  const npmProjects = projects.filter((p) => p.ecosystem === "npm");
41145
41148
  const pypiProjects = projects.filter((p) => p.ecosystem === "pypi");
41149
+ const fullScanConfig = { ...config, scanAll: true };
41146
41150
  const npmPackages = [];
41147
41151
  const pypiPackages = [];
41152
+ const seenNpm = /* @__PURE__ */ new Set();
41153
+ const seenPypi = /* @__PURE__ */ new Set();
41148
41154
  for (const proj of npmProjects) {
41149
41155
  try {
41150
- const discovery = discoverChanges(proj.path, config);
41156
+ const discovery = discoverChanges(proj.path, fullScanConfig);
41151
41157
  for (const pkg of discovery.packages) {
41152
- if (!config.allowlist.includes(pkg.name)) npmPackages.push(pkg);
41158
+ const key = `${pkg.name}@${pkg.version}`;
41159
+ if (!config.allowlist.includes(pkg.name) && !seenNpm.has(key)) {
41160
+ seenNpm.add(key);
41161
+ npmPackages.push(pkg);
41162
+ }
41153
41163
  }
41154
41164
  } catch {
41155
41165
  }
41156
41166
  }
41157
41167
  for (const proj of pypiProjects) {
41158
- const packages = parsePythonDepFile(proj.path, proj.depFile);
41159
- for (const pkg of packages) {
41160
- if (!config.allowlist.includes(pkg.name)) pypiPackages.push(pkg);
41168
+ try {
41169
+ const packages = parsePythonDepFile(proj.path, proj.depFile);
41170
+ for (const pkg of packages) {
41171
+ const key = `${pkg.name}@${pkg.version}`;
41172
+ if (!config.allowlist.includes(pkg.name) && !seenPypi.has(key)) {
41173
+ seenPypi.add(key);
41174
+ pypiPackages.push(pkg);
41175
+ }
41176
+ }
41177
+ } catch {
41161
41178
  }
41162
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
+ }
41163
41187
  const totalPackages = npmPackages.length + pypiPackages.length;
41164
41188
  if (totalPackages === 0) {
41165
41189
  dispatch({ type: "DISCOVERY_EMPTY", message: "No packages to scan." });
@@ -41204,7 +41228,7 @@ async function scanProjects(projects, config, dispatch) {
41204
41228
  safeVersions,
41205
41229
  durationMs: Date.now() - startMs
41206
41230
  };
41207
- dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0 });
41231
+ dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0, discoveredTotal });
41208
41232
  } catch (error) {
41209
41233
  if (error instanceof TrialExhaustedError) {
41210
41234
  dispatch({ type: "TRIAL_EXHAUSTED", scansUsed: error.scansUsed, maxScans: error.maxScans });
@@ -41226,12 +41250,12 @@ var init_useScan = __esm({
41226
41250
  });
41227
41251
 
41228
41252
  // src/ui/components/ProgressBar.tsx
41229
- var import_chalk9, import_jsx_runtime9, ProgressBar;
41253
+ var import_jsx_runtime9, ProgressBar;
41230
41254
  var init_ProgressBar = __esm({
41231
41255
  async "src/ui/components/ProgressBar.tsx"() {
41232
41256
  "use strict";
41233
41257
  await init_build2();
41234
- import_chalk9 = __toESM(require_source());
41258
+ await init_build3();
41235
41259
  import_jsx_runtime9 = __toESM(require_jsx_runtime());
41236
41260
  ProgressBar = ({
41237
41261
  value,
@@ -41239,21 +41263,33 @@ var init_ProgressBar = __esm({
41239
41263
  label
41240
41264
  }) => {
41241
41265
  const termWidth = process.stdout.columns || 80;
41242
- const counter = `${value}/${total}`;
41243
- 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);
41244
41269
  const fraction = total > 0 ? Math.min(1, value / total) : 0;
41245
41270
  const filled = Math.round(fraction * barWidth);
41246
41271
  const empty = barWidth - filled;
41247
- const bar = "\u2588".repeat(filled) + "\u2591".repeat(empty);
41248
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
41249
- import_chalk9.default.cyan("["),
41250
- import_chalk9.default.green(bar.slice(0, filled)),
41251
- import_chalk9.default.gray(bar.slice(filled)),
41252
- import_chalk9.default.cyan("]"),
41253
- " ",
41254
- counter,
41255
- label ? ` ${label}` : ""
41256
- ] }) });
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
+ ] });
41257
41293
  };
41258
41294
  }
41259
41295
  });
@@ -41342,7 +41378,7 @@ var init_useTerminalSize = __esm({
41342
41378
  function groupPackages3(packages) {
41343
41379
  const map = /* @__PURE__ */ new Map();
41344
41380
  for (const pkg of packages) {
41345
- 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}`;
41346
41382
  const group = map.get(fingerprint) ?? [];
41347
41383
  group.push(pkg);
41348
41384
  map.set(fingerprint, group);
@@ -41351,10 +41387,10 @@ function groupPackages3(packages) {
41351
41387
  }
41352
41388
  function actionBadge4(score, config) {
41353
41389
  if (score >= config.blockThreshold)
41354
- return { label: "BLOCK", color: import_chalk10.default.red };
41390
+ return { label: "BLOCK", color: import_chalk9.default.red };
41355
41391
  if (score >= config.warnThreshold)
41356
- return { label: "WARN", color: import_chalk10.default.yellow };
41357
- 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 };
41358
41394
  }
41359
41395
  function truncate3(s, max) {
41360
41396
  return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
@@ -41364,7 +41400,12 @@ function pad3(s, len) {
41364
41400
  }
41365
41401
  function findingsSummaryHeight(group) {
41366
41402
  const rep = group.packages[0];
41367
- 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
+ }
41368
41409
  if (group.packages.length > 3) h += 1;
41369
41410
  return h;
41370
41411
  }
@@ -41373,12 +41414,20 @@ function findingsDetailHeight(group, safeVersions) {
41373
41414
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
41374
41415
  let h = 0;
41375
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);
41376
41422
  for (const finding of visibleFindings) {
41377
41423
  h += 1;
41378
41424
  h += 1;
41379
- h += Math.min(finding.evidence.length, EVIDENCE_LIMIT2);
41380
- 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;
41381
41428
  }
41429
+ if (visibleFindings.length > 0 && !hasEvidence) h += 1;
41430
+ if (rep.recommendation) h += 1;
41382
41431
  if (safeVersions[rep.name]) h += 1;
41383
41432
  return h;
41384
41433
  }
@@ -41408,13 +41457,13 @@ function viewReducer(_state, action) {
41408
41457
  return { cursor: action.cursor, expandedIndex: action.expandedIndex, expandLevel: action.expandLevel, viewport: action.viewport };
41409
41458
  }
41410
41459
  }
41411
- 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;
41412
41461
  var init_InteractiveResultsView = __esm({
41413
41462
  async "src/ui/components/InteractiveResultsView.tsx"() {
41414
41463
  "use strict";
41415
41464
  import_react30 = __toESM(require_react());
41416
41465
  await init_build2();
41417
- import_chalk10 = __toESM(require_source());
41466
+ import_chalk9 = __toESM(require_source());
41418
41467
  await init_ScoreHeader();
41419
41468
  init_useExpandAnimation();
41420
41469
  await init_useTerminalSize();
@@ -41427,11 +41476,11 @@ var init_InteractiveResultsView = __esm({
41427
41476
  1: "INFO"
41428
41477
  };
41429
41478
  SEVERITY_COLORS = {
41430
- 5: (s) => import_chalk10.default.red.bold(s),
41431
- 4: (s) => import_chalk10.default.redBright(s),
41432
- 3: (s) => import_chalk10.default.yellow(s),
41433
- 2: (s) => import_chalk10.default.cyan(s),
41434
- 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)
41435
41484
  };
41436
41485
  EVIDENCE_LIMIT2 = 2;
41437
41486
  FIXED_CHROME = 16;
@@ -41440,7 +41489,8 @@ var init_InteractiveResultsView = __esm({
41440
41489
  config,
41441
41490
  durationMs,
41442
41491
  onExit,
41443
- onBack
41492
+ onBack,
41493
+ discoveredTotal
41444
41494
  }) => {
41445
41495
  const flagged = (0, import_react30.useMemo)(
41446
41496
  () => result.packages.filter((p) => p.score > 0),
@@ -41595,7 +41645,7 @@ var init_InteractiveResultsView = __esm({
41595
41645
  ] })
41596
41646
  ] }),
41597
41647
  aboveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41598
- import_chalk10.default.cyan(" \u2191"),
41648
+ import_chalk9.default.cyan(" \u2191"),
41599
41649
  " ",
41600
41650
  aboveCount,
41601
41651
  " more above"
@@ -41610,8 +41660,8 @@ var init_InteractiveResultsView = __esm({
41610
41660
  const chevron = level !== null ? "\u25BE" : "\u25B8";
41611
41661
  const rowContent = ` ${chevron} ` + pad3(label, 7) + pad3(truncate3(names, nameCol - 2), nameCol) + `score ${rep.score}`;
41612
41662
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
41613
- isCursor ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: import_chalk10.default.bgGray.white.bold(rowContent) }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41614
- 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} `),
41615
41665
  color(pad3(label, 7)),
41616
41666
  pad3(truncate3(names, nameCol - 2), nameCol),
41617
41667
  color(`score ${rep.score}`)
@@ -41636,7 +41686,7 @@ var init_InteractiveResultsView = __esm({
41636
41686
  ] }, group.key);
41637
41687
  }),
41638
41688
  belowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41639
- import_chalk10.default.cyan(" \u2193"),
41689
+ import_chalk9.default.cyan(" \u2193"),
41640
41690
  " ",
41641
41691
  belowCount,
41642
41692
  " more below"
@@ -41655,17 +41705,32 @@ var init_InteractiveResultsView = __esm({
41655
41705
  width: "100%",
41656
41706
  children: [
41657
41707
  clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41658
- import_chalk10.default.green("\u2713"),
41708
+ import_chalk9.default.green("\u2713"),
41659
41709
  " ",
41660
41710
  clean.length,
41661
41711
  " package",
41662
41712
  clean.length !== 1 ? "s" : "",
41663
41713
  " passed with score 0"
41664
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
+ ] }),
41665
41723
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41666
41724
  "Completed in ",
41667
41725
  (durationMs / 1e3).toFixed(1),
41668
- "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
+ ] })
41669
41734
  ] })
41670
41735
  ]
41671
41736
  }
@@ -41673,36 +41738,36 @@ var init_InteractiveResultsView = __esm({
41673
41738
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41674
41739
  " ",
41675
41740
  groups.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41676
- import_chalk10.default.cyan("\u2191\u2193"),
41741
+ import_chalk9.default.cyan("\u2191\u2193"),
41677
41742
  " navigate",
41678
41743
  " ",
41679
- import_chalk10.default.cyan("\u23CE"),
41744
+ import_chalk9.default.cyan("\u23CE"),
41680
41745
  " toggle",
41681
41746
  " ",
41682
- import_chalk10.default.cyan("e"),
41747
+ import_chalk9.default.cyan("e"),
41683
41748
  " expand/collapse",
41684
41749
  " ",
41685
41750
  onBack && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41686
- import_chalk10.default.cyan("b"),
41751
+ import_chalk9.default.cyan("b"),
41687
41752
  " back",
41688
41753
  " "
41689
41754
  ] }),
41690
- import_chalk10.default.cyan("q"),
41755
+ import_chalk9.default.cyan("q"),
41691
41756
  " quit"
41692
41757
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
41693
41758
  "Press ",
41694
- import_chalk10.default.cyan("q"),
41759
+ import_chalk9.default.cyan("q"),
41695
41760
  " or ",
41696
- import_chalk10.default.cyan("Enter"),
41761
+ import_chalk9.default.cyan("Enter"),
41697
41762
  " to exit"
41698
41763
  ] })
41699
41764
  ] })
41700
41765
  ] });
41701
41766
  };
41702
41767
  T = {
41703
- branch: import_chalk10.default.dim("\u251C\u2500\u2500"),
41704
- last: import_chalk10.default.dim("\u2514\u2500\u2500"),
41705
- 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"),
41706
41771
  blank: " "
41707
41772
  };
41708
41773
  FindingsSummary = ({ group, maxWidth, maxLines }) => {
@@ -41710,6 +41775,27 @@ var init_InteractiveResultsView = __esm({
41710
41775
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
41711
41776
  const hasAffects = group.packages.length > 3;
41712
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
+ }
41713
41799
  for (let idx = 0; idx < visibleFindings.length; idx++) {
41714
41800
  const f = visibleFindings[idx];
41715
41801
  const isLast = !hasAffects && idx === visibleFindings.length - 1;
@@ -41722,8 +41808,8 @@ var init_InteractiveResultsView = __esm({
41722
41808
  " ",
41723
41809
  sevColor(pad3(sevLabel, 4)),
41724
41810
  " ",
41725
- import_chalk10.default.dim(f.id)
41726
- ] }, `${f.id}-${idx}`)
41811
+ import_chalk9.default.dim(f.id ?? f.category ?? "")
41812
+ ] }, `${f.id ?? f.category}-${idx}`)
41727
41813
  );
41728
41814
  }
41729
41815
  if (hasAffects) {
@@ -41746,40 +41832,65 @@ var init_InteractiveResultsView = __esm({
41746
41832
  const trailingItems = (hasAffects ? 1 : 0) + (hasSafe ? 1 : 0);
41747
41833
  const evidenceWidth = Math.max(30, maxWidth - 12);
41748
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);
41749
41858
  for (let idx = 0; idx < visibleFindings.length; idx++) {
41750
41859
  const finding = visibleFindings[idx];
41751
41860
  const isLastFinding = idx === visibleFindings.length - 1 && trailingItems === 0;
41752
- const connector = isLastFinding ? T.last : T.branch;
41753
- 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} `;
41754
41863
  const sevLabel = SEVERITY_LABELS3[finding.severity] ?? "INFO";
41755
41864
  const sevColor = SEVERITY_COLORS[finding.severity] ?? SEVERITY_COLORS[1];
41756
- const evidenceSlice = finding.evidence.slice(0, EVIDENCE_LIMIT2);
41757
- 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 ?? "";
41758
41869
  allLines.push(
41759
41870
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41760
41871
  connector,
41761
41872
  " ",
41762
41873
  sevColor(pad3(sevLabel, 4)),
41763
41874
  " ",
41764
- import_chalk10.default.bold(finding.id)
41765
- ] }, `${finding.id}-${idx}-badge`)
41875
+ import_chalk9.default.bold(findingId)
41876
+ ] }, `${findingId}-${idx}-badge`)
41766
41877
  );
41767
41878
  allLines.push(
41768
41879
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41769
41880
  continuation,
41770
41881
  " ",
41771
41882
  finding.title
41772
- ] }, `${finding.id}-${idx}-title`)
41883
+ ] }, `${findingId}-${idx}-title`)
41773
41884
  );
41774
41885
  for (let i = 0; i < evidenceSlice.length; i++) {
41775
41886
  allLines.push(
41776
41887
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41777
41888
  continuation,
41778
41889
  " ",
41779
- import_chalk10.default.dim("\u203A"),
41890
+ import_chalk9.default.dim("\u203A"),
41780
41891
  " ",
41781
41892
  truncate3(evidenceSlice[i], evidenceWidth)
41782
- ] }, `${finding.id}-${idx}-ev-${i}`)
41893
+ ] }, `${findingId}-${idx}-ev-${i}`)
41783
41894
  );
41784
41895
  }
41785
41896
  if (overflow > 0) {
@@ -41787,26 +41898,45 @@ var init_InteractiveResultsView = __esm({
41787
41898
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41788
41899
  continuation,
41789
41900
  " ",
41790
- import_chalk10.default.dim(`+${overflow} more`)
41791
- ] }, `${finding.id}-${idx}-overflow`)
41901
+ import_chalk9.default.dim(`+${overflow} more`)
41902
+ ] }, `${findingId}-${idx}-overflow`)
41792
41903
  );
41793
41904
  }
41794
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
+ }
41795
41916
  if (hasAffects) {
41796
41917
  allLines.push(
41797
41918
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41798
- hasSafe ? T.branch : T.last,
41919
+ hasSafe || hasRecommendation ? T.branch : T.last,
41799
41920
  " ",
41800
41921
  truncate3(affectsLine(group), maxWidth - 8)
41801
41922
  ] }, "affects")
41802
41923
  );
41803
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
+ }
41804
41934
  if (hasSafe) {
41805
41935
  allLines.push(
41806
41936
  /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41807
41937
  T.last,
41808
41938
  " ",
41809
- import_chalk10.default.green(`Safe: ${rep.name}@${safeVersion}`)
41939
+ import_chalk9.default.green(`Safe: ${rep.name}@${safeVersion}`)
41810
41940
  ] }, "safe")
41811
41941
  );
41812
41942
  }
@@ -41899,12 +42029,17 @@ var init_App2 = __esm({
41899
42029
  const { exit } = use_app_default();
41900
42030
  const { rows: termRows } = useTerminalSize();
41901
42031
  const prevPhaseRef = (0, import_react32.useRef)(state.phase);
42032
+ const altScreenActiveRef = (0, import_react32.useRef)(false);
41902
42033
  (0, import_react32.useEffect)(() => {
41903
42034
  if (!process.stdout.isTTY) return;
41904
42035
  process.stdout.write("\x1B[?1049h");
41905
42036
  process.stdout.write("\x1B[2J\x1B[H");
42037
+ altScreenActiveRef.current = true;
41906
42038
  return () => {
41907
- process.stdout.write("\x1B[?1049l");
42039
+ if (altScreenActiveRef.current) {
42040
+ process.stdout.write("\x1B[?1049l");
42041
+ altScreenActiveRef.current = false;
42042
+ }
41908
42043
  process.stdout.write("\x1B[?25h");
41909
42044
  };
41910
42045
  }, []);
@@ -41927,23 +42062,35 @@ var init_App2 = __esm({
41927
42062
  }
41928
42063
  exit();
41929
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]);
41930
42075
  (0, import_react32.useEffect)(() => {
41931
42076
  if (state.phase === "empty") {
41932
- process.exitCode = 0;
41933
- const timer = setTimeout(() => exit(), 0);
42077
+ const timer = exitWithMessage(`${state.message}
42078
+ `, 0);
41934
42079
  return () => clearTimeout(timer);
41935
42080
  }
41936
42081
  if (state.phase === "error") {
41937
- process.exitCode = 3;
41938
- const timer = setTimeout(() => exit(), 0);
42082
+ const timer = exitWithMessage(`Error: ${state.error.message}
42083
+ `, 3);
41939
42084
  return () => clearTimeout(timer);
41940
42085
  }
41941
42086
  if (state.phase === "trial_exhausted") {
41942
- process.exitCode = 1;
41943
- 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
+ );
41944
42091
  return () => clearTimeout(timer);
41945
42092
  }
41946
- }, [state, config, exit]);
42093
+ }, [state, exitWithMessage]);
41947
42094
  const content = (() => {
41948
42095
  switch (state.phase) {
41949
42096
  case "discovering":
@@ -41961,23 +42108,14 @@ var init_App2 = __esm({
41961
42108
  }
41962
42109
  );
41963
42110
  case "scanning":
41964
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", children: [
41965
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
41966
- ProgressBar,
41967
- {
41968
- value: state.done,
41969
- total: state.total,
41970
- label: state.currentBatch.length > 0 ? state.currentBatch[state.currentBatch.length - 1] : void 0
41971
- }
41972
- ),
41973
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { dimColor: true, children: [
41974
- "Scanning ",
41975
- state.done,
41976
- "/",
41977
- state.total,
41978
- " packages..."
41979
- ] })
41980
- ] });
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
+ );
41981
42119
  case "results":
41982
42120
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
41983
42121
  InteractiveResultsView,
@@ -41986,7 +42124,8 @@ var init_App2 = __esm({
41986
42124
  config,
41987
42125
  durationMs: state.durationMs,
41988
42126
  onExit: handleResultsExit,
41989
- onBack: restartSelection ?? void 0
42127
+ onBack: restartSelection ?? void 0,
42128
+ discoveredTotal: state.discoveredTotal
41990
42129
  }
41991
42130
  );
41992
42131
  case "empty":
@@ -42099,33 +42238,33 @@ async function checkForUpdate(currentVersion) {
42099
42238
  return null;
42100
42239
  }
42101
42240
  async function runUpdate(currentVersion) {
42102
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42103
- 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"));
42104
42243
  const latest = await fetchLatestVersion();
42105
42244
  if (!latest) {
42106
- process.stderr.write(chalk9.red(" Could not reach npm registry.\n"));
42245
+ process.stderr.write(chalk8.red(" Could not reach npm registry.\n"));
42107
42246
  process.exit(1);
42108
42247
  }
42109
42248
  if (!isNewer(latest, currentVersion)) {
42110
42249
  process.stderr.write(
42111
- chalk9.green(` Already on latest version (${currentVersion}).
42250
+ chalk8.green(` Already on latest version (${currentVersion}).
42112
42251
  `)
42113
42252
  );
42114
42253
  return;
42115
42254
  }
42116
- process.stderr.write(chalk9.dim(` Installing ${PKG_NAME}@${latest}...
42255
+ process.stderr.write(chalk8.dim(` Installing ${PKG_NAME}@${latest}...
42117
42256
  `));
42118
42257
  try {
42119
42258
  execSync(`npm install -g ${PKG_NAME}@${latest}`, { stdio: "inherit" });
42120
42259
  writeCache({ latest, checkedAt: Date.now() });
42121
42260
  process.stderr.write(
42122
- chalk9.green(`
42261
+ chalk8.green(`
42123
42262
  Updated ${currentVersion} \u2192 ${latest}
42124
42263
  `)
42125
42264
  );
42126
42265
  } catch {
42127
42266
  process.stderr.write(
42128
- chalk9.red(`
42267
+ chalk8.red(`
42129
42268
  Update failed. Try manually: npm i -g ${PKG_NAME}@${latest}
42130
42269
  `)
42131
42270
  );
@@ -42177,8 +42316,8 @@ async function main() {
42177
42316
  if (rawCommand === "logout") {
42178
42317
  const { clearCredentials: clearCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
42179
42318
  clearCredentials2();
42180
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42181
- 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"));
42182
42321
  return;
42183
42322
  }
42184
42323
  const config = parseConfig(process.argv);
@@ -42193,8 +42332,8 @@ async function main() {
42193
42332
  }
42194
42333
  const updateMsg2 = await updatePromise;
42195
42334
  if (updateMsg2) {
42196
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42197
- process.stderr.write(chalk9.dim(updateMsg2));
42335
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42336
+ process.stderr.write(chalk8.dim(updateMsg2));
42198
42337
  }
42199
42338
  return;
42200
42339
  }
@@ -42208,8 +42347,8 @@ async function main() {
42208
42347
  await waitUntilExit();
42209
42348
  } else {
42210
42349
  if (config.mode === "off") {
42211
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42212
- 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"));
42213
42352
  process.exit(0);
42214
42353
  }
42215
42354
  const { App: App3 } = await init_App2().then(() => App_exports);
@@ -42220,15 +42359,15 @@ async function main() {
42220
42359
  }
42221
42360
  const updateMsg = await updatePromise;
42222
42361
  if (updateMsg) {
42223
- const chalk9 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42224
- process.stderr.write(chalk9.dim(updateMsg));
42362
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42363
+ process.stderr.write(chalk8.dim(updateMsg));
42225
42364
  }
42226
42365
  }
42227
42366
  main().catch((err) => {
42228
42367
  try {
42229
- const chalk9 = require_source();
42368
+ const chalk8 = require_source();
42230
42369
  process.stderr.write(`
42231
- ${chalk9.bold.red("Error:")} ${err.message}
42370
+ ${chalk8.bold.red("Error:")} ${err.message}
42232
42371
 
42233
42372
  `);
42234
42373
  } catch {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@westbayberry/dg",
3
- "version": "1.0.20",
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",