@westbayberry/dg 1.0.35 → 1.0.39

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 +923 -1995
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -226,7 +226,7 @@ function loadDgrc() {
226
226
  function validateApiUrl(url) {
227
227
  try {
228
228
  const parsed = new URL(url);
229
- const isLocal = parsed.hostname === "localhost" || parsed.hostname.startsWith("127.");
229
+ const isLocal = parsed.hostname === "localhost" || parsed.hostname.startsWith("127.") || parsed.hostname.startsWith("100.") || parsed.hostname.startsWith("192.168.");
230
230
  if (parsed.protocol !== "https:" && !isLocal) {
231
231
  process.stderr.write(`Error: API URL must use HTTPS (got ${parsed.protocol}). Use localhost for local testing.
232
232
  `);
@@ -264,6 +264,7 @@ function parseConfig(argv, strictFlags = true) {
264
264
  "scan-all": { type: "boolean", default: false },
265
265
  "base-lockfile": { type: "string" },
266
266
  workspace: { type: "string", short: "w" },
267
+ output: { type: "string", short: "o" },
267
268
  debug: { type: "boolean", default: false },
268
269
  help: { type: "boolean", default: false },
269
270
  version: { type: "boolean", default: false },
@@ -329,6 +330,7 @@ function parseConfig(argv, strictFlags = true) {
329
330
  scanAll: values["scan-all"],
330
331
  baseLockfile: values["base-lockfile"] ?? null,
331
332
  workspace: values.workspace ?? process.env.DG_WORKSPACE ?? null,
333
+ outputFile: values.output ?? null,
332
334
  command,
333
335
  debug
334
336
  };
@@ -367,6 +369,7 @@ var init_config = __esm({
367
369
  --scan-all Scan all packages, not just changed
368
370
  --base-lockfile <path> Path to base lockfile for explicit diff
369
371
  --workspace <dir> Scan a specific workspace subdirectory
372
+ --output, -o <file> Save JSON results to file (use with --json)
370
373
  --debug Show diagnostic output (discovery, batches, timing)
371
374
  --help Show this help message
372
375
  --version Show version number
@@ -1457,15 +1460,15 @@ var require_route = __commonJS({
1457
1460
  };
1458
1461
  }
1459
1462
  function wrapConversion(toModel, graph) {
1460
- const path = [graph[toModel].parent, toModel];
1463
+ const path2 = [graph[toModel].parent, toModel];
1461
1464
  let fn = conversions[graph[toModel].parent][toModel];
1462
1465
  let cur = graph[toModel].parent;
1463
1466
  while (graph[cur].parent) {
1464
- path.unshift(graph[cur].parent);
1467
+ path2.unshift(graph[cur].parent);
1465
1468
  fn = link2(conversions[graph[cur].parent][cur], fn);
1466
1469
  cur = graph[cur].parent;
1467
1470
  }
1468
- fn.conversion = path;
1471
+ fn.conversion = path2;
1469
1472
  return fn;
1470
1473
  }
1471
1474
  module.exports = function(fromModel) {
@@ -1904,14 +1907,14 @@ var require_templates = __commonJS({
1904
1907
  }
1905
1908
  return results;
1906
1909
  }
1907
- function buildStyle(chalk10, styles8) {
1910
+ function buildStyle(chalk8, styles8) {
1908
1911
  const enabled = {};
1909
1912
  for (const layer of styles8) {
1910
1913
  for (const style of layer.styles) {
1911
1914
  enabled[style[0]] = layer.inverse ? null : style.slice(1);
1912
1915
  }
1913
1916
  }
1914
- let current = chalk10;
1917
+ let current = chalk8;
1915
1918
  for (const [styleName, styles9] of Object.entries(enabled)) {
1916
1919
  if (!Array.isArray(styles9)) {
1917
1920
  continue;
@@ -1923,7 +1926,7 @@ var require_templates = __commonJS({
1923
1926
  }
1924
1927
  return current;
1925
1928
  }
1926
- module.exports = (chalk10, temporary) => {
1929
+ module.exports = (chalk8, temporary) => {
1927
1930
  const styles8 = [];
1928
1931
  const chunks = [];
1929
1932
  let chunk = [];
@@ -1933,13 +1936,13 @@ var require_templates = __commonJS({
1933
1936
  } else if (style) {
1934
1937
  const string = chunk.join("");
1935
1938
  chunk = [];
1936
- chunks.push(styles8.length === 0 ? string : buildStyle(chalk10, styles8)(string));
1939
+ chunks.push(styles8.length === 0 ? string : buildStyle(chalk8, styles8)(string));
1937
1940
  styles8.push({ inverse, styles: parseStyle(style) });
1938
1941
  } else if (close) {
1939
1942
  if (styles8.length === 0) {
1940
1943
  throw new Error("Found extraneous } in Chalk template literal");
1941
1944
  }
1942
- chunks.push(buildStyle(chalk10, styles8)(chunk.join("")));
1945
+ chunks.push(buildStyle(chalk8, styles8)(chunk.join("")));
1943
1946
  chunk = [];
1944
1947
  styles8.pop();
1945
1948
  } else {
@@ -1987,16 +1990,16 @@ var require_source = __commonJS({
1987
1990
  }
1988
1991
  };
1989
1992
  var chalkFactory2 = (options) => {
1990
- const chalk11 = {};
1991
- applyOptions2(chalk11, options);
1992
- chalk11.template = (...arguments_) => chalkTag(chalk11.template, ...arguments_);
1993
- Object.setPrototypeOf(chalk11, Chalk.prototype);
1994
- Object.setPrototypeOf(chalk11.template, chalk11);
1995
- chalk11.template.constructor = () => {
1993
+ const chalk9 = {};
1994
+ applyOptions2(chalk9, options);
1995
+ chalk9.template = (...arguments_) => chalkTag(chalk9.template, ...arguments_);
1996
+ Object.setPrototypeOf(chalk9, Chalk.prototype);
1997
+ Object.setPrototypeOf(chalk9.template, chalk9);
1998
+ chalk9.template.constructor = () => {
1996
1999
  throw new Error("`chalk.constructor()` is deprecated. Use `new chalk.Instance()` instead.");
1997
2000
  };
1998
- chalk11.template.Instance = ChalkClass;
1999
- return chalk11.template;
2001
+ chalk9.template.Instance = ChalkClass;
2002
+ return chalk9.template;
2000
2003
  };
2001
2004
  function Chalk(options) {
2002
2005
  return chalkFactory2(options);
@@ -2107,7 +2110,7 @@ var require_source = __commonJS({
2107
2110
  return openAll + string + closeAll;
2108
2111
  };
2109
2112
  var template;
2110
- var chalkTag = (chalk11, ...strings) => {
2113
+ var chalkTag = (chalk9, ...strings) => {
2111
2114
  const [firstString] = strings;
2112
2115
  if (!isArray(firstString) || !isArray(firstString.raw)) {
2113
2116
  return strings.join(" ");
@@ -2123,14 +2126,14 @@ var require_source = __commonJS({
2123
2126
  if (template === void 0) {
2124
2127
  template = require_templates();
2125
2128
  }
2126
- return template(chalk11, parts.join(""));
2129
+ return template(chalk9, parts.join(""));
2127
2130
  };
2128
2131
  Object.defineProperties(Chalk.prototype, styles8);
2129
- var chalk10 = Chalk();
2130
- chalk10.supportsColor = stdoutColor2;
2131
- chalk10.stderr = Chalk({ level: stderrColor2 ? stderrColor2.level : 0 });
2132
- chalk10.stderr.supportsColor = stderrColor2;
2133
- module.exports = chalk10;
2132
+ var chalk8 = Chalk();
2133
+ chalk8.supportsColor = stdoutColor2;
2134
+ chalk8.stderr = Chalk({ level: stderrColor2 ? stderrColor2.level : 0 });
2135
+ chalk8.stderr.supportsColor = stderrColor2;
2136
+ module.exports = chalk8;
2134
2137
  }
2135
2138
  });
2136
2139
 
@@ -2261,7 +2264,7 @@ var require_react_production_min = __commonJS({
2261
2264
  });
2262
2265
  return d;
2263
2266
  }
2264
- function T2(a) {
2267
+ function T(a) {
2265
2268
  if (-1 === a._status) {
2266
2269
  var b = a._result;
2267
2270
  b = b();
@@ -2344,7 +2347,7 @@ var require_react_production_min = __commonJS({
2344
2347
  };
2345
2348
  exports.isValidElement = O;
2346
2349
  exports.lazy = function(a) {
2347
- return { $$typeof: y, _payload: { _status: -1, _result: a }, _init: T2 };
2350
+ return { $$typeof: y, _payload: { _status: -1, _result: a }, _init: T };
2348
2351
  };
2349
2352
  exports.memo = function(a, b) {
2350
2353
  return { $$typeof: x, type: a, compare: void 0 === b ? null : b };
@@ -3466,19 +3469,19 @@ var require_react_development = __commonJS({
3466
3469
  }
3467
3470
  return dispatcher.useContext(Context);
3468
3471
  }
3469
- function useState9(initialState) {
3472
+ function useState3(initialState) {
3470
3473
  var dispatcher = resolveDispatcher();
3471
3474
  return dispatcher.useState(initialState);
3472
3475
  }
3473
- function useReducer6(reducer5, initialArg, init) {
3476
+ function useReducer5(reducer5, initialArg, init) {
3474
3477
  var dispatcher = resolveDispatcher();
3475
3478
  return dispatcher.useReducer(reducer5, initialArg, init);
3476
3479
  }
3477
- function useRef9(initialValue) {
3480
+ function useRef4(initialValue) {
3478
3481
  var dispatcher = resolveDispatcher();
3479
3482
  return dispatcher.useRef(initialValue);
3480
3483
  }
3481
- function useEffect16(create2, deps) {
3484
+ function useEffect10(create2, deps) {
3482
3485
  var dispatcher = resolveDispatcher();
3483
3486
  return dispatcher.useEffect(create2, deps);
3484
3487
  }
@@ -3490,7 +3493,7 @@ var require_react_development = __commonJS({
3490
3493
  var dispatcher = resolveDispatcher();
3491
3494
  return dispatcher.useLayoutEffect(create2, deps);
3492
3495
  }
3493
- function useCallback6(callback, deps) {
3496
+ function useCallback4(callback, deps) {
3494
3497
  var dispatcher = resolveDispatcher();
3495
3498
  return dispatcher.useCallback(callback, deps);
3496
3499
  }
@@ -4257,19 +4260,19 @@ var require_react_development = __commonJS({
4257
4260
  exports.memo = memo;
4258
4261
  exports.startTransition = startTransition;
4259
4262
  exports.unstable_act = act;
4260
- exports.useCallback = useCallback6;
4263
+ exports.useCallback = useCallback4;
4261
4264
  exports.useContext = useContext7;
4262
4265
  exports.useDebugValue = useDebugValue;
4263
4266
  exports.useDeferredValue = useDeferredValue;
4264
- exports.useEffect = useEffect16;
4267
+ exports.useEffect = useEffect10;
4265
4268
  exports.useId = useId;
4266
4269
  exports.useImperativeHandle = useImperativeHandle;
4267
4270
  exports.useInsertionEffect = useInsertionEffect;
4268
4271
  exports.useLayoutEffect = useLayoutEffect2;
4269
4272
  exports.useMemo = useMemo4;
4270
- exports.useReducer = useReducer6;
4271
- exports.useRef = useRef9;
4272
- exports.useState = useState9;
4273
+ exports.useReducer = useReducer5;
4274
+ exports.useRef = useRef4;
4275
+ exports.useState = useState3;
4273
4276
  exports.useSyncExternalStore = useSyncExternalStore;
4274
4277
  exports.useTransition = useTransition;
4275
4278
  exports.version = ReactVersion;
@@ -5162,14 +5165,14 @@ var init_yoga_wasm_base64_esm = __esm({
5162
5165
  b.P && b.O || Ta("makeClassHandle requires ptr and ptrType");
5163
5166
  !!b.U !== !!b.T && Ta("Both smartPtrType and smartPtr must be specified");
5164
5167
  b.count = { value: 1 };
5165
- return T2(Object.create(a, { M: { value: b } }));
5168
+ return T(Object.create(a, { M: { value: b } }));
5166
5169
  }
5167
- function T2(a) {
5168
- if ("undefined" === typeof FinalizationRegistry) return T2 = (b) => b, a;
5170
+ function T(a) {
5171
+ if ("undefined" === typeof FinalizationRegistry) return T = (b) => b, a;
5169
5172
  Na = new FinalizationRegistry((b) => {
5170
5173
  Oa(b.M);
5171
5174
  });
5172
- T2 = (b) => {
5175
+ T = (b) => {
5173
5176
  var c = b.M;
5174
5177
  c.T && Na.register(b, { M: c }, b);
5175
5178
  return b;
@@ -5177,7 +5180,7 @@ var init_yoga_wasm_base64_esm = __esm({
5177
5180
  Ma = (b) => {
5178
5181
  Na.unregister(b);
5179
5182
  };
5180
- return T2(a);
5183
+ return T(a);
5181
5184
  }
5182
5185
  var Va = {};
5183
5186
  function Wa(a) {
@@ -5546,7 +5549,7 @@ var init_yoga_wasm_base64_esm = __esm({
5546
5549
  X.prototype.clone = function() {
5547
5550
  this.M.O || $a(this);
5548
5551
  if (this.M.aa) return this.M.count.value += 1, this;
5549
- var a = T2, b = Object, c = b.create, d = Object.getPrototypeOf(this), e = this.M;
5552
+ var a = T, b = Object, c = b.create, d = Object.getPrototypeOf(this), e = this.M;
5550
5553
  a = a(c.call(b, d, { M: { value: { count: e.count, $: e.$, aa: e.aa, O: e.O, P: e.P, T: e.T, U: e.U } } }));
5551
5554
  a.M.count.value += 1;
5552
5555
  a.M.$ = false;
@@ -5643,7 +5646,7 @@ var init_yoga_wasm_base64_esm = __esm({
5643
5646
  l.notifyOnDestruction();
5644
5647
  n.aa = true;
5645
5648
  Object.defineProperties(this, { M: { value: n } });
5646
- T2(this);
5649
+ T(this);
5647
5650
  l = n.O;
5648
5651
  l = Ia(e, l);
5649
5652
  Q.hasOwnProperty(l) ? L("Tried to register registered instance: " + l) : Q[l] = this;
@@ -6471,7 +6474,7 @@ function wrapAssembly(lib) {
6471
6474
  lib.Node.destroy(this);
6472
6475
  });
6473
6476
  patch(lib.Node.prototype, "freeRecursive", function() {
6474
- for (let t = 0, T2 = this.getChildCount(); t < T2; ++t) {
6477
+ for (let t = 0, T = this.getChildCount(); t < T; ++t) {
6475
6478
  this.getChild(0).freeRecursive();
6476
6479
  }
6477
6480
  this.free();
@@ -6639,15 +6642,15 @@ var require_scheduler_production_min = __commonJS({
6639
6642
  F(R);
6640
6643
  };
6641
6644
  else if ("undefined" !== typeof MessageChannel) {
6642
- T2 = new MessageChannel(), U = T2.port2;
6643
- T2.port1.onmessage = R;
6645
+ T = new MessageChannel(), U = T.port2;
6646
+ T.port1.onmessage = R;
6644
6647
  S = function() {
6645
6648
  U.postMessage(null);
6646
6649
  };
6647
6650
  } else S = function() {
6648
6651
  D(R, 0);
6649
6652
  };
6650
- var T2;
6653
+ var T;
6651
6654
  var U;
6652
6655
  function I(a) {
6653
6656
  O = a;
@@ -9817,7 +9820,7 @@ var require_react_reconciler_production_min = __commonJS({
9817
9820
  return null;
9818
9821
  }
9819
9822
  }
9820
- var Gg = false, S = false, Hg = "function" === typeof WeakSet ? WeakSet : Set, T2 = null;
9823
+ var Gg = false, S = false, Hg = "function" === typeof WeakSet ? WeakSet : Set, T = null;
9821
9824
  function Ig(a, b) {
9822
9825
  var c = a.ref;
9823
9826
  if (null !== c) if ("function" === typeof c) try {
@@ -9837,9 +9840,9 @@ var require_react_reconciler_production_min = __commonJS({
9837
9840
  var Kg = false;
9838
9841
  function Lg(a, b) {
9839
9842
  Ha(a.containerInfo);
9840
- for (T2 = b; null !== T2; ) if (a = T2, b = a.child, 0 !== (a.subtreeFlags & 1028) && null !== b) b.return = a, T2 = b;
9841
- else for (; null !== T2; ) {
9842
- a = T2;
9843
+ for (T = b; null !== T; ) if (a = T, b = a.child, 0 !== (a.subtreeFlags & 1028) && null !== b) b.return = a, T = b;
9844
+ else for (; null !== T; ) {
9845
+ a = T;
9843
9846
  try {
9844
9847
  var c = a.alternate;
9845
9848
  if (0 !== (a.flags & 1024)) switch (a.tag) {
@@ -9870,10 +9873,10 @@ var require_react_reconciler_production_min = __commonJS({
9870
9873
  b = a.sibling;
9871
9874
  if (null !== b) {
9872
9875
  b.return = a.return;
9873
- T2 = b;
9876
+ T = b;
9874
9877
  break;
9875
9878
  }
9876
- T2 = a.return;
9879
+ T = a.return;
9877
9880
  }
9878
9881
  c = Kg;
9879
9882
  Kg = false;
@@ -10201,9 +10204,9 @@ var require_react_reconciler_production_min = __commonJS({
10201
10204
  ah(a);
10202
10205
  if (d & 8192) {
10203
10206
  c = null !== a.memoizedState;
10204
- if ((a.stateNode.isHidden = c) && !g && 0 !== (a.mode & 1)) for (T2 = a, d = a.child; null !== d; ) {
10205
- for (b = T2 = d; null !== T2; ) {
10206
- g = T2;
10207
+ if ((a.stateNode.isHidden = c) && !g && 0 !== (a.mode & 1)) for (T = a, d = a.child; null !== d; ) {
10208
+ for (b = T = d; null !== T; ) {
10209
+ g = T;
10207
10210
  var h = g.child;
10208
10211
  switch (g.tag) {
10209
10212
  case 0:
@@ -10236,7 +10239,7 @@ var require_react_reconciler_production_min = __commonJS({
10236
10239
  continue;
10237
10240
  }
10238
10241
  }
10239
- null !== h ? (h.return = g, T2 = h) : ch(b);
10242
+ null !== h ? (h.return = g, T = h) : ch(b);
10240
10243
  }
10241
10244
  d = d.sibling;
10242
10245
  }
@@ -10325,12 +10328,12 @@ var require_react_reconciler_production_min = __commonJS({
10325
10328
  b & 4096 && (a.flags &= -4097);
10326
10329
  }
10327
10330
  function dh(a, b, c) {
10328
- T2 = a;
10331
+ T = a;
10329
10332
  eh(a, b, c);
10330
10333
  }
10331
10334
  function eh(a, b, c) {
10332
- for (var d = 0 !== (a.mode & 1); null !== T2; ) {
10333
- var e = T2, f = e.child;
10335
+ for (var d = 0 !== (a.mode & 1); null !== T; ) {
10336
+ var e = T, f = e.child;
10334
10337
  if (22 === e.tag && d) {
10335
10338
  var g = null !== e.memoizedState || Gg;
10336
10339
  if (!g) {
@@ -10338,19 +10341,19 @@ var require_react_reconciler_production_min = __commonJS({
10338
10341
  h = Gg;
10339
10342
  var l = S;
10340
10343
  Gg = g;
10341
- if ((S = k) && !l) for (T2 = e; null !== T2; ) g = T2, k = g.child, 22 === g.tag && null !== g.memoizedState ? fh(e) : null !== k ? (k.return = g, T2 = k) : fh(e);
10342
- for (; null !== f; ) T2 = f, eh(f, b, c), f = f.sibling;
10343
- T2 = e;
10344
+ if ((S = k) && !l) for (T = e; null !== T; ) g = T, k = g.child, 22 === g.tag && null !== g.memoizedState ? fh(e) : null !== k ? (k.return = g, T = k) : fh(e);
10345
+ for (; null !== f; ) T = f, eh(f, b, c), f = f.sibling;
10346
+ T = e;
10344
10347
  Gg = h;
10345
10348
  S = l;
10346
10349
  }
10347
10350
  gh(a, b, c);
10348
- } else 0 !== (e.subtreeFlags & 8772) && null !== f ? (f.return = e, T2 = f) : gh(a, b, c);
10351
+ } else 0 !== (e.subtreeFlags & 8772) && null !== f ? (f.return = e, T = f) : gh(a, b, c);
10349
10352
  }
10350
10353
  }
10351
10354
  function gh(a) {
10352
- for (; null !== T2; ) {
10353
- var b = T2;
10355
+ for (; null !== T; ) {
10356
+ var b = T;
10354
10357
  if (0 !== (b.flags & 8772)) {
10355
10358
  var c = b.alternate;
10356
10359
  try {
@@ -10422,37 +10425,37 @@ var require_react_reconciler_production_min = __commonJS({
10422
10425
  }
10423
10426
  }
10424
10427
  if (b === a) {
10425
- T2 = null;
10428
+ T = null;
10426
10429
  break;
10427
10430
  }
10428
10431
  c = b.sibling;
10429
10432
  if (null !== c) {
10430
10433
  c.return = b.return;
10431
- T2 = c;
10434
+ T = c;
10432
10435
  break;
10433
10436
  }
10434
- T2 = b.return;
10437
+ T = b.return;
10435
10438
  }
10436
10439
  }
10437
10440
  function ch(a) {
10438
- for (; null !== T2; ) {
10439
- var b = T2;
10441
+ for (; null !== T; ) {
10442
+ var b = T;
10440
10443
  if (b === a) {
10441
- T2 = null;
10444
+ T = null;
10442
10445
  break;
10443
10446
  }
10444
10447
  var c = b.sibling;
10445
10448
  if (null !== c) {
10446
10449
  c.return = b.return;
10447
- T2 = c;
10450
+ T = c;
10448
10451
  break;
10449
10452
  }
10450
- T2 = b.return;
10453
+ T = b.return;
10451
10454
  }
10452
10455
  }
10453
10456
  function fh(a) {
10454
- for (; null !== T2; ) {
10455
- var b = T2;
10457
+ for (; null !== T; ) {
10458
+ var b = T;
10456
10459
  try {
10457
10460
  switch (b.tag) {
10458
10461
  case 0:
@@ -10494,16 +10497,16 @@ var require_react_reconciler_production_min = __commonJS({
10494
10497
  U(b, b.return, k);
10495
10498
  }
10496
10499
  if (b === a) {
10497
- T2 = null;
10500
+ T = null;
10498
10501
  break;
10499
10502
  }
10500
10503
  var h = b.sibling;
10501
10504
  if (null !== h) {
10502
10505
  h.return = b.return;
10503
- T2 = h;
10506
+ T = h;
10504
10507
  break;
10505
10508
  }
10506
- T2 = b.return;
10509
+ T = b.return;
10507
10510
  }
10508
10511
  }
10509
10512
  var hh = 0, ih = 1, jh = 2, kh = 3, lh = 4;
@@ -11145,15 +11148,15 @@ var require_react_reconciler_production_min = __commonJS({
11145
11148
  if (0 !== (H & 6)) throw Error(n(331));
11146
11149
  var e = H;
11147
11150
  H |= 4;
11148
- for (T2 = a.current; null !== T2; ) {
11149
- var f = T2, g = f.child;
11150
- if (0 !== (T2.flags & 16)) {
11151
+ for (T = a.current; null !== T; ) {
11152
+ var f = T, g = f.child;
11153
+ if (0 !== (T.flags & 16)) {
11151
11154
  var h = f.deletions;
11152
11155
  if (null !== h) {
11153
11156
  for (var k = 0; k < h.length; k++) {
11154
11157
  var l = h[k];
11155
- for (T2 = l; null !== T2; ) {
11156
- var m = T2;
11158
+ for (T = l; null !== T; ) {
11159
+ var m = T;
11157
11160
  switch (m.tag) {
11158
11161
  case 0:
11159
11162
  case 11:
@@ -11161,21 +11164,21 @@ var require_react_reconciler_production_min = __commonJS({
11161
11164
  Mg(8, m, f);
11162
11165
  }
11163
11166
  var r = m.child;
11164
- if (null !== r) r.return = m, T2 = r;
11165
- else for (; null !== T2; ) {
11166
- m = T2;
11167
+ if (null !== r) r.return = m, T = r;
11168
+ else for (; null !== T; ) {
11169
+ m = T;
11167
11170
  var p = m.sibling, B = m.return;
11168
11171
  Pg(m);
11169
11172
  if (m === l) {
11170
- T2 = null;
11173
+ T = null;
11171
11174
  break;
11172
11175
  }
11173
11176
  if (null !== p) {
11174
11177
  p.return = B;
11175
- T2 = p;
11178
+ T = p;
11176
11179
  break;
11177
11180
  }
11178
- T2 = B;
11181
+ T = B;
11179
11182
  }
11180
11183
  }
11181
11184
  }
@@ -11191,12 +11194,12 @@ var require_react_reconciler_production_min = __commonJS({
11191
11194
  } while (null !== Y);
11192
11195
  }
11193
11196
  }
11194
- T2 = f;
11197
+ T = f;
11195
11198
  }
11196
11199
  }
11197
- if (0 !== (f.subtreeFlags & 2064) && null !== g) g.return = f, T2 = g;
11198
- else b: for (; null !== T2; ) {
11199
- f = T2;
11200
+ if (0 !== (f.subtreeFlags & 2064) && null !== g) g.return = f, T = g;
11201
+ else b: for (; null !== T; ) {
11202
+ f = T;
11200
11203
  if (0 !== (f.flags & 2048)) switch (f.tag) {
11201
11204
  case 0:
11202
11205
  case 11:
@@ -11206,19 +11209,19 @@ var require_react_reconciler_production_min = __commonJS({
11206
11209
  var E = f.sibling;
11207
11210
  if (null !== E) {
11208
11211
  E.return = f.return;
11209
- T2 = E;
11212
+ T = E;
11210
11213
  break b;
11211
11214
  }
11212
- T2 = f.return;
11215
+ T = f.return;
11213
11216
  }
11214
11217
  }
11215
11218
  var u = a.current;
11216
- for (T2 = u; null !== T2; ) {
11217
- g = T2;
11219
+ for (T = u; null !== T; ) {
11220
+ g = T;
11218
11221
  var t = g.child;
11219
- if (0 !== (g.subtreeFlags & 2064) && null !== t) t.return = g, T2 = t;
11220
- else b: for (g = u; null !== T2; ) {
11221
- h = T2;
11222
+ if (0 !== (g.subtreeFlags & 2064) && null !== t) t.return = g, T = t;
11223
+ else b: for (g = u; null !== T; ) {
11224
+ h = T;
11222
11225
  if (0 !== (h.flags & 2048)) try {
11223
11226
  switch (h.tag) {
11224
11227
  case 0:
@@ -11230,16 +11233,16 @@ var require_react_reconciler_production_min = __commonJS({
11230
11233
  U(h, h.return, lc);
11231
11234
  }
11232
11235
  if (h === g) {
11233
- T2 = null;
11236
+ T = null;
11234
11237
  break b;
11235
11238
  }
11236
11239
  var Db = h.sibling;
11237
11240
  if (null !== Db) {
11238
11241
  Db.return = h.return;
11239
- T2 = Db;
11242
+ T = Db;
11240
11243
  break b;
11241
11244
  }
11242
- T2 = h.return;
11245
+ T = h.return;
11243
11246
  }
11244
11247
  }
11245
11248
  H = e;
@@ -11979,9 +11982,9 @@ var require_react_reconciler_development = __commonJS({
11979
11982
  module.exports = function $$$reconciler($$$hostConfig) {
11980
11983
  var exports2 = {};
11981
11984
  "use strict";
11982
- var React18 = require_react();
11985
+ var React15 = require_react();
11983
11986
  var Scheduler = require_scheduler();
11984
- var ReactSharedInternals = React18.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
11987
+ var ReactSharedInternals = React15.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
11985
11988
  var suppressWarning = false;
11986
11989
  function setSuppressWarning(newSuppressWarning) {
11987
11990
  {
@@ -12045,7 +12048,7 @@ var require_react_reconciler_development = __commonJS({
12045
12048
  var HostPortal = 4;
12046
12049
  var HostComponent = 5;
12047
12050
  var HostText = 6;
12048
- var Fragment7 = 7;
12051
+ var Fragment5 = 7;
12049
12052
  var Mode = 8;
12050
12053
  var ContextConsumer = 9;
12051
12054
  var ContextProvider = 10;
@@ -12185,7 +12188,7 @@ var require_react_reconciler_development = __commonJS({
12185
12188
  return "DehydratedFragment";
12186
12189
  case ForwardRef:
12187
12190
  return getWrappedName$1(type, type.render, "ForwardRef");
12188
- case Fragment7:
12191
+ case Fragment5:
12189
12192
  return "Fragment";
12190
12193
  case HostComponent:
12191
12194
  return type;
@@ -15319,7 +15322,7 @@ var require_react_reconciler_development = __commonJS({
15319
15322
  }
15320
15323
  }
15321
15324
  function updateFragment2(returnFiber, current2, fragment, lanes, key) {
15322
- if (current2 === null || current2.tag !== Fragment7) {
15325
+ if (current2 === null || current2.tag !== Fragment5) {
15323
15326
  var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);
15324
15327
  created.return = returnFiber;
15325
15328
  return created;
@@ -15722,7 +15725,7 @@ var require_react_reconciler_development = __commonJS({
15722
15725
  if (child.key === key) {
15723
15726
  var elementType = element.type;
15724
15727
  if (elementType === REACT_FRAGMENT_TYPE) {
15725
- if (child.tag === Fragment7) {
15728
+ if (child.tag === Fragment5) {
15726
15729
  deleteRemainingChildren(returnFiber, child.sibling);
15727
15730
  var existing = useFiber(child, element.props.children);
15728
15731
  existing.return = returnFiber;
@@ -21213,7 +21216,7 @@ var require_react_reconciler_development = __commonJS({
21213
21216
  var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
21214
21217
  return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2);
21215
21218
  }
21216
- case Fragment7:
21219
+ case Fragment5:
21217
21220
  return updateFragment(current2, workInProgress2, renderLanes2);
21218
21221
  case Mode:
21219
21222
  return updateMode(current2, workInProgress2, renderLanes2);
@@ -21650,7 +21653,7 @@ var require_react_reconciler_development = __commonJS({
21650
21653
  case SimpleMemoComponent:
21651
21654
  case FunctionComponent:
21652
21655
  case ForwardRef:
21653
- case Fragment7:
21656
+ case Fragment5:
21654
21657
  case Mode:
21655
21658
  case Profiler:
21656
21659
  case ContextConsumer:
@@ -26418,7 +26421,7 @@ var require_react_reconciler_development = __commonJS({
26418
26421
  return fiber;
26419
26422
  }
26420
26423
  function createFiberFromFragment(elements, mode, lanes, key) {
26421
- var fiber = createFiber(Fragment7, elements, key, mode);
26424
+ var fiber = createFiber(Fragment5, elements, key, mode);
26422
26425
  fiber.lanes = lanes;
26423
26426
  return fiber;
26424
26427
  }
@@ -26858,10 +26861,10 @@ var require_react_reconciler_development = __commonJS({
26858
26861
  var setErrorHandler = null;
26859
26862
  var setSuspenseHandler = null;
26860
26863
  {
26861
- var copyWithDeleteImpl = function(obj, path, index2) {
26862
- var key = path[index2];
26864
+ var copyWithDeleteImpl = function(obj, path2, index2) {
26865
+ var key = path2[index2];
26863
26866
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
26864
- if (index2 + 1 === path.length) {
26867
+ if (index2 + 1 === path2.length) {
26865
26868
  if (isArray(updated)) {
26866
26869
  updated.splice(key, 1);
26867
26870
  } else {
@@ -26869,11 +26872,11 @@ var require_react_reconciler_development = __commonJS({
26869
26872
  }
26870
26873
  return updated;
26871
26874
  }
26872
- updated[key] = copyWithDeleteImpl(obj[key], path, index2 + 1);
26875
+ updated[key] = copyWithDeleteImpl(obj[key], path2, index2 + 1);
26873
26876
  return updated;
26874
26877
  };
26875
- var copyWithDelete = function(obj, path) {
26876
- return copyWithDeleteImpl(obj, path, 0);
26878
+ var copyWithDelete = function(obj, path2) {
26879
+ return copyWithDeleteImpl(obj, path2, 0);
26877
26880
  };
26878
26881
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
26879
26882
  var oldKey = oldPath[index2];
@@ -26911,17 +26914,17 @@ var require_react_reconciler_development = __commonJS({
26911
26914
  }
26912
26915
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
26913
26916
  };
26914
- var copyWithSetImpl = function(obj, path, index2, value) {
26915
- if (index2 >= path.length) {
26917
+ var copyWithSetImpl = function(obj, path2, index2, value) {
26918
+ if (index2 >= path2.length) {
26916
26919
  return value;
26917
26920
  }
26918
- var key = path[index2];
26921
+ var key = path2[index2];
26919
26922
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
26920
- updated[key] = copyWithSetImpl(obj[key], path, index2 + 1, value);
26923
+ updated[key] = copyWithSetImpl(obj[key], path2, index2 + 1, value);
26921
26924
  return updated;
26922
26925
  };
26923
- var copyWithSet = function(obj, path, value) {
26924
- return copyWithSetImpl(obj, path, 0, value);
26926
+ var copyWithSet = function(obj, path2, value) {
26927
+ return copyWithSetImpl(obj, path2, 0, value);
26925
26928
  };
26926
26929
  var findHook = function(fiber, id) {
26927
26930
  var currentHook2 = fiber.memoizedState;
@@ -26931,10 +26934,10 @@ var require_react_reconciler_development = __commonJS({
26931
26934
  }
26932
26935
  return currentHook2;
26933
26936
  };
26934
- overrideHookState = function(fiber, id, path, value) {
26937
+ overrideHookState = function(fiber, id, path2, value) {
26935
26938
  var hook = findHook(fiber, id);
26936
26939
  if (hook !== null) {
26937
- var newState = copyWithSet(hook.memoizedState, path, value);
26940
+ var newState = copyWithSet(hook.memoizedState, path2, value);
26938
26941
  hook.memoizedState = newState;
26939
26942
  hook.baseState = newState;
26940
26943
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -26944,10 +26947,10 @@ var require_react_reconciler_development = __commonJS({
26944
26947
  }
26945
26948
  }
26946
26949
  };
26947
- overrideHookStateDeletePath = function(fiber, id, path) {
26950
+ overrideHookStateDeletePath = function(fiber, id, path2) {
26948
26951
  var hook = findHook(fiber, id);
26949
26952
  if (hook !== null) {
26950
- var newState = copyWithDelete(hook.memoizedState, path);
26953
+ var newState = copyWithDelete(hook.memoizedState, path2);
26951
26954
  hook.memoizedState = newState;
26952
26955
  hook.baseState = newState;
26953
26956
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -26970,8 +26973,8 @@ var require_react_reconciler_development = __commonJS({
26970
26973
  }
26971
26974
  }
26972
26975
  };
26973
- overrideProps = function(fiber, path, value) {
26974
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
26976
+ overrideProps = function(fiber, path2, value) {
26977
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path2, value);
26975
26978
  if (fiber.alternate) {
26976
26979
  fiber.alternate.pendingProps = fiber.pendingProps;
26977
26980
  }
@@ -26980,8 +26983,8 @@ var require_react_reconciler_development = __commonJS({
26980
26983
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
26981
26984
  }
26982
26985
  };
26983
- overridePropsDeletePath = function(fiber, path) {
26984
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path);
26986
+ overridePropsDeletePath = function(fiber, path2) {
26987
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path2);
26985
26988
  if (fiber.alternate) {
26986
26989
  fiber.alternate.pendingProps = fiber.pendingProps;
26987
26990
  }
@@ -33042,10 +33045,10 @@ var init_source = __esm({
33042
33045
  object.level = options.level === void 0 ? colorLevel : options.level;
33043
33046
  };
33044
33047
  chalkFactory = (options) => {
33045
- const chalk10 = (...strings) => strings.join(" ");
33046
- applyOptions(chalk10, options);
33047
- Object.setPrototypeOf(chalk10, createChalk.prototype);
33048
- return chalk10;
33048
+ const chalk8 = (...strings) => strings.join(" ");
33049
+ applyOptions(chalk8, options);
33050
+ Object.setPrototypeOf(chalk8, createChalk.prototype);
33051
+ return chalk8;
33049
33052
  };
33050
33053
  Object.setPrototypeOf(createChalk.prototype, Function.prototype);
33051
33054
  for (const [styleName, style] of Object.entries(ansi_styles_default3)) {
@@ -35049,8 +35052,8 @@ var init_ErrorOverview = __esm({
35049
35052
  init_dist3();
35050
35053
  init_Box();
35051
35054
  init_Text();
35052
- cleanupPath = (path) => {
35053
- return path?.replace(`file://${cwd()}/`, "");
35055
+ cleanupPath = (path2) => {
35056
+ return path2?.replace(`file://${cwd()}/`, "");
35054
35057
  };
35055
35058
  stackUtils = new import_stack_utils.default({
35056
35059
  cwd: cwd(),
@@ -37932,7 +37935,7 @@ var require_react_jsx_runtime_development = __commonJS({
37932
37935
  if (process.env.NODE_ENV !== "production") {
37933
37936
  (function() {
37934
37937
  "use strict";
37935
- var React18 = require_react();
37938
+ var React15 = require_react();
37936
37939
  var REACT_ELEMENT_TYPE = Symbol.for("react.element");
37937
37940
  var REACT_PORTAL_TYPE = Symbol.for("react.portal");
37938
37941
  var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
@@ -37958,7 +37961,7 @@ var require_react_jsx_runtime_development = __commonJS({
37958
37961
  }
37959
37962
  return null;
37960
37963
  }
37961
- var ReactSharedInternals = React18.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
37964
+ var ReactSharedInternals = React15.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
37962
37965
  function error(format) {
37963
37966
  {
37964
37967
  {
@@ -38808,11 +38811,11 @@ var require_react_jsx_runtime_development = __commonJS({
38808
38811
  return jsxWithValidation(type, props, key, false);
38809
38812
  }
38810
38813
  }
38811
- var jsx12 = jsxWithValidationDynamic;
38812
- var jsxs14 = jsxWithValidationStatic;
38814
+ var jsx9 = jsxWithValidationDynamic;
38815
+ var jsxs11 = jsxWithValidationStatic;
38813
38816
  exports.Fragment = REACT_FRAGMENT_TYPE;
38814
- exports.jsx = jsx12;
38815
- exports.jsxs = jsxs14;
38817
+ exports.jsx = jsx9;
38818
+ exports.jsxs = jsxs11;
38816
38819
  })();
38817
38820
  }
38818
38821
  }
@@ -38955,25 +38958,29 @@ function sanitize(s) {
38955
38958
  return stripVTControlCharacters(s);
38956
38959
  }
38957
38960
  function sanitizeResponse(response) {
38958
- return {
38959
- ...response,
38960
- packages: response.packages.map((pkg) => ({
38961
- ...pkg,
38962
- name: sanitize(pkg.name),
38963
- version: sanitize(pkg.version),
38964
- findings: pkg.findings.map((f) => ({
38965
- ...f,
38966
- id: sanitize(f.id ?? ""),
38967
- title: sanitize(f.title),
38968
- evidence: f.evidence.map(sanitize)
38969
- })),
38970
- reasons: (pkg.reasons ?? []).map(sanitize),
38971
- recommendation: pkg.recommendation ? sanitize(pkg.recommendation) : void 0
38972
- })),
38973
- safeVersions: Object.fromEntries(
38974
- Object.entries(response.safeVersions).map(([k, v]) => [sanitize(k), sanitize(v)])
38975
- )
38961
+ const sanitized = {
38962
+ score: response.score,
38963
+ action: response.action,
38964
+ packages: response.packages.map((pkg) => {
38965
+ const clean = {
38966
+ name: sanitize(pkg.name),
38967
+ version: sanitize(pkg.version),
38968
+ score: pkg.score,
38969
+ findings: pkg.findings.map((f) => ({
38970
+ ...f,
38971
+ id: sanitize(f.id ?? ""),
38972
+ title: sanitize(f.title),
38973
+ evidence: f.evidence.map(sanitize)
38974
+ })),
38975
+ reasons: (pkg.reasons ?? []).map(sanitize)
38976
+ };
38977
+ if (pkg.recommendation) clean.recommendation = sanitize(pkg.recommendation);
38978
+ if (pkg.license) clean.license = pkg.license;
38979
+ return clean;
38980
+ })
38976
38981
  };
38982
+ if (response.durationMs) sanitized.durationMs = response.durationMs;
38983
+ return sanitized;
38977
38984
  }
38978
38985
  var init_sanitize = __esm({
38979
38986
  "src/sanitize.ts"() {
@@ -39237,9 +39244,9 @@ function parseLockfile(content) {
39237
39244
  const lockfileVersion = json.lockfileVersion ?? 1;
39238
39245
  const packages = /* @__PURE__ */ new Map();
39239
39246
  if (lockfileVersion >= 2 && json.packages) {
39240
- for (const [path, entry] of Object.entries(json.packages)) {
39241
- if (path === "") continue;
39242
- const name = extractPackageName(path);
39247
+ for (const [path2, entry] of Object.entries(json.packages)) {
39248
+ if (path2 === "") continue;
39249
+ const name = extractPackageName(path2);
39243
39250
  if (name && !packages.has(name)) {
39244
39251
  const e = entry;
39245
39252
  const deps = e.dependencies;
@@ -39475,23 +39482,38 @@ var init_parse_package_json = __esm({
39475
39482
  import { execFileSync as execFileSync2 } from "node:child_process";
39476
39483
  import { readFileSync as readFileSync6, existsSync as existsSync5, statSync } from "node:fs";
39477
39484
  import { join as join5 } from "node:path";
39478
- function readFileSafe(path) {
39479
- const size = statSync(path).size;
39485
+ function readFileSafe(path2) {
39486
+ const size = statSync(path2).size;
39480
39487
  if (size > MAX_LOCKFILE_BYTES) {
39481
- throw new Error(`Lockfile too large (${(size / 1024 / 1024).toFixed(0)} MB, max 50 MB): ${path}`);
39488
+ throw new Error(`Lockfile too large (${(size / 1024 / 1024).toFixed(0)} MB, max 50 MB): ${path2}`);
39482
39489
  }
39483
- return readFileSync6(path, "utf-8");
39490
+ return readFileSync6(path2, "utf-8");
39484
39491
  }
39485
39492
  function discoverChanges(cwd2, config) {
39486
39493
  if (config.workspace) {
39487
39494
  cwd2 = join5(cwd2, config.workspace);
39488
39495
  }
39489
39496
  const lockfileInfo = findLockfile(cwd2);
39497
+ const pythonDepFiles = ["requirements.txt", "Pipfile.lock", "poetry.lock"];
39498
+ let pythonPackages = [];
39499
+ for (const pyFile of pythonDepFiles) {
39500
+ if (existsSync5(join5(cwd2, pyFile))) {
39501
+ const pyPkgs = parsePythonDepFile(cwd2, pyFile);
39502
+ for (const p of pyPkgs) {
39503
+ if (p.version === "latest") continue;
39504
+ pythonPackages.push({ name: p.name, version: p.version, previousVersion: null, isNew: true });
39505
+ }
39506
+ break;
39507
+ }
39508
+ }
39490
39509
  if (!lockfileInfo) {
39491
- const pythonFiles = ["requirements.txt", "Pipfile.lock", "poetry.lock"];
39492
- const hasPython = pythonFiles.some((f) => existsSync5(join5(cwd2, f)));
39493
- if (hasPython) {
39494
- return { packages: [], method: "fallback", skipped: [] };
39510
+ if (pythonPackages.length > 0) {
39511
+ const skipped = [];
39512
+ if (pythonPackages.length > config.maxPackages) {
39513
+ skipped.push(...pythonPackages.slice(config.maxPackages).map((p) => `${p.name}@${p.version}`));
39514
+ pythonPackages = pythonPackages.slice(0, config.maxPackages);
39515
+ }
39516
+ return { packages: [], pythonPackages, method: "scan-all", skipped };
39495
39517
  }
39496
39518
  throw new Error(
39497
39519
  "No lockfile found (package-lock.json, yarn.lock, pnpm-lock.yaml, requirements.txt, Pipfile.lock, or poetry.lock). Run from your project root or use --base-lockfile."
@@ -39513,7 +39535,7 @@ function discoverChanges(cwd2, config) {
39513
39535
  isNew: true
39514
39536
  });
39515
39537
  }
39516
- return { packages: packages2, method: "scan-all", skipped: [] };
39538
+ return { packages: packages2, pythonPackages, method: "scan-all", skipped: [] };
39517
39539
  }
39518
39540
  if (config.baseLockfile) {
39519
39541
  if (!existsSync5(config.baseLockfile)) {
@@ -39524,6 +39546,7 @@ function discoverChanges(cwd2, config) {
39524
39546
  const diff2 = diffLockfiles(baseParsed, headParsed, config.maxPackages, directDeps);
39525
39547
  return {
39526
39548
  packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
39549
+ pythonPackages,
39527
39550
  method: "base-lockfile",
39528
39551
  skipped: diff2.skipped
39529
39552
  };
@@ -39534,6 +39557,7 @@ function discoverChanges(cwd2, config) {
39534
39557
  const diff2 = diffLockfiles(baseParsed, headParsed, config.maxPackages, directDeps);
39535
39558
  return {
39536
39559
  packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
39560
+ pythonPackages,
39537
39561
  method: "git-diff",
39538
39562
  skipped: diff2.skipped
39539
39563
  };
@@ -39553,6 +39577,7 @@ function discoverChanges(cwd2, config) {
39553
39577
  });
39554
39578
  return {
39555
39579
  packages: resolved.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
39580
+ pythonPackages,
39556
39581
  method: "fallback",
39557
39582
  skipped: []
39558
39583
  };
@@ -39570,7 +39595,7 @@ function discoverChanges(cwd2, config) {
39570
39595
  isNew: true
39571
39596
  });
39572
39597
  }
39573
- return { packages, method: "fallback", skipped: [] };
39598
+ return { packages, pythonPackages, method: "fallback", skipped: [] };
39574
39599
  }
39575
39600
  function findLockfile(cwd2) {
39576
39601
  const candidates = [
@@ -39919,13 +39944,272 @@ var init_pip_wrapper = __esm({
39919
39944
  }
39920
39945
  });
39921
39946
 
39947
+ // src/ui/components/FileSavePrompt.tsx
39948
+ var FileSavePrompt_exports = {};
39949
+ __export(FileSavePrompt_exports, {
39950
+ FileSavePrompt: () => FileSavePrompt
39951
+ });
39952
+ import * as fs2 from "fs";
39953
+ import * as path from "path";
39954
+ function listDirectory(dir) {
39955
+ try {
39956
+ const raw = fs2.readdirSync(dir, { withFileTypes: true });
39957
+ const entries = raw.map((e) => ({ name: e.name, isDirectory: e.isDirectory() })).sort((a, b) => {
39958
+ if (a.isDirectory !== b.isDirectory) return a.isDirectory ? -1 : 1;
39959
+ return a.name.localeCompare(b.name);
39960
+ });
39961
+ if (path.dirname(dir) !== dir) {
39962
+ entries.unshift({ name: "..", isDirectory: true });
39963
+ }
39964
+ return entries;
39965
+ } catch {
39966
+ return [{ name: "..", isDirectory: true }];
39967
+ }
39968
+ }
39969
+ function ensureJsonExtension(name) {
39970
+ if (!name) return "scan.json";
39971
+ if (name.endsWith(".json")) return name;
39972
+ return name + ".json";
39973
+ }
39974
+ function clamp(n, min, max) {
39975
+ return Math.max(min, Math.min(max, n));
39976
+ }
39977
+ function reducer2(state, action) {
39978
+ switch (action.type) {
39979
+ case "SET_FILENAME":
39980
+ return { ...state, filename: action.filename, cursorPos: action.cursorPos, focus: "filename", confirmOverwrite: false, error: null };
39981
+ case "EDIT_FILENAME":
39982
+ return { ...state, filename: action.filename, cursorPos: action.cursorPos, confirmOverwrite: false, error: null };
39983
+ case "SET_DIRECTORY":
39984
+ return { ...state, directory: action.directory, entries: action.entries, browserCursor: 0, browserViewport: 0, filterText: "", error: null };
39985
+ case "MOVE_BROWSER": {
39986
+ let viewport = state.browserViewport;
39987
+ if (action.cursor < viewport) viewport = action.cursor;
39988
+ if (action.cursor >= viewport + VISIBLE_ROWS) viewport = action.cursor - VISIBLE_ROWS + 1;
39989
+ return { ...state, browserCursor: action.cursor, browserViewport: viewport };
39990
+ }
39991
+ case "FOCUS":
39992
+ return { ...state, focus: action.target, filterText: action.target === "filename" ? "" : state.filterText };
39993
+ case "FILTER":
39994
+ return { ...state, filterText: action.text, browserCursor: 0, browserViewport: 0 };
39995
+ case "CONFIRM_OVERWRITE":
39996
+ return { ...state, confirmOverwrite: true };
39997
+ case "RESET_OVERWRITE":
39998
+ return { ...state, confirmOverwrite: false };
39999
+ case "SET_ERROR":
40000
+ return { ...state, error: action.error };
40001
+ }
40002
+ }
40003
+ var import_react25, import_chalk4, import_jsx_runtime3, VISIBLE_ROWS, FileSavePrompt;
40004
+ var init_FileSavePrompt = __esm({
40005
+ async "src/ui/components/FileSavePrompt.tsx"() {
40006
+ "use strict";
40007
+ import_react25 = __toESM(require_react());
40008
+ await init_build2();
40009
+ import_chalk4 = __toESM(require_source());
40010
+ import_jsx_runtime3 = __toESM(require_jsx_runtime());
40011
+ VISIBLE_ROWS = 15;
40012
+ FileSavePrompt = ({
40013
+ defaultName,
40014
+ directory: initialDir,
40015
+ score,
40016
+ action: scanAction,
40017
+ packageCount,
40018
+ onSave,
40019
+ onCancel
40020
+ }) => {
40021
+ const initialEntries = (0, import_react25.useMemo)(() => listDirectory(initialDir), [initialDir]);
40022
+ const [state, dispatch] = (0, import_react25.useReducer)(reducer2, {
40023
+ filename: defaultName,
40024
+ cursorPos: defaultName.length,
40025
+ directory: initialDir,
40026
+ entries: initialEntries,
40027
+ browserCursor: 0,
40028
+ browserViewport: 0,
40029
+ focus: "filename",
40030
+ filterText: "",
40031
+ confirmOverwrite: false,
40032
+ error: null
40033
+ });
40034
+ const filteredEntries = (0, import_react25.useMemo)(() => {
40035
+ const dirs = state.entries.filter((e) => e.isDirectory);
40036
+ if (!state.filterText) return dirs;
40037
+ const q = state.filterText.toLowerCase();
40038
+ return dirs.filter((e) => e.name.toLowerCase().includes(q));
40039
+ }, [state.entries, state.filterText]);
40040
+ const visibleEntries = filteredEntries.slice(
40041
+ state.browserViewport,
40042
+ state.browserViewport + VISIBLE_ROWS
40043
+ );
40044
+ use_input_default((input, key) => {
40045
+ if (key.escape) {
40046
+ onCancel();
40047
+ return;
40048
+ }
40049
+ if (state.focus === "filename") {
40050
+ if (key.return) {
40051
+ const fullName = ensureJsonExtension(state.filename);
40052
+ const fullPath = path.join(state.directory, fullName);
40053
+ if (!state.confirmOverwrite && fs2.existsSync(fullPath)) {
40054
+ dispatch({ type: "CONFIRM_OVERWRITE" });
40055
+ return;
40056
+ }
40057
+ onSave(fullPath);
40058
+ return;
40059
+ }
40060
+ if (key.downArrow) {
40061
+ dispatch({ type: "FOCUS", target: "browser" });
40062
+ return;
40063
+ }
40064
+ if (key.backspace || key.delete) {
40065
+ if (state.cursorPos > 0) {
40066
+ const next = state.filename.slice(0, state.cursorPos - 1) + state.filename.slice(state.cursorPos);
40067
+ dispatch({ type: "EDIT_FILENAME", filename: next, cursorPos: state.cursorPos - 1 });
40068
+ }
40069
+ return;
40070
+ }
40071
+ if (key.leftArrow) {
40072
+ dispatch({ type: "EDIT_FILENAME", filename: state.filename, cursorPos: Math.max(0, state.cursorPos - 1) });
40073
+ return;
40074
+ }
40075
+ if (key.rightArrow) {
40076
+ dispatch({ type: "EDIT_FILENAME", filename: state.filename, cursorPos: Math.min(state.filename.length, state.cursorPos + 1) });
40077
+ return;
40078
+ }
40079
+ if (input && /^[\x20-\x7e]+$/.test(input)) {
40080
+ const next = state.filename.slice(0, state.cursorPos) + input + state.filename.slice(state.cursorPos);
40081
+ dispatch({ type: "EDIT_FILENAME", filename: next, cursorPos: state.cursorPos + input.length });
40082
+ return;
40083
+ }
40084
+ return;
40085
+ }
40086
+ if (key.upArrow) {
40087
+ if (state.browserCursor > 0) {
40088
+ dispatch({ type: "MOVE_BROWSER", cursor: state.browserCursor - 1 });
40089
+ } else {
40090
+ dispatch({ type: "FOCUS", target: "filename" });
40091
+ }
40092
+ return;
40093
+ }
40094
+ if ((key.backspace || key.delete) && !state.filterText) {
40095
+ const parentDir = path.dirname(state.directory);
40096
+ if (parentDir !== state.directory) {
40097
+ dispatch({ type: "SET_DIRECTORY", directory: parentDir, entries: listDirectory(parentDir) });
40098
+ }
40099
+ return;
40100
+ }
40101
+ if (key.downArrow) {
40102
+ dispatch({ type: "MOVE_BROWSER", cursor: clamp(state.browserCursor + 1, 0, filteredEntries.length - 1) });
40103
+ return;
40104
+ }
40105
+ if (key.return) {
40106
+ const entry = filteredEntries[state.browserCursor];
40107
+ if (!entry || !entry.isDirectory) return;
40108
+ const newDir = entry.name === ".." ? path.dirname(state.directory) : path.join(state.directory, entry.name);
40109
+ dispatch({ type: "SET_DIRECTORY", directory: newDir, entries: listDirectory(newDir) });
40110
+ return;
40111
+ }
40112
+ if (key.backspace || key.delete) {
40113
+ dispatch({ type: "FILTER", text: state.filterText.slice(0, -1) });
40114
+ return;
40115
+ }
40116
+ if (input && /^[\x20-\x7e]+$/.test(input)) {
40117
+ dispatch({ type: "FILTER", text: state.filterText + input });
40118
+ }
40119
+ });
40120
+ const actionColor2 = scanAction === "block" ? import_chalk4.default.red : scanAction === "warn" ? import_chalk4.default.yellow : import_chalk4.default.green;
40121
+ const filenameDisplay = state.filename.slice(0, state.cursorPos) + (state.focus === "filename" ? import_chalk4.default.inverse(state.filename[state.cursorPos] || " ") : "") + state.filename.slice(state.cursorPos + 1);
40122
+ const shortDir = state.directory.replace(process.env.HOME || "", "~");
40123
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, children: [
40124
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
40125
+ import_chalk4.default.cyan("\u25C6"),
40126
+ " ",
40127
+ import_chalk4.default.bold("Save Scan Results")
40128
+ ] }),
40129
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
40130
+ "Score: ",
40131
+ import_chalk4.default.bold(String(score)),
40132
+ " ",
40133
+ actionColor2(scanAction.toUpperCase()),
40134
+ " ",
40135
+ import_chalk4.default.dim("\u2502"),
40136
+ " ",
40137
+ packageCount,
40138
+ " packages scanned"
40139
+ ] }),
40140
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: "" }),
40141
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
40142
+ state.focus === "filename" ? import_chalk4.default.cyan("\u258C") : " ",
40143
+ import_chalk4.default.bold("File:"),
40144
+ " ",
40145
+ filenameDisplay,
40146
+ import_chalk4.default.dim(".json")
40147
+ ] }),
40148
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: import_chalk4.default.dim(` \u2500\u2500\u2500 ${shortDir} \u2500\u2500\u2500 [${state.browserCursor + 1}/${filteredEntries.length}]`) }),
40149
+ visibleEntries.map((entry, i) => {
40150
+ const realIdx = state.browserViewport + i;
40151
+ const isCursor = state.focus === "browser" && realIdx === state.browserCursor;
40152
+ const prefix = isCursor ? import_chalk4.default.cyan("\u258C") : " ";
40153
+ const icon = entry.isDirectory ? "\u{1F4C1} " : " ";
40154
+ const name = entry.isDirectory ? import_chalk4.default.bold(entry.name + "/") : entry.name;
40155
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
40156
+ prefix,
40157
+ icon,
40158
+ name
40159
+ ] }, `${entry.name}-${i}`);
40160
+ }),
40161
+ filteredEntries.length > VISIBLE_ROWS && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { dimColor: true, children: [
40162
+ " ",
40163
+ import_chalk4.default.dim(`\u2191\u2193 ${filteredEntries.length - VISIBLE_ROWS} more`)
40164
+ ] }),
40165
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: "" }),
40166
+ state.filterText && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { dimColor: true, children: [
40167
+ ' filter: "',
40168
+ state.filterText,
40169
+ '" (',
40170
+ filteredEntries.length,
40171
+ " matches)"
40172
+ ] }),
40173
+ state.confirmOverwrite && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "yellow", children: [
40174
+ " ",
40175
+ import_chalk4.default.yellow("\u26A0"),
40176
+ " ",
40177
+ ensureJsonExtension(state.filename),
40178
+ " exists ",
40179
+ import_chalk4.default.dim("\u2014"),
40180
+ " Enter again to overwrite"
40181
+ ] }),
40182
+ state.error && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "red", children: [
40183
+ " ",
40184
+ import_chalk4.default.red("\u2717"),
40185
+ " ",
40186
+ state.error
40187
+ ] }),
40188
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
40189
+ import_chalk4.default.bold.hex("#FFD700")("\u23CE"),
40190
+ " ",
40191
+ import_chalk4.default.bold.hex("#FFD700")("save"),
40192
+ " ",
40193
+ import_chalk4.default.bold.cyan("\u2191\u2193"),
40194
+ " ",
40195
+ import_chalk4.default.dim("browse"),
40196
+ " ",
40197
+ import_chalk4.default.bold.cyan("esc"),
40198
+ " ",
40199
+ import_chalk4.default.dim("cancel")
40200
+ ] })
40201
+ ] });
40202
+ };
40203
+ }
40204
+ });
40205
+
39922
40206
  // src/discover.ts
39923
40207
  var discover_exports = {};
39924
40208
  __export(discover_exports, {
39925
40209
  discoverProjects: () => discoverProjects
39926
40210
  });
39927
- import { existsSync as existsSync7, readFileSync as readFileSync8, readdirSync, lstatSync } from "node:fs";
39928
- import { join as join6, relative, basename } from "node:path";
40211
+ import { existsSync as existsSync8, readFileSync as readFileSync8, readdirSync as readdirSync2, lstatSync } from "node:fs";
40212
+ import { join as join7, relative, basename } from "node:path";
39929
40213
  function discoverProjects(root) {
39930
40214
  const projects = [];
39931
40215
  walk(root, root, 0, projects);
@@ -39934,8 +40218,8 @@ function discoverProjects(root) {
39934
40218
  function walk(dir, root, depth, out) {
39935
40219
  if (depth > MAX_DEPTH) return;
39936
40220
  for (const lockfile of NPM_LOCKFILES) {
39937
- const lockPath = join6(dir, lockfile);
39938
- if (existsSync7(lockPath)) {
40221
+ const lockPath = join7(dir, lockfile);
40222
+ if (existsSync8(lockPath)) {
39939
40223
  const count = countNpmPackages(lockPath);
39940
40224
  if (count > 0) {
39941
40225
  out.push({
@@ -39950,8 +40234,8 @@ function walk(dir, root, depth, out) {
39950
40234
  }
39951
40235
  }
39952
40236
  for (const depFile of PYTHON_DEPFILES) {
39953
- const depPath = join6(dir, depFile);
39954
- if (existsSync7(depPath)) {
40237
+ const depPath = join7(dir, depFile);
40238
+ if (existsSync8(depPath)) {
39955
40239
  const count = countPythonPackages(depPath, depFile);
39956
40240
  if (count > 0) {
39957
40241
  out.push({
@@ -39967,13 +40251,13 @@ function walk(dir, root, depth, out) {
39967
40251
  }
39968
40252
  let entries;
39969
40253
  try {
39970
- entries = readdirSync(dir);
40254
+ entries = readdirSync2(dir);
39971
40255
  } catch {
39972
40256
  return;
39973
40257
  }
39974
40258
  for (const entry of entries) {
39975
40259
  if (SKIP_DIRS.has(entry) || entry.startsWith(".")) continue;
39976
- const full = join6(dir, entry);
40260
+ const full = join7(dir, entry);
39977
40261
  try {
39978
40262
  const st = lstatSync(full);
39979
40263
  if (st.isDirectory() && !st.isSymbolicLink()) {
@@ -40067,10 +40351,72 @@ __export(static_output_exports, {
40067
40351
  runStaticNpm: () => runStaticNpm,
40068
40352
  runStaticPip: () => runStaticPip
40069
40353
  });
40354
+ function writeJsonFile(filepath, json) {
40355
+ const fs3 = __require("fs");
40356
+ const path2 = __require("path");
40357
+ const resolved = path2.resolve(filepath);
40358
+ try {
40359
+ fs3.writeFileSync(resolved, json + "\n");
40360
+ process.stderr.write(import_chalk5.default.green(` \u2713 Saved to ${resolved}
40361
+
40362
+ `));
40363
+ } catch (err) {
40364
+ const msg = err instanceof Error ? err.message : String(err);
40365
+ process.stderr.write(import_chalk5.default.red(` Error saving file: ${msg}
40366
+
40367
+ `));
40368
+ }
40369
+ }
40370
+ async function handleJsonOutput(result, config) {
40371
+ if (!config.json) return false;
40372
+ const json = JSON.stringify(result, null, 2);
40373
+ if (config.outputFile) {
40374
+ writeJsonFile(config.outputFile, json);
40375
+ return true;
40376
+ }
40377
+ if (!process.stdout.isTTY) {
40378
+ process.stdout.write(json + "\n");
40379
+ return true;
40380
+ }
40381
+ const localDate = (/* @__PURE__ */ new Date()).toLocaleDateString("sv-SE");
40382
+ const defaultName = `dg-scan-${localDate}`;
40383
+ const { render: render2 } = await init_build2().then(() => build_exports);
40384
+ const React15 = await Promise.resolve().then(() => __toESM(require_react()));
40385
+ const { FileSavePrompt: FileSavePrompt2 } = await init_FileSavePrompt().then(() => FileSavePrompt_exports);
40386
+ await new Promise((resolve) => {
40387
+ const inkInstance = render2(
40388
+ React15.createElement(FileSavePrompt2, {
40389
+ defaultName,
40390
+ directory: process.cwd(),
40391
+ score: result.score,
40392
+ action: result.action,
40393
+ packageCount: result.packages.length,
40394
+ onSave: (filepath) => {
40395
+ const fs3 = __require("fs");
40396
+ try {
40397
+ fs3.writeFileSync(filepath, json + "\n");
40398
+ inkInstance.unmount();
40399
+ process.stderr.write(import_chalk5.default.green(` \u2713 Saved to ${filepath}
40400
+
40401
+ `));
40402
+ } catch (err) {
40403
+ }
40404
+ resolve();
40405
+ },
40406
+ onCancel: () => {
40407
+ inkInstance.unmount();
40408
+ process.stderr.write(import_chalk5.default.dim(" Cancelled.\n\n"));
40409
+ resolve();
40410
+ }
40411
+ })
40412
+ );
40413
+ });
40414
+ return true;
40415
+ }
40070
40416
  function printTrialBanner(result) {
40071
40417
  if (result.trialScansRemaining === void 0) return;
40072
40418
  process.stderr.write(
40073
- import_chalk4.default.dim(` Free tier \xB7 Run \`dg login\` for finding details and higher rate limits.
40419
+ import_chalk5.default.dim(` Free tier \xB7 Run \`dg login\` for higher scan limits.
40074
40420
  `)
40075
40421
  );
40076
40422
  }
@@ -40082,7 +40428,7 @@ function handleTrialExhausted2(error, jsonMode = false) {
40082
40428
  hasKey = !!getStoredApiKey2();
40083
40429
  } catch {
40084
40430
  }
40085
- const message = hasKey ? "Your API key may be invalid or expired. Run `dg logout` then `dg login` to re-authenticate." : "Free trial scans used up. Run `dg login` to create a free account and continue scanning.";
40431
+ const message = hasKey ? "Your API key may be invalid or expired. Run `dg logout` then `dg login` to re-authenticate." : "Monthly scan limit reached. Run `dg login` to create a free account for higher limits.";
40086
40432
  if (jsonMode) {
40087
40433
  process.stdout.write(JSON.stringify({
40088
40434
  error: true,
@@ -40093,13 +40439,13 @@ function handleTrialExhausted2(error, jsonMode = false) {
40093
40439
  }, null, 2) + "\n");
40094
40440
  } else {
40095
40441
  if (hasKey) {
40096
- process.stderr.write(import_chalk4.default.yellow(`
40442
+ process.stderr.write(import_chalk5.default.yellow(`
40097
40443
  ${message}
40098
40444
 
40099
40445
  `));
40100
40446
  } else {
40101
40447
  process.stderr.write(
40102
- import_chalk4.default.yellow("\n Free trial scans used up.\n") + import_chalk4.default.white(" Run `dg login` to create a free account and continue scanning.\n\n")
40448
+ import_chalk5.default.yellow("\n Monthly scan limit reached (200 scans/month on free tier).\n") + import_chalk5.default.white(" Run `dg login` for higher limits, or upgrade at westbayberry.com/pricing\n\n")
40103
40449
  );
40104
40450
  }
40105
40451
  }
@@ -40109,9 +40455,9 @@ function handleTrialExhausted2(error, jsonMode = false) {
40109
40455
  return false;
40110
40456
  }
40111
40457
  function actionColor(action) {
40112
- if (action === "block") return import_chalk4.default.red;
40113
- if (action === "warn") return import_chalk4.default.yellow;
40114
- return import_chalk4.default.green;
40458
+ if (action === "block") return import_chalk5.default.red;
40459
+ if (action === "warn") return import_chalk5.default.yellow;
40460
+ return import_chalk5.default.green;
40115
40461
  }
40116
40462
  function pad(s, len) {
40117
40463
  return s + " ".repeat(Math.max(0, len - s.length));
@@ -40131,21 +40477,18 @@ function groupPackages(packages) {
40131
40477
  return [...map.values()].map((pkgs) => ({ packages: pkgs, key: pkgs[0].name })).sort((a, b) => b.packages[0].score - a.packages[0].score);
40132
40478
  }
40133
40479
  function actionBadge(score) {
40134
- if (score >= 70) return { label: "BLOCK", color: import_chalk4.default.red };
40135
- if (score >= 60) return { label: "WARN", color: import_chalk4.default.yellow };
40136
- return { label: "pass", color: import_chalk4.default.green };
40480
+ if (score >= 70) return { label: "BLOCK", color: import_chalk5.default.red };
40481
+ if (score >= 60) return { label: "WARN", color: import_chalk5.default.yellow };
40482
+ return { label: "pass", color: import_chalk5.default.green };
40137
40483
  }
40138
- function renderResultStatic(result, config) {
40139
- if (config.json) {
40140
- return JSON.stringify(result, null, 2);
40141
- }
40484
+ function renderResultStatic(result, _config) {
40142
40485
  const lines = [];
40143
40486
  const actionStr = result.action.toUpperCase();
40144
40487
  const colorAction = actionColor(result.action);
40145
40488
  lines.push("");
40146
- lines.push(` ${import_chalk4.default.bold("Dependency Guardian")}`);
40489
+ lines.push(` ${import_chalk5.default.bold("Dependency Guardian")}`);
40147
40490
  lines.push(
40148
- ` Score: ${import_chalk4.default.bold(String(result.score))}${" ".repeat(
40491
+ ` Score: ${import_chalk5.default.bold(String(result.score))}${" ".repeat(
40149
40492
  Math.max(1, 50 - String(result.score).length)
40150
40493
  )}${colorAction(actionStr)}`
40151
40494
  );
@@ -40155,11 +40498,11 @@ function renderResultStatic(result, config) {
40155
40498
  const total = result.packages.length;
40156
40499
  if (flagged.length > 0) {
40157
40500
  lines.push(
40158
- ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk4.default.dim("\u2502")} ${import_chalk4.default.yellow(`${flagged.length} flagged`)} \u2502 ${import_chalk4.default.green(`${clean.length} clean`)}`
40501
+ ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk5.default.dim("\u2502")} ${import_chalk5.default.yellow(`${flagged.length} flagged`)} \u2502 ${import_chalk5.default.green(`${clean.length} clean`)}`
40159
40502
  );
40160
40503
  } else {
40161
40504
  lines.push(
40162
- ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk4.default.dim("\u2502")} ${import_chalk4.default.green("all clean")}`
40505
+ ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk5.default.dim("\u2502")} ${import_chalk5.default.green("all clean")}`
40163
40506
  );
40164
40507
  }
40165
40508
  const licensedPkgs = result.packages.filter((p) => p.license);
@@ -40168,7 +40511,7 @@ function renderResultStatic(result, config) {
40168
40511
  );
40169
40512
  if (licenseIssues.length > 0) {
40170
40513
  lines.push(
40171
- ` ${import_chalk4.default.dim("Licenses:")} ${import_chalk4.default.yellow(`${licenseIssues.length} need review`)} \u2502 ${import_chalk4.default.green(`${licensedPkgs.length - licenseIssues.length} permissive`)}`
40514
+ ` ${import_chalk5.default.dim("Licenses:")} ${import_chalk5.default.yellow(`${licenseIssues.length} need review`)} \u2502 ${import_chalk5.default.green(`${licensedPkgs.length - licenseIssues.length} permissive`)}`
40172
40515
  );
40173
40516
  }
40174
40517
  lines.push("");
@@ -40179,30 +40522,30 @@ function renderResultStatic(result, config) {
40179
40522
  }
40180
40523
  const groups = groupPackages(flagged);
40181
40524
  if (flagged.length > 0) {
40182
- lines.push(` ${import_chalk4.default.bold("Flagged Packages")}`);
40183
- lines.push(` ${import_chalk4.default.dim("\u2500".repeat(60))}`);
40525
+ lines.push(` ${import_chalk5.default.bold("Flagged Packages")}`);
40526
+ lines.push(` ${import_chalk5.default.dim("\u2500".repeat(60))}`);
40184
40527
  for (const group of groups) {
40185
40528
  const rep = group.packages[0];
40186
40529
  const { label, color } = actionBadge(rep.score);
40187
40530
  const names = group.packages.length === 1 ? rep.name : group.packages.length <= 3 ? group.packages.map((p) => p.name).join(", ") : `${group.packages[0].name} + ${group.packages.length - 1} similar`;
40188
40531
  const lcInfo = rep.license;
40189
40532
  const lcStr = lcInfo ? truncate(lcInfo.spdx ?? lcInfo.raw ?? "", 14) : "";
40190
- const lcColor = !lcInfo ? import_chalk4.default.dim : lcInfo.riskCategory === "permissive" ? import_chalk4.default.green : lcInfo.riskCategory === "no-license" || lcInfo.riskCategory === "unlicensed" || lcInfo.riskCategory === "network-copyleft" ? import_chalk4.default.red : import_chalk4.default.yellow;
40533
+ const lcColor = !lcInfo ? import_chalk5.default.dim : lcInfo.riskCategory === "permissive" ? import_chalk5.default.green : lcInfo.riskCategory === "no-license" || lcInfo.riskCategory === "unlicensed" || lcInfo.riskCategory === "network-copyleft" ? import_chalk5.default.red : import_chalk5.default.yellow;
40191
40534
  lines.push(
40192
- ` ${color(pad(label, 7))}${import_chalk4.default.bold(pad(truncate(names, 36), 38))}${lcColor(pad(lcStr, 16))}${import_chalk4.default.dim(`score ${rep.score}`)}`
40535
+ ` ${color(pad(label, 7))}${import_chalk5.default.bold(pad(truncate(names, 36), 38))}${lcColor(pad(lcStr, 16))}${import_chalk5.default.dim(`score ${rep.score}`)}`
40193
40536
  );
40194
40537
  }
40195
40538
  lines.push("");
40196
40539
  }
40197
40540
  if (clean.length > 0) {
40198
40541
  lines.push(
40199
- ` ${import_chalk4.default.green("\u2713")} ${import_chalk4.default.dim(`${clean.length} package${clean.length !== 1 ? "s" : ""} passed with score 0`)}`
40542
+ ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.dim(`${clean.length} package${clean.length !== 1 ? "s" : ""} passed with score 0`)}`
40200
40543
  );
40201
40544
  lines.push("");
40202
40545
  }
40203
40546
  if (result.durationMs) {
40204
40547
  lines.push(
40205
- ` ${import_chalk4.default.dim(`Completed in ${(result.durationMs / 1e3).toFixed(1)}s`)}`
40548
+ ` ${import_chalk5.default.dim(`Completed in ${(result.durationMs / 1e3).toFixed(1)}s`)}`
40206
40549
  );
40207
40550
  lines.push("");
40208
40551
  }
@@ -40211,12 +40554,12 @@ function renderResultStatic(result, config) {
40211
40554
  async function runStatic(config) {
40212
40555
  const dbg = (msg) => {
40213
40556
  if (config.debug)
40214
- process.stderr.write(import_chalk4.default.dim(` [debug] ${msg}
40557
+ process.stderr.write(import_chalk5.default.dim(` [debug] ${msg}
40215
40558
  `));
40216
40559
  };
40217
40560
  if (config.mode === "off") {
40218
40561
  process.stderr.write(
40219
- import_chalk4.default.dim(" Dependency Guardian: mode is off \u2014 skipping.\n")
40562
+ import_chalk5.default.dim(" Dependency Guardian: mode is off \u2014 skipping.\n")
40220
40563
  );
40221
40564
  process.exit(0);
40222
40565
  }
@@ -40224,40 +40567,44 @@ async function runStatic(config) {
40224
40567
  `mode=${config.mode} max=${config.maxPackages}`
40225
40568
  );
40226
40569
  dbg(`api=${config.apiUrl}`);
40227
- process.stderr.write(import_chalk4.default.dim(" Discovering package changes...\n"));
40570
+ process.stderr.write(import_chalk5.default.dim(" Discovering package changes...\n"));
40228
40571
  const discovery = discoverChanges(process.cwd(), config);
40229
40572
  dbg(`discovery method: ${discovery.method}`);
40230
- if (discovery.packages.length === 0) {
40573
+ if (discovery.pythonPackages.length > 0) {
40574
+ dbg(`python packages: ${discovery.pythonPackages.length}`);
40575
+ }
40576
+ if (discovery.packages.length === 0 && discovery.pythonPackages.length === 0) {
40231
40577
  const { discoverProjects: discoverProjects2 } = await Promise.resolve().then(() => (init_discover(), discover_exports));
40232
40578
  const subProjects = discoverProjects2(process.cwd());
40233
40579
  if (subProjects.length > 0) {
40234
- process.stderr.write(import_chalk4.default.yellow(" No packages found in current directory, but found projects in subdirectories:\n\n"));
40580
+ process.stderr.write(import_chalk5.default.yellow(" No packages found in current directory, but found projects in subdirectories:\n\n"));
40235
40581
  for (const proj of subProjects) {
40236
40582
  const pkgLabel = proj.packageCount === 1 ? "package" : "packages";
40237
40583
  process.stderr.write(
40238
- import_chalk4.default.white(` ${proj.ecosystem} `) + import_chalk4.default.cyan(proj.relativePath) + import_chalk4.default.dim(` (${proj.packageCount} ${pkgLabel})
40584
+ import_chalk5.default.white(` ${proj.ecosystem} `) + import_chalk5.default.cyan(proj.relativePath) + import_chalk5.default.dim(` (${proj.packageCount} ${pkgLabel})
40239
40585
  `)
40240
40586
  );
40241
40587
  }
40242
- process.stderr.write(import_chalk4.default.dim("\n Use --workspace to scan a specific project:\n"));
40243
- process.stderr.write(import_chalk4.default.dim(` dg scan --workspace ${subProjects[0].relativePath}${config.scanAll ? " --scan-all" : ""}
40588
+ process.stderr.write(import_chalk5.default.dim("\n Use --workspace to scan a specific project:\n"));
40589
+ process.stderr.write(import_chalk5.default.dim(` dg scan --workspace ${subProjects[0].relativePath}${config.scanAll ? " --scan-all" : ""}
40244
40590
 
40245
40591
  `));
40246
40592
  } else {
40247
- process.stderr.write(import_chalk4.default.dim(" No package changes detected.\n"));
40593
+ process.stderr.write(import_chalk5.default.dim(" No package changes detected.\n"));
40248
40594
  }
40249
40595
  process.exit(0);
40250
40596
  }
40251
40597
  const packages = discovery.packages;
40598
+ const totalToScan = packages.length + discovery.pythonPackages.length;
40252
40599
  process.stderr.write(
40253
- import_chalk4.default.dim(
40254
- ` Scanning ${packages.length} package${packages.length !== 1 ? "s" : ""} (${discovery.method})...
40600
+ import_chalk5.default.dim(
40601
+ ` Scanning ${totalToScan} package${totalToScan !== 1 ? "s" : ""}${discovery.pythonPackages.length > 0 ? ` (${packages.length} npm + ${discovery.pythonPackages.length} Python)` : ""} (${discovery.method})...
40255
40602
  `
40256
40603
  )
40257
40604
  );
40258
40605
  if (discovery.skipped.length > 0) {
40259
40606
  process.stderr.write(
40260
- import_chalk4.default.yellow(
40607
+ import_chalk5.default.yellow(
40261
40608
  ` Warning: ${discovery.skipped.length} package(s) skipped (max-packages=${config.maxPackages})
40262
40609
  `
40263
40610
  )
@@ -40269,10 +40616,29 @@ async function runStatic(config) {
40269
40616
  let result;
40270
40617
  try {
40271
40618
  const startMs = Date.now();
40272
- result = await callAnalyzeAPI(packages, config, (done, total) => {
40273
- process.stderr.write(import_chalk4.default.dim(` Analyzed ${done}/${total}...
40619
+ if (packages.length > 0) {
40620
+ result = await callAnalyzeAPI(packages, config, (done, total) => {
40621
+ process.stderr.write(import_chalk5.default.dim(` Analyzed ${done}/${total}...
40274
40622
  `));
40275
- });
40623
+ });
40624
+ } else {
40625
+ result = { score: 0, action: "pass", packages: [], safeVersions: {} };
40626
+ }
40627
+ if (discovery.pythonPackages.length > 0) {
40628
+ process.stderr.write(
40629
+ import_chalk5.default.dim(` Scanning ${discovery.pythonPackages.length} Python package${discovery.pythonPackages.length !== 1 ? "s" : ""}...
40630
+ `)
40631
+ );
40632
+ const pyResult = await callPyPIAnalyzeAPI(discovery.pythonPackages, config);
40633
+ result.packages.push(...pyResult.packages);
40634
+ result.score = Math.max(result.score, pyResult.score);
40635
+ if (pyResult.action === "block" || pyResult.action === "warn" && result.action === "pass") {
40636
+ result.action = pyResult.action;
40637
+ }
40638
+ if (pyResult.trialScansRemaining !== void 0) {
40639
+ result.trialScansRemaining = pyResult.trialScansRemaining;
40640
+ }
40641
+ }
40276
40642
  dbg(
40277
40643
  `API responded in ${Date.now() - startMs}ms, action=${result.action}, score=${result.score}`
40278
40644
  );
@@ -40280,6 +40646,13 @@ async function runStatic(config) {
40280
40646
  if (handleTrialExhausted2(error, config.json)) return;
40281
40647
  throw error;
40282
40648
  }
40649
+ const jsonHandled = await handleJsonOutput(result, config);
40650
+ if (jsonHandled) {
40651
+ printTrialBanner(result);
40652
+ if (result.action === "block" && config.mode === "block") process.exit(2);
40653
+ else if (result.action === "block" || result.action === "warn") process.exit(1);
40654
+ process.exit(0);
40655
+ }
40283
40656
  const output = renderResultStatic(result, config);
40284
40657
  process.stdout.write(output + "\n");
40285
40658
  printTrialBanner(result);
@@ -40300,7 +40673,7 @@ async function runStaticNpm(npmArgs, config) {
40300
40673
  const bareSpecs = readBareInstallPackages(process.cwd());
40301
40674
  if (bareSpecs.length === 0) {
40302
40675
  process.stderr.write(
40303
- import_chalk4.default.dim(
40676
+ import_chalk5.default.dim(
40304
40677
  " Dependency Guardian: no packages to scan, passing through to npm.\n"
40305
40678
  )
40306
40679
  );
@@ -40308,7 +40681,7 @@ async function runStaticNpm(npmArgs, config) {
40308
40681
  process.exit(code);
40309
40682
  }
40310
40683
  process.stderr.write(
40311
- import_chalk4.default.dim(
40684
+ import_chalk5.default.dim(
40312
40685
  ` Resolving ${bareSpecs.length} package${bareSpecs.length !== 1 ? "s" : ""} from package.json...
40313
40686
  `
40314
40687
  )
@@ -40316,7 +40689,7 @@ async function runStaticNpm(npmArgs, config) {
40316
40689
  const { resolved: resolved2, failed: failed2 } = await resolvePackages(bareSpecs);
40317
40690
  if (failed2.length > 0 && config.debug) {
40318
40691
  process.stderr.write(
40319
- import_chalk4.default.dim(
40692
+ import_chalk5.default.dim(
40320
40693
  ` [debug] Could not resolve: ${failed2.slice(0, 5).join(", ")}${failed2.length > 5 ? ` (+${failed2.length - 5} more)` : ""}
40321
40694
  `
40322
40695
  )
@@ -40325,7 +40698,7 @@ async function runStaticNpm(npmArgs, config) {
40325
40698
  return scanAndInstallStatic(resolved2, parsed, config);
40326
40699
  }
40327
40700
  process.stderr.write(
40328
- import_chalk4.default.dim(
40701
+ import_chalk5.default.dim(
40329
40702
  ` Resolving ${parsed.packages.length} package${parsed.packages.length !== 1 ? "s" : ""}...
40330
40703
  `
40331
40704
  )
@@ -40333,7 +40706,7 @@ async function runStaticNpm(npmArgs, config) {
40333
40706
  const { resolved, failed } = await resolvePackages(parsed.packages);
40334
40707
  if (failed.length > 0) {
40335
40708
  process.stderr.write(
40336
- import_chalk4.default.yellow(
40709
+ import_chalk5.default.yellow(
40337
40710
  ` Warning: Could not resolve versions for: ${failed.join(", ")}
40338
40711
  `
40339
40712
  )
@@ -40341,7 +40714,7 @@ async function runStaticNpm(npmArgs, config) {
40341
40714
  }
40342
40715
  if (resolved.length === 0) {
40343
40716
  process.stderr.write(
40344
- import_chalk4.default.dim(" No packages to scan. Passing through to npm.\n")
40717
+ import_chalk5.default.dim(" No packages to scan. Passing through to npm.\n")
40345
40718
  );
40346
40719
  const code = await runNpm(parsed.rawArgs);
40347
40720
  process.exit(code);
@@ -40350,7 +40723,7 @@ async function runStaticNpm(npmArgs, config) {
40350
40723
  }
40351
40724
  async function scanAndInstallStatic(resolved, parsed, config) {
40352
40725
  process.stderr.write(
40353
- import_chalk4.default.dim(
40726
+ import_chalk5.default.dim(
40354
40727
  ` Scanning ${resolved.length} package${resolved.length !== 1 ? "s" : ""}...
40355
40728
  `
40356
40729
  )
@@ -40362,7 +40735,7 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40362
40735
  const elapsed = Date.now() - startMs;
40363
40736
  if (config.debug) {
40364
40737
  process.stderr.write(
40365
- import_chalk4.default.dim(
40738
+ import_chalk5.default.dim(
40366
40739
  ` [debug] API responded in ${elapsed}ms, action=${result.action}, score=${result.score}
40367
40740
  `
40368
40741
  )
@@ -40372,7 +40745,7 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40372
40745
  if (handleTrialExhausted2(error, config.json)) return;
40373
40746
  const msg = error instanceof Error ? error.message : String(error);
40374
40747
  process.stderr.write(
40375
- import_chalk4.default.yellow(
40748
+ import_chalk5.default.yellow(
40376
40749
  ` Warning: Scan failed (${msg}). Proceeding with install.
40377
40750
  `
40378
40751
  )
@@ -40383,8 +40756,8 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40383
40756
  }
40384
40757
  if (result.action === "pass") {
40385
40758
  process.stderr.write(
40386
- import_chalk4.default.green(
40387
- ` ${import_chalk4.default.bold("\u2713")} ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
40759
+ import_chalk5.default.green(
40760
+ ` ${import_chalk5.default.bold("\u2713")} ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
40388
40761
  `
40389
40762
  )
40390
40763
  );
@@ -40398,7 +40771,7 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40398
40771
  printTrialBanner(result);
40399
40772
  if (result.action === "warn") {
40400
40773
  process.stderr.write(
40401
- import_chalk4.default.yellow(" Warnings detected. Proceeding with install.\n\n")
40774
+ import_chalk5.default.yellow(" Warnings detected. Proceeding with install.\n\n")
40402
40775
  );
40403
40776
  const code = await runNpm(parsed.rawArgs);
40404
40777
  process.exit(code);
@@ -40406,8 +40779,8 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40406
40779
  if (result.action === "block") {
40407
40780
  if (parsed.dgForce) {
40408
40781
  process.stderr.write(
40409
- import_chalk4.default.yellow(
40410
- import_chalk4.default.bold(
40782
+ import_chalk5.default.yellow(
40783
+ import_chalk5.default.bold(
40411
40784
  " --dg-force: Bypassing block. Install at your own risk.\n\n"
40412
40785
  )
40413
40786
  )
@@ -40416,10 +40789,10 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40416
40789
  process.exit(code);
40417
40790
  }
40418
40791
  process.stderr.write(
40419
- import_chalk4.default.red(import_chalk4.default.bold(" BLOCKED: ")) + import_chalk4.default.red("High-risk packages detected. Install aborted.\n")
40792
+ import_chalk5.default.red(import_chalk5.default.bold(" BLOCKED: ")) + import_chalk5.default.red("High-risk packages detected. Install aborted.\n")
40420
40793
  );
40421
40794
  process.stderr.write(
40422
- import_chalk4.default.dim(" Use --dg-force to bypass this check.\n\n")
40795
+ import_chalk5.default.dim(" Use --dg-force to bypass this check.\n\n")
40423
40796
  );
40424
40797
  process.exit(2);
40425
40798
  }
@@ -40436,13 +40809,13 @@ async function runStaticPip(pipArgs, config) {
40436
40809
  }
40437
40810
  if (specs.length === 0) {
40438
40811
  process.stderr.write(
40439
- import_chalk4.default.dim(" Dependency Guardian: no packages to scan, passing through to pip.\n")
40812
+ import_chalk5.default.dim(" Dependency Guardian: no packages to scan, passing through to pip.\n")
40440
40813
  );
40441
40814
  const code = await runPip(parsed.rawArgs);
40442
40815
  process.exit(code);
40443
40816
  }
40444
40817
  process.stderr.write(
40445
- import_chalk4.default.dim(
40818
+ import_chalk5.default.dim(
40446
40819
  ` Resolving ${specs.length} package${specs.length !== 1 ? "s" : ""} from PyPI...
40447
40820
  `
40448
40821
  )
@@ -40450,19 +40823,19 @@ async function runStaticPip(pipArgs, config) {
40450
40823
  const { resolved, failed } = await resolvePackages2(specs);
40451
40824
  if (failed.length > 0) {
40452
40825
  process.stderr.write(
40453
- import_chalk4.default.yellow(` Warning: Could not resolve versions for: ${failed.join(", ")}
40826
+ import_chalk5.default.yellow(` Warning: Could not resolve versions for: ${failed.join(", ")}
40454
40827
  `)
40455
40828
  );
40456
40829
  }
40457
40830
  if (resolved.length === 0) {
40458
40831
  process.stderr.write(
40459
- import_chalk4.default.dim(" No packages to scan. Passing through to pip.\n")
40832
+ import_chalk5.default.dim(" No packages to scan. Passing through to pip.\n")
40460
40833
  );
40461
40834
  const code = await runPip(parsed.rawArgs);
40462
40835
  process.exit(code);
40463
40836
  }
40464
40837
  process.stderr.write(
40465
- import_chalk4.default.dim(
40838
+ import_chalk5.default.dim(
40466
40839
  ` Scanning ${resolved.length} Python package${resolved.length !== 1 ? "s" : ""}...
40467
40840
  `
40468
40841
  )
@@ -40474,7 +40847,7 @@ async function runStaticPip(pipArgs, config) {
40474
40847
  if (handleTrialExhausted2(error, config.json)) return;
40475
40848
  const msg = error instanceof Error ? error.message : String(error);
40476
40849
  process.stderr.write(
40477
- import_chalk4.default.yellow(` Warning: Scan failed (${msg}). Proceeding with install.
40850
+ import_chalk5.default.yellow(` Warning: Scan failed (${msg}). Proceeding with install.
40478
40851
  `)
40479
40852
  );
40480
40853
  const code = await runPip(parsed.rawArgs);
@@ -40483,8 +40856,8 @@ async function runStaticPip(pipArgs, config) {
40483
40856
  }
40484
40857
  if (result.action === "pass") {
40485
40858
  process.stderr.write(
40486
- import_chalk4.default.green(
40487
- ` ${import_chalk4.default.bold("\u2713")} ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
40859
+ import_chalk5.default.green(
40860
+ ` ${import_chalk5.default.bold("\u2713")} ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
40488
40861
  `
40489
40862
  )
40490
40863
  );
@@ -40498,7 +40871,7 @@ async function runStaticPip(pipArgs, config) {
40498
40871
  printTrialBanner(result);
40499
40872
  if (result.action === "warn") {
40500
40873
  process.stderr.write(
40501
- import_chalk4.default.yellow(" Warnings detected. Proceeding with install.\n\n")
40874
+ import_chalk5.default.yellow(" Warnings detected. Proceeding with install.\n\n")
40502
40875
  );
40503
40876
  const code = await runPip(parsed.rawArgs);
40504
40877
  process.exit(code);
@@ -40506,16 +40879,16 @@ async function runStaticPip(pipArgs, config) {
40506
40879
  if (result.action === "block") {
40507
40880
  if (parsed.dgForce) {
40508
40881
  process.stderr.write(
40509
- import_chalk4.default.yellow(import_chalk4.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
40882
+ import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
40510
40883
  );
40511
40884
  const code = await runPip(parsed.rawArgs);
40512
40885
  process.exit(code);
40513
40886
  }
40514
40887
  process.stderr.write(
40515
- import_chalk4.default.red(import_chalk4.default.bold(" BLOCKED: ")) + import_chalk4.default.red("High-risk packages detected. Install aborted.\n")
40888
+ import_chalk5.default.red(import_chalk5.default.bold(" BLOCKED: ")) + import_chalk5.default.red("High-risk packages detected. Install aborted.\n")
40516
40889
  );
40517
40890
  process.stderr.write(
40518
- import_chalk4.default.dim(" Use --dg-force to bypass this check.\n\n")
40891
+ import_chalk5.default.dim(" Use --dg-force to bypass this check.\n\n")
40519
40892
  );
40520
40893
  process.exit(2);
40521
40894
  }
@@ -40531,17 +40904,17 @@ async function runStaticLogin() {
40531
40904
  const existing = getStoredApiKey2();
40532
40905
  if (existing) {
40533
40906
  process.stderr.write(
40534
- import_chalk4.default.yellow(" Already authenticated.\n") + import_chalk4.default.dim(" Run `dg logout` first to re-authenticate.\n")
40907
+ import_chalk5.default.yellow(" Already authenticated.\n") + import_chalk5.default.dim(" Run `dg logout` first to re-authenticate.\n")
40535
40908
  );
40536
40909
  return;
40537
40910
  }
40538
- process.stderr.write(import_chalk4.default.dim(" Creating login session...\n"));
40911
+ process.stderr.write(import_chalk5.default.dim(" Creating login session...\n"));
40539
40912
  let session;
40540
40913
  try {
40541
40914
  session = await createAuthSession2();
40542
40915
  } catch (err) {
40543
40916
  process.stderr.write(
40544
- import_chalk4.default.red(` Error: ${err instanceof Error ? err.message : String(err)}
40917
+ import_chalk5.default.red(` Error: ${err instanceof Error ? err.message : String(err)}
40545
40918
  `)
40546
40919
  );
40547
40920
  process.exit(1);
@@ -40549,10 +40922,10 @@ async function runStaticLogin() {
40549
40922
  process.stderr.write(`
40550
40923
  Authenticate your account at:
40551
40924
  `);
40552
- process.stderr.write(` ${import_chalk4.default.cyan(session.verifyUrl)}
40925
+ process.stderr.write(` ${import_chalk5.default.cyan(session.verifyUrl)}
40553
40926
 
40554
40927
  `);
40555
- process.stderr.write(import_chalk4.default.dim(" Press ENTER to open in the browser...\n"));
40928
+ process.stderr.write(import_chalk5.default.dim(" Press ENTER to open in the browser...\n"));
40556
40929
  await new Promise((resolve) => {
40557
40930
  const onData = () => {
40558
40931
  process.stdin.removeListener("data", onData);
@@ -40567,7 +40940,7 @@ async function runStaticLogin() {
40567
40940
  openBrowser2(session.verifyUrl);
40568
40941
  } catch {
40569
40942
  }
40570
- process.stderr.write(import_chalk4.default.dim(" Waiting for authorization...\n"));
40943
+ process.stderr.write(import_chalk5.default.dim(" Waiting for authorization...\n"));
40571
40944
  const POLL_INTERVAL = 2e3;
40572
40945
  const MAX_ATTEMPTS = 150;
40573
40946
  for (let i = 0; i < MAX_ATTEMPTS; i++) {
@@ -40577,15 +40950,15 @@ async function runStaticLogin() {
40577
40950
  if (result.status === "complete" && result.apiKey) {
40578
40951
  saveCredentials2(result.apiKey);
40579
40952
  process.stderr.write(
40580
- import_chalk4.default.green(`
40953
+ import_chalk5.default.green(`
40581
40954
  Logged in as ${result.email ?? "unknown"}
40582
- `) + import_chalk4.default.dim(" Credentials saved.\n\n")
40955
+ `) + import_chalk5.default.dim(" Credentials saved.\n\n")
40583
40956
  );
40584
40957
  return;
40585
40958
  }
40586
40959
  if (result.status === "expired") {
40587
40960
  process.stderr.write(
40588
- import_chalk4.default.yellow("\n Session expired. Run `dg login` to try again.\n")
40961
+ import_chalk5.default.yellow("\n Session expired. Run `dg login` to try again.\n")
40589
40962
  );
40590
40963
  process.exit(1);
40591
40964
  }
@@ -40593,15 +40966,15 @@ async function runStaticLogin() {
40593
40966
  }
40594
40967
  }
40595
40968
  process.stderr.write(
40596
- import_chalk4.default.yellow("\n Timed out waiting for authorization.\n")
40969
+ import_chalk5.default.yellow("\n Timed out waiting for authorization.\n")
40597
40970
  );
40598
40971
  process.exit(1);
40599
40972
  }
40600
- var import_chalk4;
40973
+ var import_chalk5;
40601
40974
  var init_static_output = __esm({
40602
40975
  "src/static-output.ts"() {
40603
40976
  "use strict";
40604
- import_chalk4 = __toESM(require_source());
40977
+ import_chalk5 = __toESM(require_source());
40605
40978
  init_api();
40606
40979
  init_lockfile();
40607
40980
  init_npm_wrapper();
@@ -40616,14 +40989,14 @@ __export(hook_exports, {
40616
40989
  });
40617
40990
  import { execFileSync as execFileSync3 } from "node:child_process";
40618
40991
  import {
40619
- existsSync as existsSync8,
40992
+ existsSync as existsSync9,
40620
40993
  readFileSync as readFileSync9,
40621
40994
  writeFileSync as writeFileSync3,
40622
40995
  mkdirSync,
40623
40996
  chmodSync as chmodSync2,
40624
40997
  unlinkSync as unlinkSync2
40625
40998
  } from "node:fs";
40626
- import { join as join7 } from "node:path";
40999
+ import { join as join8 } from "node:path";
40627
41000
  function findGitDir() {
40628
41001
  try {
40629
41002
  return execFileSync3("git", ["rev-parse", "--git-dir"], {
@@ -40636,10 +41009,10 @@ function findGitDir() {
40636
41009
  }
40637
41010
  function installHook() {
40638
41011
  const gitDir = findGitDir();
40639
- const hooksDir = join7(gitDir, "hooks");
40640
- const hookPath = join7(hooksDir, "pre-commit");
41012
+ const hooksDir = join8(gitDir, "hooks");
41013
+ const hookPath = join8(hooksDir, "pre-commit");
40641
41014
  mkdirSync(hooksDir, { recursive: true });
40642
- if (existsSync8(hookPath)) {
41015
+ if (existsSync9(hookPath)) {
40643
41016
  const existing = readFileSync9(hookPath, "utf-8");
40644
41017
  if (existing.includes(HOOK_MARKER)) {
40645
41018
  process.stderr.write(" Hook already installed.\n");
@@ -40660,8 +41033,8 @@ function installHook() {
40660
41033
  }
40661
41034
  function uninstallHook() {
40662
41035
  const gitDir = findGitDir();
40663
- const hookPath = join7(gitDir, "hooks", "pre-commit");
40664
- if (!existsSync8(hookPath)) {
41036
+ const hookPath = join8(gitDir, "hooks", "pre-commit");
41037
+ if (!existsSync9(hookPath)) {
40665
41038
  process.stderr.write(" No hook to remove.\n");
40666
41039
  return;
40667
41040
  }
@@ -40784,7 +41157,7 @@ ${HOOK_SCRIPT.split("\n").slice(1).join("\n")}${MARKER_END}
40784
41157
  });
40785
41158
 
40786
41159
  // src/ui/hooks/useNpmWrapper.ts
40787
- function reducer2(_state, action) {
41160
+ function reducer3(_state, action) {
40788
41161
  switch (action.type) {
40789
41162
  case "PASSTHROUGH":
40790
41163
  return { phase: "passthrough" };
@@ -40808,12 +41181,12 @@ function reducer2(_state, action) {
40808
41181
  return { phase: "trial_exhausted" };
40809
41182
  }
40810
41183
  }
40811
- function useNpmWrapper(npmArgs, config) {
40812
- const [state, dispatch] = (0, import_react25.useReducer)(reducer2, { phase: "resolving", count: 0 });
40813
- const started = (0, import_react25.useRef)(false);
40814
- const parsedRef = (0, import_react25.useRef)(parseNpmArgs(npmArgs));
40815
- const pendingInstall = (0, import_react25.useRef)(null);
40816
- const rejectRef = (0, import_react25.useRef)(null);
41184
+ function useNpmWrapper(npmArgs, config, exit) {
41185
+ const [state, dispatch] = (0, import_react26.useReducer)(reducer3, { phase: "resolving", count: 0 });
41186
+ const started = (0, import_react26.useRef)(false);
41187
+ const parsedRef = (0, import_react26.useRef)(parseNpmArgs(npmArgs));
41188
+ const pendingInstall = (0, import_react26.useRef)(null);
41189
+ const rejectRef = (0, import_react26.useRef)(null);
40817
41190
  const confirmInstall = () => {
40818
41191
  if (pendingInstall.current) {
40819
41192
  pendingInstall.current();
@@ -40828,7 +41201,7 @@ function useNpmWrapper(npmArgs, config) {
40828
41201
  rejectRef.current = null;
40829
41202
  }
40830
41203
  };
40831
- (0, import_react25.useEffect)(() => {
41204
+ (0, import_react26.useEffect)(() => {
40832
41205
  if (started.current) return;
40833
41206
  started.current = true;
40834
41207
  const parsed = parsedRef.current;
@@ -40863,18 +41236,24 @@ function useNpmWrapper(npmArgs, config) {
40863
41236
  dispatch({ type: "SCANNING", count: resolved.length });
40864
41237
  const result = await callAnalyzeAPI(resolved, config);
40865
41238
  if (result.action === "pass") {
40866
- dispatch({ type: "PASS", count: resolved.length });
40867
- dispatch({ type: "INSTALLING" });
41239
+ if (exit) exit();
41240
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
41241
+ process.stderr.write(
41242
+ chalk8.green(` \u2713 ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
41243
+ `)
41244
+ );
41245
+ process.stderr.write("\n");
40868
41246
  const code = await runNpm(parsed.rawArgs);
40869
- dispatch({ type: "DONE", exitCode: code });
41247
+ process.exit(code);
40870
41248
  return;
40871
41249
  }
40872
41250
  if (result.action === "warn") {
40873
- dispatch({ type: "WARN", result });
41251
+ if (exit) exit();
40874
41252
  process.stdout.write(renderResultStatic(result, config) + "\n");
40875
- dispatch({ type: "INSTALLING" });
41253
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
41254
+ process.stderr.write(chalk8.yellow(" Warnings detected. Proceeding with install.\n\n"));
40876
41255
  const code = await runNpm(parsed.rawArgs);
40877
- dispatch({ type: "DONE", exitCode: code });
41256
+ process.exit(code);
40878
41257
  return;
40879
41258
  }
40880
41259
  if (result.action === "block") {
@@ -40915,11 +41294,11 @@ function useNpmWrapper(npmArgs, config) {
40915
41294
  }, [npmArgs, config]);
40916
41295
  return { state, confirmInstall, rejectInstall };
40917
41296
  }
40918
- var import_react25;
41297
+ var import_react26;
40919
41298
  var init_useNpmWrapper = __esm({
40920
41299
  "src/ui/hooks/useNpmWrapper.ts"() {
40921
41300
  "use strict";
40922
- import_react25 = __toESM(require_react());
41301
+ import_react26 = __toESM(require_react());
40923
41302
  init_npm_wrapper();
40924
41303
  init_api();
40925
41304
  init_static_output();
@@ -40928,7 +41307,7 @@ var init_useNpmWrapper = __esm({
40928
41307
 
40929
41308
  // src/ui/components/ScoreHeader.tsx
40930
41309
  function scoreColor(score, action) {
40931
- const colorFn = action === "block" ? import_chalk5.default.red.bold : action === "warn" ? import_chalk5.default.yellow.bold : import_chalk5.default.green.bold;
41310
+ const colorFn = action === "block" ? import_chalk6.default.red.bold : action === "warn" ? import_chalk6.default.yellow.bold : import_chalk6.default.green.bold;
40932
41311
  return colorFn(String(score));
40933
41312
  }
40934
41313
  function severityBar(counts) {
@@ -40942,7 +41321,7 @@ function severityBar(counts) {
40942
41321
  if (count === 0) continue;
40943
41322
  const width = Math.max(2, Math.round(count / total * BAR_WIDTH));
40944
41323
  const bar = "\u2501".repeat(width);
40945
- const colorFn = SEV_COLORS[lv] ?? import_chalk5.default.dim;
41324
+ const colorFn = SEV_COLORS[lv] ?? import_chalk6.default.dim;
40946
41325
  parts.push(`${colorFn(bar)} ${count} ${SEV_LABELS[lv] ?? ""}`);
40947
41326
  }
40948
41327
  return parts.join(" ");
@@ -40976,10 +41355,10 @@ function fillCircle(grid, cx, cy, r, type) {
40976
41355
  }
40977
41356
  function renderLogo(action) {
40978
41357
  const colors = {
40979
- 1: import_chalk5.default.dim,
40980
- 2: import_chalk5.default.white,
40981
- 3: (s) => import_chalk5.default.bold.white(s),
40982
- 4: action === "block" ? import_chalk5.default.red : action === "warn" ? import_chalk5.default.yellow : import_chalk5.default.green
41358
+ 1: import_chalk6.default.dim,
41359
+ 2: import_chalk6.default.white,
41360
+ 3: (s) => import_chalk6.default.bold.white(s),
41361
+ 4: action === "block" ? import_chalk6.default.red : action === "warn" ? import_chalk6.default.yellow : import_chalk6.default.green
40983
41362
  };
40984
41363
  const result = [];
40985
41364
  const { chars, types, cols } = LOGO_DATA;
@@ -40988,24 +41367,24 @@ function renderLogo(action) {
40988
41367
  for (let j = 0; j < cols; j++) {
40989
41368
  const ch = chars[i + j];
40990
41369
  const t = types[i + j];
40991
- row += t > 0 ? (colors[t] ?? import_chalk5.default.dim)(ch) : ch;
41370
+ row += t > 0 ? (colors[t] ?? import_chalk6.default.dim)(ch) : ch;
40992
41371
  }
40993
41372
  result.push(row);
40994
41373
  }
40995
41374
  return result;
40996
41375
  }
40997
- var import_chalk5, import_jsx_runtime3, SEV_COLORS, SEV_LABELS, LOGO_DATA, ScoreHeader;
41376
+ var import_chalk6, import_jsx_runtime4, SEV_COLORS, SEV_LABELS, LOGO_DATA, ScoreHeader;
40998
41377
  var init_ScoreHeader = __esm({
40999
41378
  async "src/ui/components/ScoreHeader.tsx"() {
41000
41379
  "use strict";
41001
41380
  await init_build2();
41002
- import_chalk5 = __toESM(require_source());
41003
- import_jsx_runtime3 = __toESM(require_jsx_runtime());
41381
+ import_chalk6 = __toESM(require_source());
41382
+ import_jsx_runtime4 = __toESM(require_jsx_runtime());
41004
41383
  SEV_COLORS = {
41005
- 5: (s) => import_chalk5.default.red(s),
41006
- 4: (s) => import_chalk5.default.magenta(s),
41007
- 3: (s) => import_chalk5.default.yellow(s),
41008
- 2: (s) => import_chalk5.default.dim(s)
41384
+ 5: (s) => import_chalk6.default.red(s),
41385
+ 4: (s) => import_chalk6.default.magenta(s),
41386
+ 3: (s) => import_chalk6.default.yellow(s),
41387
+ 2: (s) => import_chalk6.default.dim(s)
41009
41388
  };
41010
41389
  SEV_LABELS = {
41011
41390
  5: "crit",
@@ -41063,7 +41442,7 @@ var init_ScoreHeader = __esm({
41063
41442
  }) => {
41064
41443
  const logo = renderLogo(action);
41065
41444
  const showLogo = (process.stdout.columns ?? 80) >= 60;
41066
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
41445
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
41067
41446
  Box_default,
41068
41447
  {
41069
41448
  flexDirection: "column",
@@ -41072,37 +41451,37 @@ var init_ScoreHeader = __esm({
41072
41451
  paddingLeft: 1,
41073
41452
  paddingRight: 1,
41074
41453
  width: "100%",
41075
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "row", children: [
41076
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, children: [
41077
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { bold: true, children: [
41078
- import_chalk5.default.cyan("\u25C6"),
41454
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Box_default, { flexDirection: "row", children: [
41455
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, children: [
41456
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { bold: true, children: [
41457
+ import_chalk6.default.cyan("\u25C6"),
41079
41458
  " Dependency Guardian"
41080
41459
  ] }),
41081
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: " " }),
41082
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
41083
- import_chalk5.default.dim("Score"),
41460
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: " " }),
41461
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { children: [
41462
+ import_chalk6.default.dim("Score"),
41084
41463
  " ",
41085
41464
  scoreColor(score, action)
41086
41465
  ] }),
41087
- total !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
41088
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: " " }),
41089
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
41090
- import_chalk5.default.dim(`${total} package${total !== 1 ? "s" : ""} scanned`),
41091
- flagged !== void 0 && flagged > 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
41466
+ total !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
41467
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: " " }),
41468
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { children: [
41469
+ import_chalk6.default.dim(`${total} package${total !== 1 ? "s" : ""} scanned`),
41470
+ flagged !== void 0 && flagged > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
41092
41471
  " ",
41093
- import_chalk5.default.yellow(`${flagged} flagged`),
41472
+ import_chalk6.default.yellow(`${flagged} flagged`),
41094
41473
  " ",
41095
- import_chalk5.default.green(`${clean ?? 0} clean`)
41096
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
41474
+ import_chalk6.default.green(`${clean ?? 0} clean`)
41475
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
41097
41476
  " ",
41098
- import_chalk5.default.green("all clean")
41477
+ import_chalk6.default.green("all clean")
41099
41478
  ] })
41100
41479
  ] }),
41101
- severityCounts && Object.values(severityCounts).some((v) => v > 0) && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: severityBar(severityCounts) }),
41102
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { dimColor: true, children: `\x1B]8;;https://westbayberry.com\x07westbayberry.com\x1B]8;;\x07` })
41480
+ severityCounts && Object.values(severityCounts).some((v) => v > 0) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: severityBar(severityCounts) }),
41481
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { dimColor: true, children: `\x1B]8;;https://westbayberry.com\x07westbayberry.com\x1B]8;;\x07` })
41103
41482
  ] })
41104
41483
  ] }),
41105
- showLogo && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: logo.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: line }, i)) })
41484
+ showLogo && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: logo.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Text, { children: line }, i)) })
41106
41485
  ] })
41107
41486
  }
41108
41487
  );
@@ -41111,13 +41490,13 @@ var init_ScoreHeader = __esm({
41111
41490
  });
41112
41491
 
41113
41492
  // src/ui/components/DurationLine.tsx
41114
- var import_jsx_runtime4, DurationLine;
41493
+ var import_jsx_runtime5, DurationLine;
41115
41494
  var init_DurationLine = __esm({
41116
41495
  async "src/ui/components/DurationLine.tsx"() {
41117
41496
  "use strict";
41118
41497
  await init_build2();
41119
- import_jsx_runtime4 = __toESM(require_jsx_runtime());
41120
- DurationLine = ({ ms }) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(Text, { dimColor: true, children: [
41498
+ import_jsx_runtime5 = __toESM(require_jsx_runtime());
41499
+ DurationLine = ({ ms }) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, children: [
41121
41500
  "Completed in ",
41122
41501
  (ms / 1e3).toFixed(1),
41123
41502
  "s"
@@ -41137,16 +41516,16 @@ function groupPackages2(packages) {
41137
41516
  return [...map.values()].map((pkgs) => ({ packages: pkgs, key: pkgs[0].name })).sort((a, b) => b.packages[0].score - a.packages[0].score);
41138
41517
  }
41139
41518
  function severityColor(sev) {
41140
- if (sev >= 5) return (s) => import_chalk6.default.bold.red(s);
41141
- if (sev >= 4) return import_chalk6.default.magenta;
41142
- if (sev >= 3) return import_chalk6.default.yellow;
41143
- if (sev >= 2) return import_chalk6.default.dim;
41144
- return import_chalk6.default.dim;
41519
+ if (sev >= 5) return (s) => import_chalk7.default.bold.red(s);
41520
+ if (sev >= 4) return import_chalk7.default.magenta;
41521
+ if (sev >= 3) return import_chalk7.default.yellow;
41522
+ if (sev >= 2) return import_chalk7.default.dim;
41523
+ return import_chalk7.default.dim;
41145
41524
  }
41146
41525
  function actionBadge2(score) {
41147
- if (score >= 70) return { label: "BLOCK", color: import_chalk6.default.red };
41148
- if (score >= 60) return { label: "WARN", color: import_chalk6.default.yellow };
41149
- return { label: "PASS", color: import_chalk6.default.green };
41526
+ if (score >= 70) return { label: "BLOCK", color: import_chalk7.default.red };
41527
+ if (score >= 60) return { label: "WARN", color: import_chalk7.default.yellow };
41528
+ return { label: "PASS", color: import_chalk7.default.green };
41150
41529
  }
41151
41530
  function truncate2(s, max) {
41152
41531
  return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
@@ -41154,15 +41533,15 @@ function truncate2(s, max) {
41154
41533
  function pad2(s, len) {
41155
41534
  return s + " ".repeat(Math.max(0, len - s.length));
41156
41535
  }
41157
- var import_chalk6, import_jsx_runtime5, SEVERITY_LABELS, EVIDENCE_LIMIT, ResultsView;
41536
+ var import_chalk7, import_jsx_runtime6, SEVERITY_LABELS, EVIDENCE_LIMIT, ResultsView;
41158
41537
  var init_ResultsView = __esm({
41159
41538
  async "src/ui/components/ResultsView.tsx"() {
41160
41539
  "use strict";
41161
41540
  await init_build2();
41162
- import_chalk6 = __toESM(require_source());
41541
+ import_chalk7 = __toESM(require_source());
41163
41542
  await init_ScoreHeader();
41164
41543
  await init_DurationLine();
41165
- import_jsx_runtime5 = __toESM(require_jsx_runtime());
41544
+ import_jsx_runtime6 = __toESM(require_jsx_runtime());
41166
41545
  SEVERITY_LABELS = {
41167
41546
  5: "CRITICAL",
41168
41547
  4: "HIGH",
@@ -41180,70 +41559,70 @@ var init_ResultsView = __esm({
41180
41559
  const clean = result.packages.filter((p) => p.score === 0);
41181
41560
  const total = result.packages.length;
41182
41561
  const groups = groupPackages2(flagged);
41183
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
41184
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {}),
41185
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ScoreHeader, { score: result.score, action: result.action }),
41186
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {}),
41187
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41188
- import_chalk6.default.dim(`${total} package${total !== 1 ? "s" : ""} scanned`),
41189
- flagged.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
41562
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
41563
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {}),
41564
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ScoreHeader, { score: result.score, action: result.action }),
41565
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {}),
41566
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41567
+ import_chalk7.default.dim(`${total} package${total !== 1 ? "s" : ""} scanned`),
41568
+ flagged.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
41190
41569
  " ",
41191
- import_chalk6.default.yellow(`${flagged.length} flagged`),
41570
+ import_chalk7.default.yellow(`${flagged.length} flagged`),
41192
41571
  " ",
41193
- import_chalk6.default.green(`${clean.length} clean`)
41194
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
41572
+ import_chalk7.default.green(`${clean.length} clean`)
41573
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
41195
41574
  " ",
41196
- import_chalk6.default.green("all clean")
41575
+ import_chalk7.default.green("all clean")
41197
41576
  ] })
41198
41577
  ] }),
41199
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {}),
41200
- flagged.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
41201
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, children: "Flagged Packages" }),
41202
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { dimColor: true, children: "\u2500".repeat(60) }),
41578
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {}),
41579
+ flagged.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
41580
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { bold: true, children: "Flagged Packages" }),
41581
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { dimColor: true, children: "\u2500".repeat(60) }),
41203
41582
  groups.map((group) => {
41204
41583
  const rep = group.packages[0];
41205
41584
  const { label, color } = actionBadge2(rep.score);
41206
41585
  const names = group.packages.length === 1 ? rep.name : group.packages.length <= 3 ? group.packages.map((p) => p.name).join(", ") : `${group.packages[0].name} + ${group.packages.length - 1} similar`;
41207
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41586
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41208
41587
  " ",
41209
41588
  color(pad2(label, 7)),
41210
- import_chalk6.default.bold(pad2(truncate2(names, 50), 52)),
41211
- import_chalk6.default.dim(`score ${rep.score}`)
41589
+ import_chalk7.default.bold(pad2(truncate2(names, 50), 52)),
41590
+ import_chalk7.default.dim(`score ${rep.score}`)
41212
41591
  ] }, group.key);
41213
41592
  }),
41214
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {})
41593
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {})
41215
41594
  ] }),
41216
- clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41217
- import_chalk6.default.green("\u2713"),
41595
+ clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41596
+ import_chalk7.default.green("\u2713"),
41218
41597
  " ",
41219
- import_chalk6.default.green.bold(String(clean.length)),
41598
+ import_chalk7.default.green.bold(String(clean.length)),
41220
41599
  " ",
41221
- import_chalk6.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
41600
+ import_chalk7.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
41222
41601
  ] }),
41223
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {}),
41602
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {}),
41224
41603
  groups.filter((g) => g.packages[0].score > 0).map((group) => {
41225
41604
  const rep = group.packages[0];
41226
41605
  const names = group.packages.length === 1 ? `${rep.name}@${rep.version}` : group.packages.length <= 3 ? group.packages.map((p) => `${p.name}@${p.version}`).join(", ") : `${rep.name}@${rep.version} + ${group.packages.length - 1} identical packages`;
41227
41606
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
41228
41607
  const safeVersion = result.safeVersions[rep.name];
41229
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
41230
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41231
- import_chalk6.default.dim("\u2500\u2500"),
41608
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
41609
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41610
+ import_chalk7.default.dim("\u2500\u2500"),
41232
41611
  " ",
41233
- import_chalk6.default.bold(`${names} (score: ${rep.score})`)
41612
+ import_chalk7.default.bold(`${names} (score: ${rep.score})`)
41234
41613
  ] }),
41235
- group.packages.length > 3 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { dimColor: true, children: [
41614
+ group.packages.length > 3 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { dimColor: true, children: [
41236
41615
  " Affects: ",
41237
41616
  group.packages.map((p) => p.name).join(", ")
41238
41617
  ] }),
41239
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: " " }),
41618
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: " " }),
41240
41619
  visibleFindings.map((finding, idx) => {
41241
41620
  const sevLabel = SEVERITY_LABELS[finding.severity] ?? "INFO";
41242
41621
  const colorFn = severityColor(finding.severity);
41243
41622
  const evidenceSlice = finding.evidence.slice(0, EVIDENCE_LIMIT);
41244
41623
  const overflow = finding.evidence.length - EVIDENCE_LIMIT;
41245
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
41246
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41624
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
41625
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41247
41626
  " ",
41248
41627
  colorFn(pad2(sevLabel, 10)),
41249
41628
  finding.id,
@@ -41252,40 +41631,40 @@ var init_ResultsView = __esm({
41252
41631
  " ",
41253
41632
  finding.title
41254
41633
  ] }),
41255
- evidenceSlice.map((ev, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41634
+ evidenceSlice.map((ev, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41256
41635
  " ",
41257
- import_chalk6.default.dim(truncate2(ev, 76))
41636
+ import_chalk7.default.dim(truncate2(ev, 76))
41258
41637
  ] }, i)),
41259
- overflow > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41638
+ overflow > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41260
41639
  " ",
41261
- import_chalk6.default.dim(`... and ${overflow} more`)
41640
+ import_chalk7.default.dim(`... and ${overflow} more`)
41262
41641
  ] }),
41263
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: " " })
41642
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: " " })
41264
41643
  ] }, `${finding.id}-${idx}`);
41265
41644
  }),
41266
- safeVersion && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
41645
+ safeVersion && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41267
41646
  " ",
41268
- import_chalk6.default.green(`Safe version: ${rep.name}@${safeVersion}`)
41647
+ import_chalk7.default.green(`Safe version: ${rep.name}@${safeVersion}`)
41269
41648
  ] }),
41270
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {})
41649
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {})
41271
41650
  ] }, group.key);
41272
41651
  }),
41273
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(DurationLine, { ms: durationMs }),
41274
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Newline, {})
41652
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DurationLine, { ms: durationMs }),
41653
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Newline, {})
41275
41654
  ] });
41276
41655
  };
41277
41656
  }
41278
41657
  });
41279
41658
 
41280
41659
  // src/ui/components/ConfirmPrompt.tsx
41281
- var import_chalk7, import_jsx_runtime6, ConfirmPrompt;
41660
+ var import_chalk8, import_jsx_runtime7, ConfirmPrompt;
41282
41661
  var init_ConfirmPrompt = __esm({
41283
41662
  async "src/ui/components/ConfirmPrompt.tsx"() {
41284
41663
  "use strict";
41285
41664
  await init_build2();
41286
41665
  await init_build2();
41287
- import_chalk7 = __toESM(require_source());
41288
- import_jsx_runtime6 = __toESM(require_jsx_runtime());
41666
+ import_chalk8 = __toESM(require_source());
41667
+ import_jsx_runtime7 = __toESM(require_jsx_runtime());
41289
41668
  ConfirmPrompt = ({
41290
41669
  message,
41291
41670
  onConfirm,
@@ -41298,17 +41677,17 @@ var init_ConfirmPrompt = __esm({
41298
41677
  onReject();
41299
41678
  }
41300
41679
  });
41301
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", children: [
41302
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41303
- import_chalk7.default.red.bold("\u26A0"),
41680
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", children: [
41681
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
41682
+ import_chalk8.default.red.bold("\u26A0"),
41304
41683
  " ",
41305
- import_chalk7.default.bold(message)
41684
+ import_chalk8.default.bold(message)
41306
41685
  ] }),
41307
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { children: [
41686
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
41308
41687
  "Install anyway? [",
41309
- import_chalk7.default.bold.green("y"),
41688
+ import_chalk8.default.bold.green("y"),
41310
41689
  "es / ",
41311
- import_chalk7.default.bold.red("N"),
41690
+ import_chalk8.default.bold.red("N"),
41312
41691
  "o]"
41313
41692
  ] })
41314
41693
  ] });
@@ -41331,17 +41710,17 @@ function getHint(error) {
41331
41710
  return null;
41332
41711
  }
41333
41712
  }
41334
- var import_chalk8, import_jsx_runtime7, ErrorView;
41713
+ var import_chalk9, import_jsx_runtime8, ErrorView;
41335
41714
  var init_ErrorView = __esm({
41336
41715
  async "src/ui/components/ErrorView.tsx"() {
41337
41716
  "use strict";
41338
41717
  await init_build2();
41339
- import_chalk8 = __toESM(require_source());
41718
+ import_chalk9 = __toESM(require_source());
41340
41719
  init_sanitize();
41341
- import_jsx_runtime7 = __toESM(require_jsx_runtime());
41720
+ import_jsx_runtime8 = __toESM(require_jsx_runtime());
41342
41721
  ErrorView = ({ error }) => {
41343
41722
  const hint = getHint(error);
41344
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
41723
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
41345
41724
  Box_default,
41346
41725
  {
41347
41726
  flexDirection: "column",
@@ -41350,10 +41729,10 @@ var init_ErrorView = __esm({
41350
41729
  paddingLeft: 1,
41351
41730
  paddingRight: 1,
41352
41731
  children: [
41353
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: import_chalk8.default.red.bold("\u2718 Error") }),
41354
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { children: sanitize(error.message) }),
41355
- hint && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Text, { children: [
41356
- import_chalk8.default.yellow("\u2192"),
41732
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: import_chalk9.default.red.bold("\u2718 Error") }),
41733
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { children: sanitize(error.message) }),
41734
+ hint && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { children: [
41735
+ import_chalk9.default.yellow("\u2192"),
41357
41736
  " ",
41358
41737
  hint
41359
41738
  ] })
@@ -41369,25 +41748,25 @@ var NpmWrapperApp_exports = {};
41369
41748
  __export(NpmWrapperApp_exports, {
41370
41749
  NpmWrapperApp: () => NpmWrapperApp
41371
41750
  });
41372
- var import_react26, import_jsx_runtime8, NpmWrapperApp;
41751
+ var import_react27, import_jsx_runtime9, NpmWrapperApp;
41373
41752
  var init_NpmWrapperApp = __esm({
41374
41753
  async "src/ui/NpmWrapperApp.tsx"() {
41375
41754
  "use strict";
41376
- import_react26 = __toESM(require_react());
41755
+ import_react27 = __toESM(require_react());
41377
41756
  await init_build2();
41378
41757
  init_useNpmWrapper();
41379
41758
  await init_Spinner();
41380
41759
  await init_ResultsView();
41381
41760
  await init_ConfirmPrompt();
41382
41761
  await init_ErrorView();
41383
- import_jsx_runtime8 = __toESM(require_jsx_runtime());
41762
+ import_jsx_runtime9 = __toESM(require_jsx_runtime());
41384
41763
  NpmWrapperApp = ({
41385
41764
  npmArgs,
41386
41765
  config
41387
41766
  }) => {
41388
- const { state, confirmInstall, rejectInstall } = useNpmWrapper(npmArgs, config);
41389
41767
  const { exit } = use_app_default();
41390
- (0, import_react26.useEffect)(() => {
41768
+ const { state, confirmInstall, rejectInstall } = useNpmWrapper(npmArgs, config, exit);
41769
+ (0, import_react27.useEffect)(() => {
41391
41770
  if (state.phase === "done") {
41392
41771
  process.exitCode = state.exitCode;
41393
41772
  const timer = setTimeout(() => exit(), 0);
@@ -41401,29 +41780,29 @@ var init_NpmWrapperApp = __esm({
41401
41780
  if (state.phase === "passthrough") {
41402
41781
  }
41403
41782
  }, [state, exit]);
41404
- const handleConfirm = (0, import_react26.useCallback)(() => {
41783
+ const handleConfirm = (0, import_react27.useCallback)(() => {
41405
41784
  confirmInstall();
41406
41785
  }, [confirmInstall]);
41407
- const handleReject = (0, import_react26.useCallback)(() => {
41786
+ const handleReject = (0, import_react27.useCallback)(() => {
41408
41787
  rejectInstall();
41409
41788
  }, [rejectInstall]);
41410
41789
  switch (state.phase) {
41411
41790
  case "resolving":
41412
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
41791
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41413
41792
  Spinner2,
41414
41793
  {
41415
41794
  label: `Resolving ${state.count} package${state.count !== 1 ? "s" : ""}...`
41416
41795
  }
41417
41796
  );
41418
41797
  case "scanning":
41419
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
41798
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41420
41799
  Spinner2,
41421
41800
  {
41422
41801
  label: `Scanning ${state.count} package${state.count !== 1 ? "s" : ""}...`
41423
41802
  }
41424
41803
  );
41425
41804
  case "pass":
41426
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "green", children: [
41805
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "green", children: [
41427
41806
  "\u2713",
41428
41807
  " ",
41429
41808
  state.count,
@@ -41434,8 +41813,8 @@ var init_NpmWrapperApp = __esm({
41434
41813
  "all clear"
41435
41814
  ] });
41436
41815
  case "warn":
41437
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", children: [
41438
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
41816
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41817
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41439
41818
  ResultsView,
41440
41819
  {
41441
41820
  result: state.result,
@@ -41443,12 +41822,12 @@ var init_NpmWrapperApp = __esm({
41443
41822
  durationMs: state.result.durationMs
41444
41823
  }
41445
41824
  ),
41446
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "yellow", children: "Warnings detected. Proceeding with install..." })
41825
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", children: "Warnings detected. Proceeding with install..." })
41447
41826
  ] });
41448
41827
  case "blocked":
41449
41828
  if (state.dgForce) {
41450
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", children: [
41451
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
41829
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41830
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41452
41831
  ResultsView,
41453
41832
  {
41454
41833
  result: state.result,
@@ -41456,11 +41835,11 @@ var init_NpmWrapperApp = __esm({
41456
41835
  durationMs: state.result.durationMs
41457
41836
  }
41458
41837
  ),
41459
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "yellow", bold: true, children: "--dg-force: Bypassing block. Install at your own risk." })
41838
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "--dg-force: Bypassing block. Install at your own risk." })
41460
41839
  ] });
41461
41840
  }
41462
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", children: [
41463
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
41841
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41842
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41464
41843
  ResultsView,
41465
41844
  {
41466
41845
  result: state.result,
@@ -41468,12 +41847,12 @@ var init_NpmWrapperApp = __esm({
41468
41847
  durationMs: state.result.durationMs
41469
41848
  }
41470
41849
  ),
41471
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "red", bold: true, children: [
41850
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "red", bold: true, children: [
41472
41851
  "BLOCKED:",
41473
41852
  " ",
41474
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "red", children: "High-risk packages detected." })
41853
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "red", children: "High-risk packages detected." })
41475
41854
  ] }),
41476
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
41855
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41477
41856
  ConfirmPrompt,
41478
41857
  {
41479
41858
  message: "Proceed with install anyway?",
@@ -41483,18 +41862,18 @@ var init_NpmWrapperApp = __esm({
41483
41862
  )
41484
41863
  ] });
41485
41864
  case "installing":
41486
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Spinner2, { label: "Installing..." });
41865
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner2, { label: "Installing..." });
41487
41866
  case "done":
41488
41867
  return null;
41489
41868
  case "error":
41490
41869
  if (state.proceed) {
41491
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { color: "yellow", children: [
41870
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "yellow", children: [
41492
41871
  "Warning: Scan failed (",
41493
41872
  state.message,
41494
41873
  "). Proceeding with install."
41495
41874
  ] });
41496
41875
  }
41497
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ErrorView, { error: new Error(state.message) });
41876
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ErrorView, { error: new Error(state.message) });
41498
41877
  case "passthrough":
41499
41878
  return null;
41500
41879
  case "trial_exhausted": {
@@ -41504,20 +41883,20 @@ var init_NpmWrapperApp = __esm({
41504
41883
  hasKey = !!getStoredApiKey2();
41505
41884
  } catch {
41506
41885
  }
41507
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Box_default, { flexDirection: "column", paddingLeft: 2, children: hasKey ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
41508
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "yellow", bold: true, children: "Your API key may be invalid or expired." }),
41509
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { children: [
41886
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { flexDirection: "column", paddingLeft: 2, children: hasKey ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
41887
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "Your API key may be invalid or expired." }),
41888
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
41510
41889
  "Run ",
41511
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
41890
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
41512
41891
  " then ",
41513
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41892
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41514
41893
  " to re-authenticate."
41515
41894
  ] })
41516
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
41517
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
41518
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { children: [
41895
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
41896
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
41897
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
41519
41898
  "Run ",
41520
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41899
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41521
41900
  " to create a free account and continue scanning."
41522
41901
  ] })
41523
41902
  ] }) });
@@ -41528,7 +41907,7 @@ var init_NpmWrapperApp = __esm({
41528
41907
  });
41529
41908
 
41530
41909
  // src/ui/hooks/usePipWrapper.ts
41531
- function reducer3(_state, action) {
41910
+ function reducer4(_state, action) {
41532
41911
  switch (action.type) {
41533
41912
  case "PASSTHROUGH":
41534
41913
  return { phase: "passthrough" };
@@ -41552,12 +41931,12 @@ function reducer3(_state, action) {
41552
41931
  return { phase: "trial_exhausted" };
41553
41932
  }
41554
41933
  }
41555
- function usePipWrapper(pipArgs, config) {
41556
- const [state, dispatch] = (0, import_react27.useReducer)(reducer3, { phase: "resolving", count: 0 });
41557
- const started = (0, import_react27.useRef)(false);
41558
- const parsedRef = (0, import_react27.useRef)(parsePipArgs(pipArgs));
41559
- const pendingInstall = (0, import_react27.useRef)(null);
41560
- const rejectRef = (0, import_react27.useRef)(null);
41934
+ function usePipWrapper(pipArgs, config, exit) {
41935
+ const [state, dispatch] = (0, import_react28.useReducer)(reducer4, { phase: "resolving", count: 0 });
41936
+ const started = (0, import_react28.useRef)(false);
41937
+ const parsedRef = (0, import_react28.useRef)(parsePipArgs(pipArgs));
41938
+ const pendingInstall = (0, import_react28.useRef)(null);
41939
+ const rejectRef = (0, import_react28.useRef)(null);
41561
41940
  const confirmInstall = () => {
41562
41941
  if (pendingInstall.current) {
41563
41942
  pendingInstall.current();
@@ -41572,7 +41951,7 @@ function usePipWrapper(pipArgs, config) {
41572
41951
  rejectRef.current = null;
41573
41952
  }
41574
41953
  };
41575
- (0, import_react27.useEffect)(() => {
41954
+ (0, import_react28.useEffect)(() => {
41576
41955
  if (started.current) return;
41577
41956
  started.current = true;
41578
41957
  const parsed = parsedRef.current;
@@ -41612,18 +41991,24 @@ function usePipWrapper(pipArgs, config) {
41612
41991
  dispatch({ type: "SCANNING", count: resolved.length });
41613
41992
  const result = await callPyPIAnalyzeAPI(resolved, config);
41614
41993
  if (result.action === "pass") {
41615
- dispatch({ type: "PASS", count: resolved.length });
41616
- dispatch({ type: "INSTALLING" });
41994
+ if (exit) exit();
41995
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
41996
+ process.stderr.write(
41997
+ chalk8.green(` \u2713 ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
41998
+ `)
41999
+ );
42000
+ process.stderr.write("\n");
41617
42001
  const code = await runPip(parsed.rawArgs);
41618
- dispatch({ type: "DONE", exitCode: code });
42002
+ process.exit(code);
41619
42003
  return;
41620
42004
  }
41621
42005
  if (result.action === "warn") {
41622
- dispatch({ type: "WARN", result });
42006
+ if (exit) exit();
41623
42007
  process.stdout.write(renderResultStatic(result, config) + "\n");
41624
- dispatch({ type: "INSTALLING" });
42008
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42009
+ process.stderr.write(chalk8.yellow(" Warnings detected. Proceeding with install.\n\n"));
41625
42010
  const code = await runPip(parsed.rawArgs);
41626
- dispatch({ type: "DONE", exitCode: code });
42011
+ process.exit(code);
41627
42012
  return;
41628
42013
  }
41629
42014
  if (result.action === "block") {
@@ -41664,11 +42049,11 @@ function usePipWrapper(pipArgs, config) {
41664
42049
  }, [pipArgs, config]);
41665
42050
  return { state, confirmInstall, rejectInstall };
41666
42051
  }
41667
- var import_react27;
42052
+ var import_react28;
41668
42053
  var init_usePipWrapper = __esm({
41669
42054
  "src/ui/hooks/usePipWrapper.ts"() {
41670
42055
  "use strict";
41671
- import_react27 = __toESM(require_react());
42056
+ import_react28 = __toESM(require_react());
41672
42057
  init_pip_wrapper();
41673
42058
  init_api();
41674
42059
  init_static_output();
@@ -41680,25 +42065,25 @@ var PipWrapperApp_exports = {};
41680
42065
  __export(PipWrapperApp_exports, {
41681
42066
  PipWrapperApp: () => PipWrapperApp
41682
42067
  });
41683
- var import_react28, import_jsx_runtime9, PipWrapperApp;
42068
+ var import_react29, import_jsx_runtime10, PipWrapperApp;
41684
42069
  var init_PipWrapperApp = __esm({
41685
42070
  async "src/ui/PipWrapperApp.tsx"() {
41686
42071
  "use strict";
41687
- import_react28 = __toESM(require_react());
42072
+ import_react29 = __toESM(require_react());
41688
42073
  await init_build2();
41689
42074
  init_usePipWrapper();
41690
42075
  await init_Spinner();
41691
42076
  await init_ResultsView();
41692
42077
  await init_ConfirmPrompt();
41693
42078
  await init_ErrorView();
41694
- import_jsx_runtime9 = __toESM(require_jsx_runtime());
42079
+ import_jsx_runtime10 = __toESM(require_jsx_runtime());
41695
42080
  PipWrapperApp = ({
41696
42081
  pipArgs,
41697
42082
  config
41698
42083
  }) => {
41699
- const { state, confirmInstall, rejectInstall } = usePipWrapper(pipArgs, config);
41700
42084
  const { exit } = use_app_default();
41701
- (0, import_react28.useEffect)(() => {
42085
+ const { state, confirmInstall, rejectInstall } = usePipWrapper(pipArgs, config, exit);
42086
+ (0, import_react29.useEffect)(() => {
41702
42087
  if (state.phase === "done") {
41703
42088
  process.exitCode = state.exitCode;
41704
42089
  const timer = setTimeout(() => exit(), 0);
@@ -41712,29 +42097,29 @@ var init_PipWrapperApp = __esm({
41712
42097
  if (state.phase === "passthrough") {
41713
42098
  }
41714
42099
  }, [state, exit]);
41715
- const handleConfirm = (0, import_react28.useCallback)(() => {
42100
+ const handleConfirm = (0, import_react29.useCallback)(() => {
41716
42101
  confirmInstall();
41717
42102
  }, [confirmInstall]);
41718
- const handleReject = (0, import_react28.useCallback)(() => {
42103
+ const handleReject = (0, import_react29.useCallback)(() => {
41719
42104
  rejectInstall();
41720
42105
  }, [rejectInstall]);
41721
42106
  switch (state.phase) {
41722
42107
  case "resolving":
41723
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
42108
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
41724
42109
  Spinner2,
41725
42110
  {
41726
42111
  label: `Resolving ${state.count} package${state.count !== 1 ? "s" : ""} from PyPI...`
41727
42112
  }
41728
42113
  );
41729
42114
  case "scanning":
41730
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
42115
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
41731
42116
  Spinner2,
41732
42117
  {
41733
42118
  label: `Scanning ${state.count} Python package${state.count !== 1 ? "s" : ""}...`
41734
42119
  }
41735
42120
  );
41736
42121
  case "pass":
41737
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "green", children: [
42122
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: "green", children: [
41738
42123
  "\u2713",
41739
42124
  " ",
41740
42125
  state.count,
@@ -41745,8 +42130,8 @@ var init_PipWrapperApp = __esm({
41745
42130
  "all clear"
41746
42131
  ] });
41747
42132
  case "warn":
41748
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41749
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
42133
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42134
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
41750
42135
  ResultsView,
41751
42136
  {
41752
42137
  result: state.result,
@@ -41754,12 +42139,12 @@ var init_PipWrapperApp = __esm({
41754
42139
  durationMs: state.result.durationMs
41755
42140
  }
41756
42141
  ),
41757
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", children: "Warnings detected. Proceeding with install..." })
42142
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "yellow", children: "Warnings detected. Proceeding with install..." })
41758
42143
  ] });
41759
42144
  case "blocked":
41760
42145
  if (state.dgForce) {
41761
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41762
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
42146
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42147
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
41763
42148
  ResultsView,
41764
42149
  {
41765
42150
  result: state.result,
@@ -41767,11 +42152,11 @@ var init_PipWrapperApp = __esm({
41767
42152
  durationMs: state.result.durationMs
41768
42153
  }
41769
42154
  ),
41770
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "--dg-force: Bypassing block. Install at your own risk." })
42155
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "yellow", bold: true, children: "--dg-force: Bypassing block. Install at your own risk." })
41771
42156
  ] });
41772
42157
  }
41773
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41774
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
42158
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42159
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
41775
42160
  ResultsView,
41776
42161
  {
41777
42162
  result: state.result,
@@ -41779,12 +42164,12 @@ var init_PipWrapperApp = __esm({
41779
42164
  durationMs: state.result.durationMs
41780
42165
  }
41781
42166
  ),
41782
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "red", bold: true, children: [
42167
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: "red", bold: true, children: [
41783
42168
  "BLOCKED:",
41784
42169
  " ",
41785
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "red", children: "High-risk packages detected." })
42170
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "red", children: "High-risk packages detected." })
41786
42171
  ] }),
41787
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
42172
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
41788
42173
  ConfirmPrompt,
41789
42174
  {
41790
42175
  message: "Proceed with install anyway?",
@@ -41794,18 +42179,18 @@ var init_PipWrapperApp = __esm({
41794
42179
  )
41795
42180
  ] });
41796
42181
  case "installing":
41797
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner2, { label: "Installing with pip..." });
42182
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Spinner2, { label: "Installing with pip..." });
41798
42183
  case "done":
41799
42184
  return null;
41800
42185
  case "error":
41801
42186
  if (state.proceed) {
41802
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "yellow", children: [
42187
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { color: "yellow", children: [
41803
42188
  "Warning: Scan failed (",
41804
42189
  state.message,
41805
42190
  "). Proceeding with install."
41806
42191
  ] });
41807
42192
  }
41808
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ErrorView, { error: new Error(state.message) });
42193
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ErrorView, { error: new Error(state.message) });
41809
42194
  case "passthrough":
41810
42195
  return null;
41811
42196
  case "trial_exhausted": {
@@ -41815,20 +42200,20 @@ var init_PipWrapperApp = __esm({
41815
42200
  hasKey = !!getStoredApiKey2();
41816
42201
  } catch {
41817
42202
  }
41818
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { flexDirection: "column", paddingLeft: 2, children: hasKey ? /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
41819
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "Your API key may be invalid or expired." }),
41820
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
42203
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "column", paddingLeft: 2, children: hasKey ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
42204
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "yellow", bold: true, children: "Your API key may be invalid or expired." }),
42205
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41821
42206
  "Run ",
41822
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
42207
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
41823
42208
  " then ",
41824
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
42209
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41825
42210
  " to re-authenticate."
41826
42211
  ] })
41827
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
41828
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
41829
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
42212
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
42213
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
42214
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41830
42215
  "Run ",
41831
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
42216
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41832
42217
  " to create a free account and continue scanning."
41833
42218
  ] })
41834
42219
  ] }) });
@@ -41838,1483 +42223,6 @@ var init_PipWrapperApp = __esm({
41838
42223
  }
41839
42224
  });
41840
42225
 
41841
- // src/ui/hooks/useScan.ts
41842
- function reducer4(_state, action) {
41843
- switch (action.type) {
41844
- case "PROJECTS_FOUND":
41845
- return { phase: "selecting", projects: action.projects };
41846
- case "RESTART_SELECTION":
41847
- return { phase: "selecting", projects: action.projects };
41848
- case "DISCOVERY_COMPLETE":
41849
- return { phase: "scanning", done: 0, total: action.packages.length, currentBatch: [] };
41850
- case "DISCOVERY_EMPTY":
41851
- return { phase: "empty", message: action.message };
41852
- case "SCAN_PROGRESS":
41853
- return { phase: "scanning", done: action.done, total: action.total, currentBatch: action.currentBatch };
41854
- case "SCAN_COMPLETE":
41855
- return { phase: "results", result: action.result, durationMs: action.durationMs, skippedCount: action.skippedCount, discoveredTotal: action.discoveredTotal };
41856
- case "ERROR":
41857
- return { phase: "error", error: action.error };
41858
- case "TRIAL_EXHAUSTED":
41859
- return { phase: "trial_exhausted", scansUsed: action.scansUsed, maxScans: action.maxScans };
41860
- }
41861
- }
41862
- function useScan(config) {
41863
- const [state, dispatch] = (0, import_react29.useReducer)(reducer4, { phase: "discovering" });
41864
- const started = (0, import_react29.useRef)(false);
41865
- const [multiProjects, setMultiProjects] = (0, import_react29.useState)(null);
41866
- (0, import_react29.useEffect)(() => {
41867
- if (started.current) return;
41868
- started.current = true;
41869
- const projects = discoverProjects(process.cwd());
41870
- if (projects.length > 1) setMultiProjects(projects);
41871
- if (projects.length > 1) {
41872
- dispatch({ type: "PROJECTS_FOUND", projects });
41873
- return;
41874
- }
41875
- try {
41876
- const discovery = discoverChanges(process.cwd(), config);
41877
- const packages = discovery.packages;
41878
- if (packages.length === 0) {
41879
- dispatch({ type: "DISCOVERY_EMPTY", message: "No package changes detected." });
41880
- return;
41881
- }
41882
- dispatch({ type: "DISCOVERY_COMPLETE", packages, skippedCount: discovery.skipped.length });
41883
- runNpmScan(packages, discovery.skipped.length, config, dispatch);
41884
- } catch {
41885
- if (projects.length === 0) {
41886
- dispatch({ type: "DISCOVERY_EMPTY", message: "No dependency files found." });
41887
- return;
41888
- }
41889
- dispatch({ type: "DISCOVERY_COMPLETE", packages: [], skippedCount: 0 });
41890
- scanProjects(projects, config, dispatch);
41891
- }
41892
- }, [config]);
41893
- const scanSelectedProjects = (0, import_react29.useCallback)((projects) => {
41894
- dispatch({ type: "DISCOVERY_COMPLETE", packages: [], skippedCount: 0 });
41895
- scanProjects(projects, config, dispatch);
41896
- }, [config]);
41897
- const restartSelection = (0, import_react29.useCallback)(() => {
41898
- if (!multiProjects) return;
41899
- dispatch({ type: "RESTART_SELECTION", projects: multiProjects });
41900
- }, [multiProjects]);
41901
- return {
41902
- state,
41903
- scanSelectedProjects,
41904
- restartSelection: multiProjects ? restartSelection : null
41905
- };
41906
- }
41907
- async function runNpmScan(packages, skippedCount, config, dispatch) {
41908
- try {
41909
- const startMs = Date.now();
41910
- const result = await callAnalyzeAPI(packages, config, (done, total) => {
41911
- const batchStart = Math.max(0, done - 15);
41912
- const currentBatch = packages.slice(batchStart, done).map((p) => p.name);
41913
- dispatch({ type: "SCAN_PROGRESS", done, total, currentBatch });
41914
- });
41915
- dispatch({ type: "SCAN_COMPLETE", result, durationMs: Date.now() - startMs, skippedCount });
41916
- } catch (error) {
41917
- if (error instanceof TrialExhaustedError) {
41918
- dispatch({ type: "TRIAL_EXHAUSTED", scansUsed: error.scansUsed, maxScans: error.maxScans });
41919
- return;
41920
- }
41921
- dispatch({ type: "ERROR", error: error instanceof Error ? error : new Error(String(error)) });
41922
- }
41923
- }
41924
- async function scanProjects(projects, config, dispatch) {
41925
- try {
41926
- const npmProjects = projects.filter((p) => p.ecosystem === "npm");
41927
- const pypiProjects = projects.filter((p) => p.ecosystem === "pypi");
41928
- const fullScanConfig = { ...config, scanAll: true };
41929
- const npmPackages = [];
41930
- const pypiPackages = [];
41931
- const seenNpm = /* @__PURE__ */ new Set();
41932
- const seenPypi = /* @__PURE__ */ new Set();
41933
- for (const proj of npmProjects) {
41934
- try {
41935
- const discovery = discoverChanges(proj.path, fullScanConfig);
41936
- for (const pkg of discovery.packages) {
41937
- const key = `${pkg.name}@${pkg.version}`;
41938
- if (!seenNpm.has(key)) {
41939
- seenNpm.add(key);
41940
- npmPackages.push(pkg);
41941
- }
41942
- }
41943
- } catch {
41944
- }
41945
- }
41946
- for (const proj of pypiProjects) {
41947
- try {
41948
- const packages = parsePythonDepFile(proj.path, proj.depFile);
41949
- for (const pkg of packages) {
41950
- const key = `${pkg.name}@${pkg.version}`;
41951
- if (!seenPypi.has(key)) {
41952
- seenPypi.add(key);
41953
- pypiPackages.push(pkg);
41954
- }
41955
- }
41956
- } catch {
41957
- }
41958
- }
41959
- const discoveredTotal = npmPackages.length + pypiPackages.length;
41960
- if (!config.apiKey) {
41961
- const anonLimit = 50;
41962
- if (npmPackages.length > anonLimit) npmPackages.length = anonLimit;
41963
- const pypiSlots = Math.max(0, anonLimit - npmPackages.length);
41964
- if (pypiPackages.length > pypiSlots) pypiPackages.length = pypiSlots;
41965
- }
41966
- const totalPackages = npmPackages.length + pypiPackages.length;
41967
- if (totalPackages === 0) {
41968
- dispatch({ type: "DISCOVERY_EMPTY", message: "No packages to scan." });
41969
- return;
41970
- }
41971
- const startMs = Date.now();
41972
- const results = [];
41973
- let completed = 0;
41974
- if (npmPackages.length > 0) {
41975
- const npmResult = await callAnalyzeAPI(npmPackages, config, (done, total) => {
41976
- completed = done;
41977
- dispatch({
41978
- type: "SCAN_PROGRESS",
41979
- done: completed,
41980
- total: totalPackages,
41981
- currentBatch: npmPackages.slice(Math.max(0, done - 15), done).map((p) => p.name)
41982
- });
41983
- });
41984
- completed = npmPackages.length;
41985
- results.push(npmResult);
41986
- }
41987
- if (pypiPackages.length > 0) {
41988
- const pypiResult = await callPyPIAnalyzeAPI(pypiPackages, config, (done) => {
41989
- dispatch({
41990
- type: "SCAN_PROGRESS",
41991
- done: completed + done,
41992
- total: totalPackages,
41993
- currentBatch: pypiPackages.slice(Math.max(0, done - 15), done).map((p) => p.name)
41994
- });
41995
- });
41996
- results.push(pypiResult);
41997
- }
41998
- const allPackages = results.flatMap((r) => r.packages);
41999
- const maxScore = Math.max(0, ...allPackages.map((p) => p.score));
42000
- const action = maxScore >= 70 ? "block" : maxScore >= 60 ? "warn" : "pass";
42001
- const safeVersions = {};
42002
- for (const r of results) Object.assign(safeVersions, r.safeVersions);
42003
- const merged = {
42004
- score: maxScore,
42005
- action,
42006
- packages: allPackages,
42007
- safeVersions,
42008
- durationMs: Date.now() - startMs
42009
- };
42010
- dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0, discoveredTotal });
42011
- } catch (error) {
42012
- if (error instanceof TrialExhaustedError) {
42013
- dispatch({ type: "TRIAL_EXHAUSTED", scansUsed: error.scansUsed, maxScans: error.maxScans });
42014
- return;
42015
- }
42016
- dispatch({ type: "ERROR", error: error instanceof Error ? error : new Error(String(error)) });
42017
- }
42018
- }
42019
- var import_react29;
42020
- var init_useScan = __esm({
42021
- "src/ui/hooks/useScan.ts"() {
42022
- "use strict";
42023
- import_react29 = __toESM(require_react());
42024
- init_lockfile();
42025
- init_api();
42026
- init_discover();
42027
- init_lockfile();
42028
- }
42029
- });
42030
-
42031
- // src/ui/components/ProgressBar.tsx
42032
- function estimateScanSeconds(packageCount) {
42033
- return Math.ceil(Math.max(5, packageCount * 0.35 - 10));
42034
- }
42035
- function formatTime(seconds) {
42036
- if (seconds < 60) return `${seconds}s`;
42037
- const m = Math.floor(seconds / 60);
42038
- const s = seconds % 60;
42039
- return s > 0 ? `${m}m ${s}s` : `${m}m`;
42040
- }
42041
- var import_react30, import_chalk9, import_jsx_runtime10, ProgressBar;
42042
- var init_ProgressBar = __esm({
42043
- async "src/ui/components/ProgressBar.tsx"() {
42044
- "use strict";
42045
- import_react30 = __toESM(require_react());
42046
- await init_build2();
42047
- await init_build3();
42048
- import_chalk9 = __toESM(require_source());
42049
- import_jsx_runtime10 = __toESM(require_jsx_runtime());
42050
- ProgressBar = ({
42051
- value,
42052
- total,
42053
- label
42054
- }) => {
42055
- const startRef = (0, import_react30.useRef)(Date.now());
42056
- const [elapsed, setElapsed] = (0, import_react30.useState)(0);
42057
- (0, import_react30.useEffect)(() => {
42058
- const timer = setInterval(() => {
42059
- setElapsed(Math.floor((Date.now() - startRef.current) / 1e3));
42060
- }, 1e3);
42061
- return () => clearInterval(timer);
42062
- }, []);
42063
- const termWidth = process.stdout.columns || 80;
42064
- const percent = total > 0 ? Math.round(value / total * 100) : 0;
42065
- const estimate = estimateScanSeconds(total);
42066
- const timeInfo = `${formatTime(elapsed)} / ~${formatTime(estimate)}`;
42067
- const counter = `${value}/${total} ${percent}%`;
42068
- const barWidth = Math.max(10, termWidth - counter.length - 8);
42069
- const fraction = total > 0 ? Math.min(1, value / total) : 0;
42070
- const filled = Math.round(fraction * barWidth);
42071
- const empty = barWidth - filled;
42072
- const filledBar = "\u2501".repeat(filled);
42073
- const emptyBar = "\u2501".repeat(empty);
42074
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
42075
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42076
- import_chalk9.default.cyan("\u25C6"),
42077
- " ",
42078
- import_chalk9.default.bold("Dependency Guardian")
42079
- ] }),
42080
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }),
42081
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { children: [
42082
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "cyan", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(build_default, { type: "dots" }) }),
42083
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42084
- " Scanning ",
42085
- total,
42086
- " packages... "
42087
- ] }),
42088
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: timeInfo })
42089
- ] }),
42090
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { children: [
42091
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: " " }),
42092
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { color: "green", children: filledBar }),
42093
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: emptyBar }),
42094
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42095
- " ",
42096
- counter
42097
- ] })
42098
- ] }),
42099
- label && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42100
- " ",
42101
- import_chalk9.default.dim("\u203A"),
42102
- " ",
42103
- label
42104
- ] }) })
42105
- ] });
42106
- };
42107
- }
42108
- });
42109
-
42110
- // src/ui/hooks/useExpandAnimation.ts
42111
- function useExpandAnimation(targetHeight, active, durationMs = 180) {
42112
- const [visibleLines, setVisibleLines] = (0, import_react31.useState)(0);
42113
- const timerRef = (0, import_react31.useRef)(null);
42114
- (0, import_react31.useEffect)(() => {
42115
- if (timerRef.current) {
42116
- clearInterval(timerRef.current);
42117
- timerRef.current = null;
42118
- }
42119
- if (!active || targetHeight <= 0) {
42120
- setVisibleLines(0);
42121
- return;
42122
- }
42123
- const intervalMs = Math.max(16, Math.floor(durationMs / targetHeight));
42124
- let current = 1;
42125
- setVisibleLines(1);
42126
- timerRef.current = setInterval(() => {
42127
- current++;
42128
- if (current >= targetHeight) {
42129
- setVisibleLines(targetHeight);
42130
- if (timerRef.current) clearInterval(timerRef.current);
42131
- timerRef.current = null;
42132
- } else {
42133
- setVisibleLines(current);
42134
- }
42135
- }, intervalMs);
42136
- return () => {
42137
- if (timerRef.current) {
42138
- clearInterval(timerRef.current);
42139
- timerRef.current = null;
42140
- }
42141
- };
42142
- }, [active, targetHeight, durationMs]);
42143
- return {
42144
- visibleLines: active ? visibleLines : 0,
42145
- isAnimating: active && visibleLines > 0 && visibleLines < targetHeight
42146
- };
42147
- }
42148
- var import_react31;
42149
- var init_useExpandAnimation = __esm({
42150
- "src/ui/hooks/useExpandAnimation.ts"() {
42151
- "use strict";
42152
- import_react31 = __toESM(require_react());
42153
- }
42154
- });
42155
-
42156
- // src/ui/hooks/useTerminalSize.ts
42157
- function useTerminalSize() {
42158
- const { stdout } = use_stdout_default();
42159
- const [size, setSize] = (0, import_react32.useState)({
42160
- rows: stdout?.rows ?? process.stdout.rows ?? 24,
42161
- cols: stdout?.columns ?? process.stdout.columns ?? 80
42162
- });
42163
- (0, import_react32.useEffect)(() => {
42164
- const handle = () => {
42165
- const rows = process.stdout.rows ?? 24;
42166
- const cols = process.stdout.columns ?? 80;
42167
- if (process.stdout.isTTY) {
42168
- process.stdout.write("\x1B[2J\x1B[H");
42169
- }
42170
- setSize({ rows, cols });
42171
- };
42172
- process.stdout.setMaxListeners(process.stdout.getMaxListeners() + 1);
42173
- process.stdout.on("resize", handle);
42174
- return () => {
42175
- process.stdout.off("resize", handle);
42176
- process.stdout.setMaxListeners(Math.max(0, process.stdout.getMaxListeners() - 1));
42177
- };
42178
- }, []);
42179
- return size;
42180
- }
42181
- var import_react32;
42182
- var init_useTerminalSize = __esm({
42183
- async "src/ui/hooks/useTerminalSize.ts"() {
42184
- "use strict";
42185
- import_react32 = __toESM(require_react());
42186
- await init_build2();
42187
- }
42188
- });
42189
-
42190
- // src/ui/components/InteractiveResultsView.tsx
42191
- function groupPackages3(packages) {
42192
- const map = /* @__PURE__ */ new Map();
42193
- for (const pkg of packages) {
42194
- 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}`;
42195
- const group = map.get(fingerprint) ?? [];
42196
- group.push(pkg);
42197
- map.set(fingerprint, group);
42198
- }
42199
- return [...map.entries()].map(([fingerprint, pkgs]) => ({ packages: pkgs, key: fingerprint })).sort((a, b) => b.packages[0].score - a.packages[0].score);
42200
- }
42201
- function actionBadge3(score) {
42202
- if (score >= 70)
42203
- return { label: "BLOCK", color: import_chalk10.default.red };
42204
- if (score >= 60)
42205
- return { label: "WARN", color: import_chalk10.default.yellow };
42206
- return { label: "PASS", color: import_chalk10.default.green };
42207
- }
42208
- function truncate3(s, max) {
42209
- return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
42210
- }
42211
- function pad3(s, len) {
42212
- return s + " ".repeat(Math.max(0, len - s.length));
42213
- }
42214
- function findingsSummaryHeight(group) {
42215
- const rep = group.packages[0];
42216
- const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical);
42217
- let h = visibleFindings.length;
42218
- if (rep.license) h += 1;
42219
- if (visibleFindings.length === 0 && rep.score > 0) {
42220
- h += (rep.reasons ?? []).length;
42221
- h += 1;
42222
- }
42223
- if (group.packages.length > 3) h += 1;
42224
- return h;
42225
- }
42226
- function findingsDetailHeight(group, safeVersions) {
42227
- const rep = group.packages[0];
42228
- const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
42229
- let h = 0;
42230
- if (rep.license) h += 1;
42231
- if (group.packages.length > 3) h += 1;
42232
- if (visibleFindings.length === 0 && rep.score > 0) {
42233
- h += (rep.reasons ?? []).length;
42234
- h += 1;
42235
- }
42236
- const hasEvidence = visibleFindings.some((f) => f.evidence && f.evidence.length > 0);
42237
- for (const finding of visibleFindings) {
42238
- h += 1;
42239
- h += 1;
42240
- const evidence = finding.evidence ?? [];
42241
- h += Math.min(evidence.length, EVIDENCE_LIMIT2);
42242
- if (evidence.length > EVIDENCE_LIMIT2) h += 1;
42243
- }
42244
- if (visibleFindings.length > 0 && !hasEvidence) h += 1;
42245
- if (rep.recommendation) h += 1;
42246
- if (safeVersions[rep.name]) h += 1;
42247
- return h;
42248
- }
42249
- function groupRowHeight(group, level, safeVersions) {
42250
- if (level === null) return 1;
42251
- if (level === "summary") return 1 + findingsSummaryHeight(group);
42252
- return 1 + findingsDetailHeight(group, safeVersions);
42253
- }
42254
- function groupNames(group) {
42255
- if (group.packages.length === 1) return group.packages[0].name;
42256
- if (group.packages.length <= 3)
42257
- return group.packages.map((p) => p.name).join(", ");
42258
- return `${group.packages[0].name} + ${group.packages.length - 1} similar`;
42259
- }
42260
- function affectsLine(group) {
42261
- const names = group.packages.map((p) => p.name);
42262
- if (names.length <= 5) return names.join(", ");
42263
- return names.slice(0, 5).join(", ") + ` + ${names.length - 5} more`;
42264
- }
42265
- function buildDetailLines(group, safeVersion, maxWidth) {
42266
- const rep = group.packages[0];
42267
- const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
42268
- const lines = [];
42269
- const evidenceWidth = Math.max(30, maxWidth - 12);
42270
- if (group.packages.length > 3) {
42271
- lines.push(
42272
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42273
- "Affects: ",
42274
- affectsLine(group)
42275
- ] }, "affects")
42276
- );
42277
- lines.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }, "affects-gap"));
42278
- }
42279
- if (rep.score > 0) {
42280
- lines.push(
42281
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42282
- "Score: ",
42283
- rep.score,
42284
- "/100"
42285
- ] }, "score-info")
42286
- );
42287
- }
42288
- if (rep.recommendation) {
42289
- lines.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }, "rec-gap"));
42290
- lines.push(
42291
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42292
- import_chalk10.default.dim("Rec:"),
42293
- " ",
42294
- import_chalk10.default.cyan(truncate3(rep.recommendation, maxWidth - 8))
42295
- ] }, "recommendation")
42296
- );
42297
- }
42298
- if (safeVersion) {
42299
- lines.push(
42300
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: import_chalk10.default.green(`Safe: ${rep.name}@${safeVersion}`) }, "safe")
42301
- );
42302
- }
42303
- return lines;
42304
- }
42305
- function viewReducer(_state, action) {
42306
- switch (action.type) {
42307
- case "MOVE":
42308
- return { ..._state, cursor: action.cursor, viewport: action.viewport };
42309
- case "EXPAND":
42310
- return { ..._state, expandedIndex: action.expandedIndex, expandLevel: action.expandLevel, viewport: action.viewport };
42311
- case "MOVE_EXPAND":
42312
- return { cursor: action.cursor, expandedIndex: action.expandedIndex, expandLevel: action.expandLevel, viewport: action.viewport };
42313
- }
42314
- }
42315
- function licenseLine(rep) {
42316
- const lc = rep.license;
42317
- if (!lc) return null;
42318
- const spdx = lc.spdx ?? lc.raw ?? "";
42319
- const desc = LICENSE_DESCRIPTIONS[lc.riskCategory] ?? "";
42320
- const lcColor = lc.riskCategory === "permissive" ? import_chalk10.default.green : lc.riskCategory === "no-license" || lc.riskCategory === "unlicensed" || lc.riskCategory === "network-copyleft" ? import_chalk10.default.red : import_chalk10.default.yellow;
42321
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42322
- T.branch,
42323
- " ",
42324
- lcColor(spdx),
42325
- " ",
42326
- import_chalk10.default.dim("\u2014"),
42327
- " ",
42328
- import_chalk10.default.dim(desc)
42329
- ] }, "license-info");
42330
- }
42331
- var import_react33, import_chalk10, import_jsx_runtime11, SEVERITY_LABELS2, SEVERITY_COLORS, EVIDENCE_LIMIT2, FIXED_CHROME, DETAIL_PANE_CHROME, InteractiveResultsView, T, LICENSE_DESCRIPTIONS, FindingsSummary;
42332
- var init_InteractiveResultsView = __esm({
42333
- async "src/ui/components/InteractiveResultsView.tsx"() {
42334
- "use strict";
42335
- import_react33 = __toESM(require_react());
42336
- await init_build2();
42337
- import_chalk10 = __toESM(require_source());
42338
- await init_ScoreHeader();
42339
- init_useExpandAnimation();
42340
- await init_useTerminalSize();
42341
- import_jsx_runtime11 = __toESM(require_jsx_runtime());
42342
- SEVERITY_LABELS2 = {
42343
- 5: "CRIT",
42344
- 4: "HIGH",
42345
- 3: "MED",
42346
- 2: "LOW",
42347
- 1: "INFO"
42348
- };
42349
- SEVERITY_COLORS = {
42350
- 5: (s) => import_chalk10.default.red.bold(s),
42351
- 4: (s) => import_chalk10.default.magenta(s),
42352
- 3: (s) => import_chalk10.default.yellow(s),
42353
- 2: (s) => import_chalk10.default.dim(s),
42354
- 1: (s) => import_chalk10.default.gray(s)
42355
- };
42356
- EVIDENCE_LIMIT2 = 2;
42357
- FIXED_CHROME = 21;
42358
- DETAIL_PANE_CHROME = 20;
42359
- InteractiveResultsView = ({
42360
- result,
42361
- config,
42362
- durationMs,
42363
- onExit,
42364
- onBack,
42365
- discoveredTotal
42366
- }) => {
42367
- const flagged = (0, import_react33.useMemo)(
42368
- () => result.packages.filter((p) => p.score > 0),
42369
- [result.packages]
42370
- );
42371
- const clean = (0, import_react33.useMemo)(
42372
- () => result.packages.filter((p) => p.score === 0),
42373
- [result.packages]
42374
- );
42375
- const total = result.packages.length;
42376
- const [searchQuery, setSearchQuery] = (0, import_react33.useState)("");
42377
- const allGroups = (0, import_react33.useMemo)(() => groupPackages3(flagged), [flagged]);
42378
- const allGroupCount = allGroups.length;
42379
- const groups = (0, import_react33.useMemo)(() => {
42380
- if (!searchQuery) return allGroups;
42381
- const q = searchQuery.toLowerCase();
42382
- return allGroups.filter((g) => g.packages.some((p) => p.name.toLowerCase().includes(q)));
42383
- }, [allGroups, searchQuery]);
42384
- const severityCounts = (0, import_react33.useMemo)(() => {
42385
- const counts = {};
42386
- for (const pkg of flagged) {
42387
- const maxSev = pkg.findings.reduce((m, f) => Math.max(m, f.severity), 0);
42388
- if (maxSev >= 2) counts[maxSev] = (counts[maxSev] ?? 0) + 1;
42389
- }
42390
- return counts;
42391
- }, [flagged]);
42392
- const [view, dispatchView] = (0, import_react33.useReducer)(viewReducer, {
42393
- cursor: 0,
42394
- expandLevel: null,
42395
- expandedIndex: null,
42396
- viewport: 0
42397
- });
42398
- const viewRef = (0, import_react33.useRef)(view);
42399
- viewRef.current = view;
42400
- const [detailPane, setDetailPane] = (0, import_react33.useState)(null);
42401
- const detailPaneRef = (0, import_react33.useRef)(detailPane);
42402
- detailPaneRef.current = detailPane;
42403
- const [showHelp, setShowHelp] = (0, import_react33.useState)(false);
42404
- const showHelpRef = (0, import_react33.useRef)(showHelp);
42405
- showHelpRef.current = showHelp;
42406
- const [searchMode, setSearchMode] = (0, import_react33.useState)(false);
42407
- const searchModeRef = (0, import_react33.useRef)(searchMode);
42408
- searchModeRef.current = searchMode;
42409
- const { rows: termRows, cols: termCols } = useTerminalSize();
42410
- const availableRows = Math.max(5, termRows - FIXED_CHROME);
42411
- const innerWidth = Math.max(40, termCols - 6);
42412
- const detailGroupIdx = detailPane?.groupIndex ?? -1;
42413
- const detailLines = (0, import_react33.useMemo)(() => {
42414
- if (detailGroupIdx < 0) return [];
42415
- const group = groups[detailGroupIdx];
42416
- if (!group) return [];
42417
- return buildDetailLines(group, result.safeVersions[group.packages[0].name], innerWidth);
42418
- }, [detailGroupIdx, groups, result.safeVersions, innerWidth]);
42419
- const detailContentRows = Math.max(3, termRows - DETAIL_PANE_CHROME);
42420
- const getLevel = (idx) => {
42421
- return view.expandedIndex === idx ? view.expandLevel : null;
42422
- };
42423
- const expandTargetHeight = (0, import_react33.useMemo)(() => {
42424
- if (view.expandedIndex === null || view.expandLevel === null) return 0;
42425
- const group = groups[view.expandedIndex];
42426
- if (!group) return 0;
42427
- if (view.expandLevel === "summary") return findingsSummaryHeight(group);
42428
- return findingsDetailHeight(group, result.safeVersions);
42429
- }, [view.expandedIndex, view.expandLevel, groups, result.safeVersions]);
42430
- const { visibleLines: animVisibleLines } = useExpandAnimation(
42431
- expandTargetHeight,
42432
- view.expandedIndex !== null
42433
- );
42434
- const animatedGroupHeight = (group, level, idx) => {
42435
- if (level === null) return 1;
42436
- if (idx === view.expandedIndex) return 1 + animVisibleLines;
42437
- return groupRowHeight(group, level, result.safeVersions);
42438
- };
42439
- const visibleEnd = (0, import_react33.useMemo)(() => {
42440
- let consumed = 0;
42441
- let end = view.viewport;
42442
- while (end < groups.length) {
42443
- const level = getLevel(end);
42444
- const h = animatedGroupHeight(groups[end], level, end);
42445
- if (consumed + h > availableRows) break;
42446
- consumed += h;
42447
- end++;
42448
- }
42449
- if (end === view.viewport && groups.length > 0) end = view.viewport + 1;
42450
- return end;
42451
- }, [view.viewport, groups, view.expandedIndex, view.expandLevel, animVisibleLines, availableRows, result.safeVersions]);
42452
- const adjustViewport = (cursor, expIdx, expLvl, currentStart) => {
42453
- if (cursor < currentStart) return cursor;
42454
- const getLvl = (i) => expIdx === i ? expLvl : null;
42455
- let consumed = 0;
42456
- for (let i = currentStart; i <= cursor && i < groups.length; i++) {
42457
- consumed += groupRowHeight(groups[i], getLvl(i), result.safeVersions);
42458
- }
42459
- if (consumed <= availableRows) return currentStart;
42460
- let newStart = currentStart;
42461
- while (newStart < cursor) {
42462
- newStart++;
42463
- consumed = 0;
42464
- for (let i = newStart; i <= cursor; i++) {
42465
- consumed += groupRowHeight(groups[i], getLvl(i), result.safeVersions);
42466
- }
42467
- if (consumed <= availableRows) break;
42468
- }
42469
- return newStart;
42470
- };
42471
- (0, import_react33.useEffect)(() => {
42472
- if (groups.length === 0) return;
42473
- const { cursor, expandedIndex, expandLevel, viewport } = viewRef.current;
42474
- const clamped = Math.min(viewport, Math.max(0, groups.length - 1));
42475
- const newVp = adjustViewport(cursor, expandedIndex, expandLevel, clamped);
42476
- dispatchView({ type: "MOVE", cursor, viewport: newVp });
42477
- }, [availableRows]);
42478
- (0, import_react33.useEffect)(() => {
42479
- const dp = detailPaneRef.current;
42480
- if (dp && detailLines.length > 0) {
42481
- const maxScroll = Math.max(0, detailLines.length - detailContentRows);
42482
- if (dp.scroll > maxScroll) {
42483
- setDetailPane({ groupIndex: dp.groupIndex, scroll: maxScroll });
42484
- }
42485
- }
42486
- }, [detailContentRows, detailLines.length]);
42487
- use_input_default((input, key) => {
42488
- if (groups.length === 0) {
42489
- if (input === "q" || key.return) onExit();
42490
- return;
42491
- }
42492
- if (showHelpRef.current) {
42493
- if (input === "?" || key.escape) setShowHelp(false);
42494
- else if (input === "q") onExit();
42495
- return;
42496
- }
42497
- if (input === "?") {
42498
- setShowHelp(true);
42499
- return;
42500
- }
42501
- if (searchModeRef.current) {
42502
- if (key.escape) {
42503
- setSearchMode(false);
42504
- setSearchQuery("");
42505
- dispatchView({ type: "MOVE", cursor: 0, viewport: 0 });
42506
- } else if (key.return) {
42507
- setSearchMode(false);
42508
- } else if (key.backspace || key.delete) {
42509
- setSearchQuery((prev) => prev.slice(0, -1));
42510
- dispatchView({ type: "MOVE", cursor: 0, viewport: 0 });
42511
- } else if (input && !key.upArrow && !key.downArrow && /^[\x20-\x7e]+$/.test(input)) {
42512
- setSearchQuery((prev) => prev + input);
42513
- dispatchView({ type: "MOVE", cursor: 0, viewport: 0 });
42514
- }
42515
- return;
42516
- }
42517
- const dp = detailPaneRef.current;
42518
- if (dp !== null) {
42519
- const maxScroll = Math.max(0, detailLines.length - detailContentRows);
42520
- if (key.upArrow || input === "k") {
42521
- setDetailPane({ groupIndex: dp.groupIndex, scroll: Math.max(0, dp.scroll - 1) });
42522
- } else if (key.downArrow || input === "j") {
42523
- setDetailPane({ groupIndex: dp.groupIndex, scroll: Math.min(maxScroll, dp.scroll + 1) });
42524
- } else if (input === "g") {
42525
- setDetailPane({ groupIndex: dp.groupIndex, scroll: 0 });
42526
- } else if (input === "G") {
42527
- setDetailPane({ groupIndex: dp.groupIndex, scroll: maxScroll });
42528
- } else if (input === " " || input === "e" || input === "b" || key.escape) {
42529
- setDetailPane(null);
42530
- } else if (input === "q") {
42531
- onExit();
42532
- }
42533
- return;
42534
- }
42535
- if (groups.length === 0) {
42536
- if (input === "q") onExit();
42537
- else if (input === "/") setSearchMode(true);
42538
- return;
42539
- }
42540
- const { cursor, expandLevel: expLvl, expandedIndex: expIdx, viewport: vpStart } = viewRef.current;
42541
- if (key.upArrow || input === "k") {
42542
- const next = Math.max(0, cursor - 1);
42543
- const newVp = adjustViewport(next, expIdx, expLvl, vpStart < next ? vpStart : next);
42544
- dispatchView({ type: "MOVE", cursor: next, viewport: newVp });
42545
- } else if (key.downArrow || input === "j") {
42546
- const next = Math.min(groups.length - 1, cursor + 1);
42547
- const newVp = adjustViewport(next, expIdx, expLvl, vpStart);
42548
- dispatchView({ type: "MOVE", cursor: next, viewport: newVp });
42549
- } else if (input === "g") {
42550
- const newVp = adjustViewport(0, expIdx, expLvl, 0);
42551
- dispatchView({ type: "MOVE", cursor: 0, viewport: newVp });
42552
- } else if (input === "G") {
42553
- const last = groups.length - 1;
42554
- const newVp = adjustViewport(last, expIdx, expLvl, vpStart);
42555
- dispatchView({ type: "MOVE", cursor: last, viewport: newVp });
42556
- } else if (key.pageDown) {
42557
- const next = Math.min(groups.length - 1, cursor + availableRows);
42558
- const newVp = adjustViewport(next, expIdx, expLvl, vpStart);
42559
- dispatchView({ type: "MOVE", cursor: next, viewport: newVp });
42560
- } else if (key.pageUp) {
42561
- const next = Math.max(0, cursor - availableRows);
42562
- const newVp = adjustViewport(next, expIdx, expLvl, next);
42563
- dispatchView({ type: "MOVE", cursor: next, viewport: newVp });
42564
- } else if (key.return) {
42565
- let newExpIdx;
42566
- let newExpLvl;
42567
- if (expIdx === cursor && expLvl !== null) {
42568
- newExpIdx = null;
42569
- newExpLvl = null;
42570
- } else {
42571
- newExpIdx = cursor;
42572
- newExpLvl = "summary";
42573
- }
42574
- const newVp = adjustViewport(cursor, newExpIdx, newExpLvl, vpStart);
42575
- dispatchView({ type: "EXPAND", expandedIndex: newExpIdx, expandLevel: newExpLvl, viewport: newVp });
42576
- } else if (input === " " || input === "e") {
42577
- setDetailPane({ groupIndex: view.cursor, scroll: 0 });
42578
- } else if (input === "/") {
42579
- setSearchMode(true);
42580
- } else if (input === "b" && onBack) {
42581
- onBack();
42582
- } else if (input === "q") {
42583
- onExit();
42584
- }
42585
- });
42586
- const visibleGroups = groups.slice(view.viewport, visibleEnd);
42587
- const aboveCount = view.viewport;
42588
- const belowCount = groups.length - visibleEnd;
42589
- const lcCol = 16;
42590
- const nameCol = Math.max(20, innerWidth - 22 - lcCol);
42591
- const clampedCursor = groups.length > 0 ? Math.min(view.cursor, groups.length - 1) : 0;
42592
- if (showHelp) {
42593
- const isDetail = detailPane !== null;
42594
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42595
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42596
- ScoreHeader,
42597
- {
42598
- score: result.score,
42599
- action: result.action,
42600
- total,
42601
- flagged: flagged.length,
42602
- clean: clean.length,
42603
- severityCounts
42604
- }
42605
- ),
42606
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42607
- Box_default,
42608
- {
42609
- flexDirection: "column",
42610
- borderStyle: "round",
42611
- borderColor: "cyan",
42612
- paddingLeft: 2,
42613
- paddingRight: 2,
42614
- width: "100%",
42615
- children: [
42616
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { bold: true, children: [
42617
- import_chalk10.default.cyan("\u25C6"),
42618
- " Keyboard Shortcuts"
42619
- ] }),
42620
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42621
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { bold: true, children: " Navigation" }),
42622
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42623
- " ",
42624
- import_chalk10.default.cyan("\u2191 k"),
42625
- " ",
42626
- import_chalk10.default.dim("Move up")
42627
- ] }),
42628
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42629
- " ",
42630
- import_chalk10.default.cyan("\u2193 j"),
42631
- " ",
42632
- import_chalk10.default.dim("Move down")
42633
- ] }),
42634
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42635
- " ",
42636
- import_chalk10.default.cyan("g"),
42637
- " ",
42638
- import_chalk10.default.dim("Jump to top")
42639
- ] }),
42640
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42641
- " ",
42642
- import_chalk10.default.cyan("G"),
42643
- " ",
42644
- import_chalk10.default.dim("Jump to bottom")
42645
- ] }),
42646
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42647
- " ",
42648
- import_chalk10.default.cyan("PgUp"),
42649
- " ",
42650
- import_chalk10.default.dim("Page up")
42651
- ] }),
42652
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42653
- " ",
42654
- import_chalk10.default.cyan("PgDn"),
42655
- " ",
42656
- import_chalk10.default.dim("Page down")
42657
- ] }),
42658
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42659
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { bold: true, children: " Actions" }),
42660
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42661
- " ",
42662
- import_chalk10.default.cyan("\u23CE"),
42663
- " ",
42664
- import_chalk10.default.dim("Toggle summary")
42665
- ] }),
42666
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42667
- " ",
42668
- import_chalk10.default.cyan("space"),
42669
- " ",
42670
- import_chalk10.default.dim(isDetail ? "Back to list" : "Open detail view")
42671
- ] }),
42672
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42673
- " ",
42674
- import_chalk10.default.cyan("/"),
42675
- " ",
42676
- import_chalk10.default.dim("Search packages")
42677
- ] }),
42678
- !isDetail && onBack && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42679
- " ",
42680
- import_chalk10.default.cyan("b"),
42681
- " ",
42682
- import_chalk10.default.dim("Back to project selector")
42683
- ] }),
42684
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42685
- " ",
42686
- import_chalk10.default.cyan("q"),
42687
- " ",
42688
- import_chalk10.default.dim("Quit")
42689
- ] }),
42690
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42691
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42692
- " Press ",
42693
- import_chalk10.default.bold.cyan("?"),
42694
- " or ",
42695
- import_chalk10.default.bold.cyan("Esc"),
42696
- " to close"
42697
- ] })
42698
- ]
42699
- }
42700
- )
42701
- ] });
42702
- }
42703
- if (detailPane !== null) {
42704
- const dpGroup = groups[detailPane.groupIndex];
42705
- if (!dpGroup) {
42706
- setDetailPane(null);
42707
- } else {
42708
- const dpRep = dpGroup.packages[0];
42709
- const { color: dpColor } = actionBadge3(dpRep.score);
42710
- const dpScroll = detailPane.scroll;
42711
- const dpAbove = dpScroll;
42712
- const dpBelow = Math.max(0, detailLines.length - dpScroll - detailContentRows);
42713
- const dpVisible = detailLines.slice(dpScroll, dpScroll + detailContentRows);
42714
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42715
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42716
- ScoreHeader,
42717
- {
42718
- score: result.score,
42719
- action: result.action,
42720
- total,
42721
- flagged: flagged.length,
42722
- clean: clean.length,
42723
- severityCounts
42724
- }
42725
- ),
42726
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42727
- Box_default,
42728
- {
42729
- flexDirection: "column",
42730
- borderStyle: "round",
42731
- borderColor: "gray",
42732
- paddingLeft: 1,
42733
- paddingRight: 1,
42734
- width: "100%",
42735
- children: [
42736
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { justifyContent: "space-between", children: [
42737
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { bold: true, children: [
42738
- groupNames(dpGroup),
42739
- dpRep.license ? import_chalk10.default.dim(" \xB7 ") + (dpRep.license.riskCategory === "permissive" ? import_chalk10.default.green(dpRep.license.spdx ?? dpRep.license.raw ?? "") : dpRep.license.riskCategory === "no-license" || dpRep.license.riskCategory === "network-copyleft" ? import_chalk10.default.red(dpRep.license.spdx ?? dpRep.license.raw ?? "No license") : import_chalk10.default.yellow(dpRep.license.spdx ?? dpRep.license.raw ?? "")) : ""
42740
- ] }),
42741
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: dpColor(`score ${dpRep.score}`) })
42742
- ] }),
42743
- dpAbove > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42744
- import_chalk10.default.cyan(" \u2191"),
42745
- " ",
42746
- dpAbove,
42747
- " more above"
42748
- ] }),
42749
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: dpVisible }),
42750
- dpBelow > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42751
- import_chalk10.default.cyan(" \u2193"),
42752
- " ",
42753
- dpBelow,
42754
- " more below"
42755
- ] })
42756
- ]
42757
- }
42758
- ),
42759
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42760
- Box_default,
42761
- {
42762
- flexDirection: "column",
42763
- borderStyle: "round",
42764
- borderColor: "gray",
42765
- paddingLeft: 1,
42766
- paddingRight: 1,
42767
- width: "100%",
42768
- children: [
42769
- clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42770
- import_chalk10.default.green("\u2713"),
42771
- " ",
42772
- import_chalk10.default.green.bold(String(clean.length)),
42773
- " ",
42774
- import_chalk10.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
42775
- ] }),
42776
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { justifyContent: "space-between", children: [
42777
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42778
- (durationMs / 1e3).toFixed(1),
42779
- "s"
42780
- ] }),
42781
- result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: "Free tier \xB7 dg login for finding details" })
42782
- ] })
42783
- ]
42784
- }
42785
- ),
42786
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: import_chalk10.default.dim("\u2500".repeat(Math.min(60, termCols - 4))) }),
42787
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42788
- " ",
42789
- import_chalk10.default.bold.cyan("\u2191\u2193"),
42790
- " ",
42791
- import_chalk10.default.dim("scroll"),
42792
- " ",
42793
- import_chalk10.default.bold.cyan("space"),
42794
- " ",
42795
- import_chalk10.default.dim("back"),
42796
- " ",
42797
- import_chalk10.default.bold.cyan("q"),
42798
- " ",
42799
- import_chalk10.default.dim("quit")
42800
- ] })
42801
- ] });
42802
- }
42803
- }
42804
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42805
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42806
- ScoreHeader,
42807
- {
42808
- score: result.score,
42809
- action: result.action,
42810
- total,
42811
- flagged: flagged.length,
42812
- clean: clean.length,
42813
- severityCounts
42814
- }
42815
- ),
42816
- groups.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42817
- Box_default,
42818
- {
42819
- flexDirection: "column",
42820
- borderStyle: "round",
42821
- borderColor: "gray",
42822
- paddingLeft: 1,
42823
- paddingRight: 1,
42824
- width: "100%",
42825
- children: [
42826
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { justifyContent: "space-between", children: [
42827
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { bold: true, children: "Flagged Packages" }),
42828
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: searchQuery ? `${groups.length} of ${allGroupCount}` : `${clampedCursor + 1}/${groups.length}` })
42829
- ] }),
42830
- aboveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42831
- import_chalk10.default.cyan(" \u2191"),
42832
- " ",
42833
- aboveCount,
42834
- " more above"
42835
- ] }),
42836
- visibleGroups.map((group, visIdx) => {
42837
- const globalIdx = view.viewport + visIdx;
42838
- const isCursor = globalIdx === clampedCursor;
42839
- const level = getLevel(globalIdx);
42840
- const rep = group.packages[0];
42841
- const { label, color } = actionBadge3(rep.score);
42842
- const names = groupNames(group);
42843
- const chevron = level !== null ? "\u25BE" : "\u25B8";
42844
- const scoreStr = String(rep.score);
42845
- const lcInfo = rep.license;
42846
- const lcStr = lcInfo ? truncate3(lcInfo.spdx ?? lcInfo.raw ?? "", lcCol - 2) : "";
42847
- const lcColor = !lcInfo ? import_chalk10.default.dim : lcInfo.riskCategory === "permissive" ? import_chalk10.default.green : lcInfo.riskCategory === "no-license" || lcInfo.riskCategory === "unlicensed" || lcInfo.riskCategory === "network-copyleft" ? import_chalk10.default.red : import_chalk10.default.yellow;
42848
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42849
- isCursor ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42850
- import_chalk10.default.cyan("\u258C"),
42851
- ` ${chevron} `,
42852
- color(pad3(label, 6)),
42853
- import_chalk10.default.bold(pad3(truncate3(names, nameCol - 2), nameCol)),
42854
- lcColor(pad3(lcStr, lcCol)),
42855
- color(scoreStr.padStart(3))
42856
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42857
- ` ${import_chalk10.default.dim(chevron)} `,
42858
- color(pad3(label, 6)),
42859
- pad3(truncate3(names, nameCol - 2), nameCol),
42860
- lcColor(pad3(lcStr, lcCol)),
42861
- color(scoreStr.padStart(3))
42862
- ] }),
42863
- level === "summary" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42864
- FindingsSummary,
42865
- {
42866
- group,
42867
- maxWidth: innerWidth - 8,
42868
- maxLines: globalIdx === view.expandedIndex ? animVisibleLines : void 0
42869
- }
42870
- )
42871
- ] }, group.key);
42872
- }),
42873
- belowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42874
- import_chalk10.default.cyan(" \u2193"),
42875
- " ",
42876
- belowCount,
42877
- " more below"
42878
- ] })
42879
- ]
42880
- }
42881
- ),
42882
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42883
- Box_default,
42884
- {
42885
- flexDirection: "column",
42886
- borderStyle: "round",
42887
- borderColor: "gray",
42888
- paddingLeft: 1,
42889
- paddingRight: 1,
42890
- width: "100%",
42891
- children: [
42892
- clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42893
- import_chalk10.default.green("\u2713"),
42894
- " ",
42895
- import_chalk10.default.green.bold(String(clean.length)),
42896
- " ",
42897
- import_chalk10.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
42898
- ] }),
42899
- discoveredTotal !== void 0 && discoveredTotal > total && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42900
- "Scanned ",
42901
- total,
42902
- " of ",
42903
- discoveredTotal,
42904
- " packages ",
42905
- import_chalk10.default.dim("\u2014 dg login for full scans")
42906
- ] }),
42907
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { justifyContent: "space-between", children: [
42908
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42909
- (durationMs / 1e3).toFixed(1),
42910
- "s"
42911
- ] }),
42912
- result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: "Free tier \xB7 dg login for finding details" })
42913
- ] })
42914
- ]
42915
- }
42916
- ),
42917
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: import_chalk10.default.dim("\u2500".repeat(Math.min(60, termCols - 4))) }),
42918
- searchMode ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42919
- " ",
42920
- import_chalk10.default.bold.cyan("/"),
42921
- " ",
42922
- searchQuery,
42923
- import_chalk10.default.cyan("\u2588"),
42924
- " ",
42925
- import_chalk10.default.dim("Esc clear")
42926
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42927
- " ",
42928
- groups.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
42929
- import_chalk10.default.bold.cyan("\u2191\u2193"),
42930
- " ",
42931
- import_chalk10.default.dim("navigate"),
42932
- " ",
42933
- import_chalk10.default.bold.cyan("\u23CE"),
42934
- " ",
42935
- import_chalk10.default.dim("toggle"),
42936
- " ",
42937
- import_chalk10.default.bold.cyan("space"),
42938
- " ",
42939
- import_chalk10.default.dim("detail"),
42940
- " ",
42941
- import_chalk10.default.bold.cyan("/"),
42942
- " ",
42943
- import_chalk10.default.dim("search"),
42944
- " ",
42945
- import_chalk10.default.bold.cyan("?"),
42946
- " ",
42947
- import_chalk10.default.dim("help"),
42948
- " ",
42949
- onBack && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
42950
- import_chalk10.default.bold.cyan("b"),
42951
- " ",
42952
- import_chalk10.default.dim("back"),
42953
- " "
42954
- ] }),
42955
- import_chalk10.default.bold.cyan("q"),
42956
- " ",
42957
- import_chalk10.default.dim("quit")
42958
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
42959
- "Press ",
42960
- import_chalk10.default.bold.cyan("q"),
42961
- " or ",
42962
- import_chalk10.default.bold.cyan("Enter"),
42963
- " ",
42964
- import_chalk10.default.dim("to exit")
42965
- ] })
42966
- ] })
42967
- ] });
42968
- };
42969
- T = {
42970
- branch: import_chalk10.default.dim("\u251C\u2500\u2500"),
42971
- last: import_chalk10.default.dim("\u2514\u2500\u2500"),
42972
- pipe: import_chalk10.default.dim("\u2502"),
42973
- blank: " "
42974
- };
42975
- LICENSE_DESCRIPTIONS = {
42976
- "permissive": "Permissive \u2014 free to use, modify, and distribute. Include the copyright notice.",
42977
- "weak-copyleft": "Weak copyleft \u2014 changes to this library must be shared, but your code stays private.",
42978
- "strong-copyleft": "Strong copyleft \u2014 your entire project must be open-sourced under the same license.",
42979
- "network-copyleft": "Network copyleft \u2014 even SaaS/server use requires releasing your source code.",
42980
- "no-license": "No license found \u2014 legally all rights reserved. Use may require permission from the author.",
42981
- "unlicensed": "Explicitly unlicensed \u2014 proprietary software. A commercial agreement is required.",
42982
- "unknown": "Unrecognized license \u2014 have your legal team review before using.",
42983
- "deferred": "License declared in a file \u2014 check the LICENSE file in the package."
42984
- };
42985
- FindingsSummary = ({ group, maxWidth, maxLines }) => {
42986
- const rep = group.packages[0];
42987
- const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
42988
- const hasAffects = group.packages.length > 3;
42989
- const allLines = [];
42990
- const lcLine = licenseLine(rep);
42991
- if (lcLine) allLines.push(lcLine);
42992
- if (visibleFindings.length === 0 && rep.score > 0) {
42993
- const reasons = rep.reasons ?? [];
42994
- for (let i = 0; i < reasons.length; i++) {
42995
- allLines.push(
42996
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42997
- i < reasons.length - 1 || hasAffects ? T.branch : T.branch,
42998
- " ",
42999
- truncate3(reasons[i], maxWidth - 8)
43000
- ] }, `reason-${i}`)
43001
- );
43002
- }
43003
- allLines.push(
43004
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
43005
- import_chalk10.default.yellow(" \u2192"),
43006
- " ",
43007
- import_chalk10.default.yellow("Upgrade to Pro"),
43008
- " to see finding details ",
43009
- import_chalk10.default.dim("\u2014 dg login")
43010
- ] }, "upgrade")
43011
- );
43012
- }
43013
- for (let idx = 0; idx < visibleFindings.length; idx++) {
43014
- const f = visibleFindings[idx];
43015
- const isLast = !hasAffects && idx === visibleFindings.length - 1;
43016
- const connector = isLast ? T.last : T.branch;
43017
- const sevLabel = SEVERITY_LABELS2[f.severity] ?? "INFO";
43018
- const sevColor = SEVERITY_COLORS[f.severity] ?? SEVERITY_COLORS[1];
43019
- allLines.push(
43020
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
43021
- connector,
43022
- " ",
43023
- sevColor(pad3(sevLabel, 5)),
43024
- " ",
43025
- import_chalk10.default.dim(f.id ?? f.category ?? "")
43026
- ] }, `${f.id ?? f.category}-${idx}`)
43027
- );
43028
- }
43029
- if (hasAffects) {
43030
- allLines.push(
43031
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
43032
- T.last,
43033
- " ",
43034
- truncate3(affectsLine(group), maxWidth - 8)
43035
- ] }, "affects")
43036
- );
43037
- }
43038
- const linesToShow = maxLines !== void 0 ? allLines.slice(0, maxLines) : allLines;
43039
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Box_default, { flexDirection: "column", marginLeft: 5, children: linesToShow });
43040
- };
43041
- }
43042
- });
43043
-
43044
- // src/ui/components/ProjectSelector.tsx
43045
- var import_react34, import_chalk11, import_jsx_runtime12, ProjectSelector;
43046
- var init_ProjectSelector = __esm({
43047
- async "src/ui/components/ProjectSelector.tsx"() {
43048
- "use strict";
43049
- import_react34 = __toESM(require_react());
43050
- await init_build2();
43051
- import_chalk11 = __toESM(require_source());
43052
- init_sanitize();
43053
- import_jsx_runtime12 = __toESM(require_jsx_runtime());
43054
- ProjectSelector = ({ projects, onConfirm, onCancel }) => {
43055
- const [cursor, setCursor] = (0, import_react34.useState)(0);
43056
- const [selected, setSelected] = (0, import_react34.useState)(() => new Set(projects.map((_, i) => i)));
43057
- use_input_default((input, key) => {
43058
- if (key.upArrow) {
43059
- setCursor((c) => Math.max(0, c - 1));
43060
- } else if (key.downArrow) {
43061
- setCursor((c) => Math.min(projects.length - 1, c + 1));
43062
- } else if (input === " ") {
43063
- setSelected((prev) => {
43064
- const next = new Set(prev);
43065
- if (next.has(cursor)) next.delete(cursor);
43066
- else next.add(cursor);
43067
- return next;
43068
- });
43069
- } else if (input === "a") {
43070
- setSelected((prev) => {
43071
- if (prev.size === projects.length) return /* @__PURE__ */ new Set();
43072
- return new Set(projects.map((_, i) => i));
43073
- });
43074
- } else if (key.return) {
43075
- const picked = projects.filter((_, i) => selected.has(i));
43076
- if (picked.length > 0) onConfirm(picked);
43077
- } else if (input === "q") {
43078
- onCancel();
43079
- }
43080
- });
43081
- const ecosystemLabel = (eco) => eco === "npm" ? import_chalk11.default.magenta("npm") : import_chalk11.default.blue("pip");
43082
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, children: [
43083
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { children: [
43084
- import_chalk11.default.cyan("\u25C6"),
43085
- " ",
43086
- import_chalk11.default.bold("Dependency Guardian")
43087
- ] }),
43088
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { children: "" }),
43089
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { bold: true, children: [
43090
- "Found ",
43091
- projects.length,
43092
- " project",
43093
- projects.length !== 1 ? "s" : ""
43094
- ] }),
43095
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { children: "" }),
43096
- projects.map((proj, i) => {
43097
- const isCursor = i === cursor;
43098
- const isSelected = selected.has(i);
43099
- const prefix = isCursor ? import_chalk11.default.cyan("\u258C") : " ";
43100
- const check = isSelected ? import_chalk11.default.green("\u25C9") : import_chalk11.default.dim("\u25CB");
43101
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { children: [
43102
- prefix,
43103
- check,
43104
- " ",
43105
- sanitize(proj.relativePath).padEnd(40),
43106
- " ",
43107
- ecosystemLabel(proj.ecosystem).padEnd(5),
43108
- " ",
43109
- proj.packageCount,
43110
- " packages"
43111
- ] }, i);
43112
- }),
43113
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { children: "" }),
43114
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { dimColor: true, children: selected.size === 0 ? import_chalk11.default.yellow("Select at least 1 project to scan") : `${selected.size} of ${projects.length} selected` }),
43115
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { children: "" }),
43116
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { children: [
43117
- import_chalk11.default.bold.cyan("space"),
43118
- " ",
43119
- import_chalk11.default.dim("toggle"),
43120
- " ",
43121
- import_chalk11.default.bold.cyan("a"),
43122
- " ",
43123
- import_chalk11.default.dim("all"),
43124
- " ",
43125
- import_chalk11.default.bold.hex("#FFD700")("\u23CE"),
43126
- " ",
43127
- import_chalk11.default.bold.hex("#FFD700")("scan"),
43128
- " ",
43129
- import_chalk11.default.bold.cyan("q"),
43130
- " ",
43131
- import_chalk11.default.dim("quit")
43132
- ] })
43133
- ] });
43134
- };
43135
- }
43136
- });
43137
-
43138
- // src/ui/App.tsx
43139
- var App_exports = {};
43140
- __export(App_exports, {
43141
- App: () => App2
43142
- });
43143
- var import_react35, import_jsx_runtime13, App2;
43144
- var init_App2 = __esm({
43145
- async "src/ui/App.tsx"() {
43146
- "use strict";
43147
- import_react35 = __toESM(require_react());
43148
- await init_build2();
43149
- init_useScan();
43150
- await init_Spinner();
43151
- await init_ProgressBar();
43152
- await init_InteractiveResultsView();
43153
- await init_ErrorView();
43154
- await init_ProjectSelector();
43155
- await init_useTerminalSize();
43156
- import_jsx_runtime13 = __toESM(require_jsx_runtime());
43157
- App2 = ({ config }) => {
43158
- const { state, scanSelectedProjects, restartSelection } = useScan(config);
43159
- const { exit } = use_app_default();
43160
- useTerminalSize();
43161
- const prevPhaseRef = (0, import_react35.useRef)(state.phase);
43162
- const altScreenActiveRef = (0, import_react35.useRef)(false);
43163
- (0, import_react35.useEffect)(() => {
43164
- if (!process.stdout.isTTY) return;
43165
- process.stdout.write("\x1B[?1049h");
43166
- process.stdout.write("\x1B[2J\x1B[H");
43167
- process.stdout.write("\x1B[?1003l");
43168
- process.stdout.write("\x1B[?1000l");
43169
- altScreenActiveRef.current = true;
43170
- return () => {
43171
- if (altScreenActiveRef.current) {
43172
- process.stdout.write("\x1B[?1049l");
43173
- altScreenActiveRef.current = false;
43174
- }
43175
- process.stdout.write("\x1B[?25h");
43176
- };
43177
- }, []);
43178
- (0, import_react35.useEffect)(() => {
43179
- if (prevPhaseRef.current !== state.phase && process.stdout.isTTY) {
43180
- process.stdout.write("\x1B[2J\x1B[H");
43181
- }
43182
- prevPhaseRef.current = state.phase;
43183
- }, [state.phase]);
43184
- const leaveAltScreen = (0, import_react35.useCallback)(() => {
43185
- if (altScreenActiveRef.current && process.stdout.isTTY) {
43186
- process.stdout.write("\x1B[?1049l");
43187
- altScreenActiveRef.current = false;
43188
- }
43189
- process.stdout.write("\x1B[?25h");
43190
- }, []);
43191
- const handleResultsExit = (0, import_react35.useCallback)(() => {
43192
- if (state.phase === "results") {
43193
- const { result } = state;
43194
- if (result.action === "block" && config.mode === "block") {
43195
- process.exitCode = 2;
43196
- } else if (result.action === "block" || result.action === "warn") {
43197
- process.exitCode = 1;
43198
- } else {
43199
- process.exitCode = 0;
43200
- }
43201
- }
43202
- leaveAltScreen();
43203
- exit();
43204
- }, [state, config, exit, leaveAltScreen]);
43205
- const exitWithMessage = (0, import_react35.useCallback)((message, exitCode) => {
43206
- process.exitCode = exitCode;
43207
- leaveAltScreen();
43208
- process.stderr.write(message);
43209
- return setTimeout(() => exit(), 0);
43210
- }, [exit, leaveAltScreen]);
43211
- (0, import_react35.useEffect)(() => {
43212
- if (state.phase === "empty") {
43213
- const timer = exitWithMessage(`${state.message}
43214
- `, 0);
43215
- return () => clearTimeout(timer);
43216
- }
43217
- if (state.phase === "error") {
43218
- const timer = exitWithMessage(`Error: ${state.error.message}
43219
- `, 3);
43220
- return () => clearTimeout(timer);
43221
- }
43222
- if (state.phase === "trial_exhausted") {
43223
- let msg = "Free trial scans used up. Run `dg login` to create a free account and continue scanning.\n";
43224
- try {
43225
- const { getStoredApiKey: getStoredApiKey2 } = (init_auth(), __toCommonJS(auth_exports));
43226
- if (getStoredApiKey2()) {
43227
- msg = "Your API key may be invalid or expired. Run `dg logout` then `dg login` to re-authenticate.\n";
43228
- }
43229
- } catch {
43230
- }
43231
- const timer = exitWithMessage(msg, 1);
43232
- return () => clearTimeout(timer);
43233
- }
43234
- }, [state, exitWithMessage]);
43235
- use_input_default((input, key) => {
43236
- if (state.phase === "discovering" || state.phase === "scanning") {
43237
- if (input === "q" || key.escape) {
43238
- process.exitCode = 0;
43239
- leaveAltScreen();
43240
- exit();
43241
- }
43242
- }
43243
- });
43244
- const content = (() => {
43245
- switch (state.phase) {
43246
- case "discovering":
43247
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Spinner2, { label: `Searching for dependencies in ${process.cwd()} ...` });
43248
- case "selecting":
43249
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
43250
- ProjectSelector,
43251
- {
43252
- projects: state.projects,
43253
- onConfirm: scanSelectedProjects,
43254
- onCancel: () => {
43255
- process.exitCode = 0;
43256
- leaveAltScreen();
43257
- exit();
43258
- }
43259
- }
43260
- );
43261
- case "scanning":
43262
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
43263
- ProgressBar,
43264
- {
43265
- value: state.done,
43266
- total: state.total,
43267
- label: state.currentBatch.length > 0 ? state.currentBatch[state.currentBatch.length - 1] : void 0
43268
- }
43269
- );
43270
- case "results":
43271
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
43272
- InteractiveResultsView,
43273
- {
43274
- result: state.result,
43275
- config,
43276
- durationMs: state.durationMs,
43277
- onExit: handleResultsExit,
43278
- onBack: restartSelection ?? void 0,
43279
- discoveredTotal: state.discoveredTotal
43280
- }
43281
- );
43282
- case "empty":
43283
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: state.message });
43284
- case "error":
43285
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorView, { error: state.error });
43286
- case "trial_exhausted": {
43287
- let hasKey = false;
43288
- try {
43289
- const { getStoredApiKey: getStoredApiKey2 } = (init_auth(), __toCommonJS(auth_exports));
43290
- hasKey = !!getStoredApiKey2();
43291
- } catch {
43292
- }
43293
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexDirection: "column", paddingLeft: 2, children: hasKey ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
43294
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "yellow", bold: true, children: "Your API key may be invalid or expired." }),
43295
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { children: [
43296
- "Run ",
43297
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
43298
- " then ",
43299
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
43300
- " to re-authenticate."
43301
- ] })
43302
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
43303
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
43304
- /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { children: [
43305
- "Run ",
43306
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
43307
- " to create a free account and continue scanning."
43308
- ] })
43309
- ] }) });
43310
- }
43311
- }
43312
- })();
43313
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexDirection: "column", children: content });
43314
- };
43315
- }
43316
- });
43317
-
43318
42226
  // src/bin.ts
43319
42227
  init_config();
43320
42228
  init_npm_wrapper();
@@ -43405,33 +42313,33 @@ async function checkForUpdate(currentVersion) {
43405
42313
  return null;
43406
42314
  }
43407
42315
  async function runUpdate(currentVersion) {
43408
- const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43409
- process.stderr.write(chalk10.dim(" Checking for updates...\n"));
42316
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42317
+ process.stderr.write(chalk8.dim(" Checking for updates...\n"));
43410
42318
  const latest = await fetchLatestVersion();
43411
42319
  if (!latest) {
43412
- process.stderr.write(chalk10.red(" Could not reach npm registry.\n"));
42320
+ process.stderr.write(chalk8.red(" Could not reach npm registry.\n"));
43413
42321
  process.exit(1);
43414
42322
  }
43415
42323
  if (!isNewer(latest, currentVersion)) {
43416
42324
  process.stderr.write(
43417
- chalk10.green(` Already on latest version (${currentVersion}).
42325
+ chalk8.green(` Already on latest version (${currentVersion}).
43418
42326
  `)
43419
42327
  );
43420
42328
  return;
43421
42329
  }
43422
- process.stderr.write(chalk10.dim(` Installing ${PKG_NAME}@${latest}...
42330
+ process.stderr.write(chalk8.dim(` Installing ${PKG_NAME}@${latest}...
43423
42331
  `));
43424
42332
  try {
43425
42333
  execFileSync("npm", ["install", "-g", `${PKG_NAME}@${latest}`], { stdio: "inherit" });
43426
42334
  writeCache({ latest, checkedAt: Date.now() });
43427
42335
  process.stderr.write(
43428
- chalk10.green(`
42336
+ chalk8.green(`
43429
42337
  Updated ${currentVersion} \u2192 ${latest}
43430
42338
  `)
43431
42339
  );
43432
42340
  } catch {
43433
42341
  process.stderr.write(
43434
- chalk10.red(`
42342
+ chalk8.red(`
43435
42343
  Update failed. Try manually: npm i -g ${PKG_NAME}@${latest}
43436
42344
  `)
43437
42345
  );
@@ -43482,9 +42390,9 @@ async function main() {
43482
42390
  if (rawCommand === "login") {
43483
42391
  if (isInteractive) {
43484
42392
  const { render: render3 } = await init_build2().then(() => build_exports);
43485
- const React19 = await Promise.resolve().then(() => __toESM(require_react()));
42393
+ const React16 = await Promise.resolve().then(() => __toESM(require_react()));
43486
42394
  const { LoginApp: LoginApp2 } = await init_LoginApp().then(() => LoginApp_exports);
43487
- const { waitUntilExit } = render3(React19.createElement(LoginApp2));
42395
+ const { waitUntilExit } = render3(React16.createElement(LoginApp2));
43488
42396
  await waitUntilExit();
43489
42397
  } else {
43490
42398
  const { runStaticLogin: runStaticLogin2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
@@ -43492,6 +42400,19 @@ async function main() {
43492
42400
  }
43493
42401
  return;
43494
42402
  }
42403
+ if (rawCommand === "status") {
42404
+ const { getStoredApiKey: getStoredApiKey2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
42405
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42406
+ const apiKey = getStoredApiKey2();
42407
+ if (apiKey) {
42408
+ process.stderr.write(chalk8.green(` Authenticated`) + chalk8.dim(` (key: ${apiKey.slice(0, 12)}...)
42409
+ `));
42410
+ } else {
42411
+ process.stderr.write(chalk8.yellow(` Not authenticated.`) + chalk8.dim(` Run \`dg login\` to sign in.
42412
+ `));
42413
+ }
42414
+ return;
42415
+ }
43495
42416
  if (rawCommand === "hook") {
43496
42417
  const { handleHookCommand: handleHookCommand2 } = await Promise.resolve().then(() => (init_hook(), hook_exports));
43497
42418
  handleHookCommand2(process.argv.slice(3));
@@ -43502,21 +42423,32 @@ async function main() {
43502
42423
  return;
43503
42424
  }
43504
42425
  if (rawCommand === "logout") {
43505
- const { clearCredentials: clearCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
42426
+ const { getStoredApiKey: getStoredApiKey2, clearCredentials: clearCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
42427
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42428
+ const apiKey = getStoredApiKey2();
42429
+ if (apiKey) {
42430
+ try {
42431
+ await fetch("https://api.westbayberry.com/v1/auth/revoke", {
42432
+ method: "POST",
42433
+ headers: { Authorization: `Bearer ${apiKey}` },
42434
+ signal: AbortSignal.timeout(5e3)
42435
+ });
42436
+ } catch {
42437
+ }
42438
+ }
43506
42439
  clearCredentials2();
43507
- const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43508
- process.stderr.write(chalk10.green(" Logged out.\n"));
42440
+ process.stderr.write(chalk8.green(" Logged out.\n"));
43509
42441
  return;
43510
42442
  }
43511
- const KNOWN_COMMANDS = ["scan", "npm", "pip", "wrap", "login", "hook", "update", "logout"];
42443
+ const KNOWN_COMMANDS = ["scan", "npm", "pip", "wrap", "login", "logout", "status", "hook", "update"];
43512
42444
  if (rawCommand && !rawCommand.startsWith("-") && !KNOWN_COMMANDS.includes(rawCommand)) {
43513
- const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42445
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43514
42446
  const best = closestCommand(rawCommand, KNOWN_COMMANDS);
43515
42447
  const hint = best ? ` Did you mean '${best}'?` : "";
43516
42448
  process.stderr.write(`
43517
- ${chalk10.bold.red("Error:")} Unknown command '${rawCommand}'.${hint}
42449
+ ${chalk8.bold.red("Error:")} Unknown command '${rawCommand}'.${hint}
43518
42450
  `);
43519
- process.stderr.write(chalk10.dim(` Run 'dg --help' for available commands.
42451
+ process.stderr.write(chalk8.dim(` Run 'dg --help' for available commands.
43520
42452
 
43521
42453
  `));
43522
42454
  process.exit(1);
@@ -43524,54 +42456,50 @@ async function main() {
43524
42456
  const strictFlags = rawCommand !== "npm" && rawCommand !== "pip";
43525
42457
  const config = parseConfig(process.argv, strictFlags);
43526
42458
  const updatePromise = checkForUpdate(CLI_VERSION).catch(() => null);
42459
+ if (rawCommand !== "npm" && rawCommand !== "pip") {
42460
+ const { runStatic: runStatic2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
42461
+ await runStatic2(config);
42462
+ const updateMsg2 = await updatePromise;
42463
+ if (updateMsg2) {
42464
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42465
+ process.stderr.write(chalk8.dim(updateMsg2));
42466
+ }
42467
+ return;
42468
+ }
43527
42469
  if (config.json || !isInteractive) {
43528
42470
  if (rawCommand === "npm") {
43529
42471
  const { runStaticNpm: runStaticNpm2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
43530
42472
  await runStaticNpm2(process.argv.slice(3), config);
43531
- } else if (rawCommand === "pip") {
42473
+ } else {
43532
42474
  const { runStaticPip: runStaticPip2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
43533
42475
  await runStaticPip2(process.argv.slice(3), config);
43534
- } else {
43535
- const { runStatic: runStatic2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
43536
- await runStatic2(config);
43537
42476
  }
43538
42477
  const updateMsg2 = await updatePromise;
43539
42478
  if (updateMsg2) {
43540
- const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43541
- process.stderr.write(chalk10.dim(updateMsg2));
42479
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42480
+ process.stderr.write(chalk8.dim(updateMsg2));
43542
42481
  }
43543
42482
  return;
43544
42483
  }
43545
42484
  const { render: render2 } = await init_build2().then(() => build_exports);
43546
- const React18 = await Promise.resolve().then(() => __toESM(require_react()));
42485
+ const React15 = await Promise.resolve().then(() => __toESM(require_react()));
43547
42486
  if (rawCommand === "npm") {
43548
42487
  const { NpmWrapperApp: NpmWrapperApp2 } = await init_NpmWrapperApp().then(() => NpmWrapperApp_exports);
43549
42488
  const { waitUntilExit } = render2(
43550
- React18.createElement(NpmWrapperApp2, { config, npmArgs: process.argv.slice(3) })
43551
- );
43552
- await waitUntilExit();
43553
- } else if (rawCommand === "pip") {
43554
- const { PipWrapperApp: PipWrapperApp2 } = await init_PipWrapperApp().then(() => PipWrapperApp_exports);
43555
- const { waitUntilExit } = render2(
43556
- React18.createElement(PipWrapperApp2, { config, pipArgs: process.argv.slice(3) })
42489
+ React15.createElement(NpmWrapperApp2, { config, npmArgs: process.argv.slice(3) })
43557
42490
  );
43558
42491
  await waitUntilExit();
43559
42492
  } else {
43560
- if (config.mode === "off") {
43561
- const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43562
- process.stderr.write(chalk10.dim(" Dependency Guardian: mode is off \u2014 skipping.\n"));
43563
- process.exit(0);
43564
- }
43565
- const { App: App3 } = await init_App2().then(() => App_exports);
42493
+ const { PipWrapperApp: PipWrapperApp2 } = await init_PipWrapperApp().then(() => PipWrapperApp_exports);
43566
42494
  const { waitUntilExit } = render2(
43567
- React18.createElement(App3, { config })
42495
+ React15.createElement(PipWrapperApp2, { config, pipArgs: process.argv.slice(3) })
43568
42496
  );
43569
42497
  await waitUntilExit();
43570
42498
  }
43571
42499
  const updateMsg = await updatePromise;
43572
42500
  if (updateMsg) {
43573
- const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43574
- process.stderr.write(chalk10.dim(updateMsg));
42501
+ const chalk8 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
42502
+ process.stderr.write(chalk8.dim(updateMsg));
43575
42503
  }
43576
42504
  }
43577
42505
  main().catch((err) => {
@@ -43583,9 +42511,9 @@ main().catch((err) => {
43583
42511
  }, null, 2) + "\n");
43584
42512
  } else {
43585
42513
  try {
43586
- const chalk10 = require_source();
42514
+ const chalk8 = require_source();
43587
42515
  process.stderr.write(`
43588
- ${chalk10.bold.red("Error:")} ${err.message}
42516
+ ${chalk8.bold.red("Error:")} ${err.message}
43589
42517
 
43590
42518
  `);
43591
42519
  } catch {