@westbayberry/dg 1.0.34 → 1.0.35

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 (3) hide show
  1. package/README.md +2 -9
  2. package/dist/index.mjs +1141 -528
  3. package/package.json +3 -2
package/dist/index.mjs CHANGED
@@ -38,6 +38,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
38
38
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
39
39
  mod
40
40
  ));
41
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
41
42
 
42
43
  // src/auth.ts
43
44
  var auth_exports = {};
@@ -249,28 +250,46 @@ function getVersion() {
249
250
  return "1.0.0";
250
251
  }
251
252
  }
252
- function parseConfig(argv) {
253
- const { values, positionals } = parseArgs({
254
- args: argv.slice(2),
255
- options: {
256
- "api-url": { type: "string" },
257
- mode: { type: "string" },
258
- "block-threshold": { type: "string" },
259
- "warn-threshold": { type: "string" },
260
- "max-packages": { type: "string" },
261
- allowlist: { type: "string" },
262
- json: { type: "boolean", default: false },
263
- "scan-all": { type: "boolean", default: false },
264
- "base-lockfile": { type: "string" },
265
- workspace: { type: "string", short: "w" },
266
- debug: { type: "boolean", default: false },
267
- "no-config": { type: "boolean", default: false },
268
- help: { type: "boolean", default: false },
269
- version: { type: "boolean", default: false }
270
- },
271
- allowPositionals: true,
272
- strict: false
273
- });
253
+ function parseConfig(argv, strictFlags = true) {
254
+ let values;
255
+ let positionals;
256
+ try {
257
+ const parsed = parseArgs({
258
+ args: argv.slice(2),
259
+ options: {
260
+ "api-url": { type: "string" },
261
+ mode: { type: "string" },
262
+ "max-packages": { type: "string" },
263
+ json: { type: "boolean", default: false },
264
+ "scan-all": { type: "boolean", default: false },
265
+ "base-lockfile": { type: "string" },
266
+ workspace: { type: "string", short: "w" },
267
+ debug: { type: "boolean", default: false },
268
+ help: { type: "boolean", default: false },
269
+ version: { type: "boolean", default: false },
270
+ // Recognized but handled server-side via policy dashboard
271
+ "no-config": { type: "boolean", default: false },
272
+ allowlist: { type: "string" },
273
+ "block-threshold": { type: "string" },
274
+ "warn-threshold": { type: "string" }
275
+ },
276
+ allowPositionals: true,
277
+ strict: strictFlags
278
+ });
279
+ values = parsed.values;
280
+ positionals = parsed.positionals;
281
+ } catch (err) {
282
+ const raw = err instanceof Error ? err.message : String(err);
283
+ const match = raw.match(/Unknown option '([^']+)'/);
284
+ const msg = match ? `Unknown option '${match[1]}'.` : raw;
285
+ process.stderr.write(`
286
+ Error: ${msg}
287
+ `);
288
+ process.stderr.write(` Run 'dg --help' for available options.
289
+
290
+ `);
291
+ process.exit(1);
292
+ }
274
293
  if (values.help) {
275
294
  process.stdout.write(USAGE);
276
295
  process.exit(0);
@@ -281,8 +300,7 @@ function parseConfig(argv) {
281
300
  process.exit(0);
282
301
  }
283
302
  const command = positionals[0] ?? "scan";
284
- const noConfig = values["no-config"];
285
- const dgrc = noConfig ? {} : loadDgrc();
303
+ const dgrc = loadDgrc();
286
304
  const apiKey = dgrc.apiKey && typeof dgrc.apiKey === "string" && dgrc.apiKey.startsWith("dg_live_") ? dgrc.apiKey : null;
287
305
  const deviceId = getOrCreateDeviceId();
288
306
  const modeRaw = values.mode ?? process.env.DG_MODE ?? dgrc.mode ?? "warn";
@@ -293,19 +311,8 @@ function parseConfig(argv) {
293
311
  );
294
312
  process.exit(1);
295
313
  }
296
- const allowlistRaw = values.allowlist ?? process.env.DG_ALLOWLIST ?? "";
297
- const blockThreshold = Number(values["block-threshold"] ?? dgrc.blockThreshold ?? "70");
298
- const warnThreshold = Number(values["warn-threshold"] ?? dgrc.warnThreshold ?? "60");
299
314
  const maxPackages = Number(values["max-packages"] ?? dgrc.maxPackages ?? "200");
300
315
  const debug = values.debug || process.env.DG_DEBUG === "1";
301
- if (isNaN(blockThreshold) || blockThreshold < 0 || blockThreshold > 100) {
302
- process.stderr.write("Error: --block-threshold must be a number between 0 and 100\n");
303
- process.exit(1);
304
- }
305
- if (isNaN(warnThreshold) || warnThreshold < 0 || warnThreshold > 100) {
306
- process.stderr.write("Error: --warn-threshold must be a number between 0 and 100\n");
307
- process.exit(1);
308
- }
309
316
  if (isNaN(maxPackages) || maxPackages < 1 || maxPackages > 1e4) {
310
317
  process.stderr.write("Error: --max-packages must be a number between 1 and 10000\n");
311
318
  process.exit(1);
@@ -317,10 +324,7 @@ function parseConfig(argv) {
317
324
  values["api-url"] ?? process.env.DG_API_URL ?? dgrc.apiUrl ?? "https://api.westbayberry.com"
318
325
  ),
319
326
  mode: modeRaw,
320
- blockThreshold,
321
- warnThreshold,
322
327
  maxPackages,
323
- allowlist: (allowlistRaw ? allowlistRaw.split(",").map((s) => s.trim()).filter(Boolean) : dgrc.allowlist ?? []).map((s) => s.toLowerCase()),
324
328
  json: values.json,
325
329
  scanAll: values["scan-all"],
326
330
  baseLockfile: values["base-lockfile"] ?? null,
@@ -341,11 +345,13 @@ var init_config = __esm({
341
345
  dependency-guardian scan [options]
342
346
  dg scan [options]
343
347
  dg npm install <pkg> [npm-flags]
348
+ dg pip install <pkg> [pip-flags]
344
349
  dg wrap
345
350
 
346
351
  Commands:
347
352
  scan Scan dependencies (auto-discovers npm + Python projects)
348
353
  npm Wrap npm commands \u2014 scans packages before installing
354
+ pip Wrap pip commands \u2014 scans packages before installing
349
355
  hook install Install git pre-commit hook to scan lockfile changes
350
356
  hook uninstall Remove the pre-commit hook
351
357
  update Check for and install the latest version
@@ -356,16 +362,12 @@ var init_config = __esm({
356
362
  Options:
357
363
  --api-url <url> API base URL (default: https://api.westbayberry.com)
358
364
  --mode <mode> block | warn | off (default: warn)
359
- --block-threshold <n> Score threshold for blocking (default: 70)
360
- --warn-threshold <n> Score threshold for warnings (default: 60)
361
365
  --max-packages <n> Max packages per scan (default: 200)
362
- --allowlist <pkgs> Comma-separated package names to skip
363
366
  --json Output JSON for CI parsing
364
367
  --scan-all Scan all packages, not just changed
365
368
  --base-lockfile <path> Path to base lockfile for explicit diff
366
369
  --workspace <dir> Scan a specific workspace subdirectory
367
370
  --debug Show diagnostic output (discovery, batches, timing)
368
- --no-config Skip loading .dgrc.json config file
369
371
  --help Show this help message
370
372
  --version Show version number
371
373
 
@@ -376,7 +378,6 @@ var init_config = __esm({
376
378
  Environment Variables:
377
379
  DG_API_URL API base URL
378
380
  DG_MODE Mode (block/warn/off)
379
- DG_ALLOWLIST Comma-separated allowlist
380
381
  DG_DEBUG Enable debug output (set to 1)
381
382
  DG_WORKSPACE Workspace subdirectory to scan
382
383
 
@@ -3469,15 +3470,15 @@ var require_react_development = __commonJS({
3469
3470
  var dispatcher = resolveDispatcher();
3470
3471
  return dispatcher.useState(initialState);
3471
3472
  }
3472
- function useReducer5(reducer4, initialArg, init) {
3473
+ function useReducer6(reducer5, initialArg, init) {
3473
3474
  var dispatcher = resolveDispatcher();
3474
- return dispatcher.useReducer(reducer4, initialArg, init);
3475
+ return dispatcher.useReducer(reducer5, initialArg, init);
3475
3476
  }
3476
- function useRef8(initialValue) {
3477
+ function useRef9(initialValue) {
3477
3478
  var dispatcher = resolveDispatcher();
3478
3479
  return dispatcher.useRef(initialValue);
3479
3480
  }
3480
- function useEffect14(create2, deps) {
3481
+ function useEffect16(create2, deps) {
3481
3482
  var dispatcher = resolveDispatcher();
3482
3483
  return dispatcher.useEffect(create2, deps);
3483
3484
  }
@@ -3489,7 +3490,7 @@ var require_react_development = __commonJS({
3489
3490
  var dispatcher = resolveDispatcher();
3490
3491
  return dispatcher.useLayoutEffect(create2, deps);
3491
3492
  }
3492
- function useCallback5(callback, deps) {
3493
+ function useCallback6(callback, deps) {
3493
3494
  var dispatcher = resolveDispatcher();
3494
3495
  return dispatcher.useCallback(callback, deps);
3495
3496
  }
@@ -4256,18 +4257,18 @@ var require_react_development = __commonJS({
4256
4257
  exports.memo = memo;
4257
4258
  exports.startTransition = startTransition;
4258
4259
  exports.unstable_act = act;
4259
- exports.useCallback = useCallback5;
4260
+ exports.useCallback = useCallback6;
4260
4261
  exports.useContext = useContext7;
4261
4262
  exports.useDebugValue = useDebugValue;
4262
4263
  exports.useDeferredValue = useDeferredValue;
4263
- exports.useEffect = useEffect14;
4264
+ exports.useEffect = useEffect16;
4264
4265
  exports.useId = useId;
4265
4266
  exports.useImperativeHandle = useImperativeHandle;
4266
4267
  exports.useInsertionEffect = useInsertionEffect;
4267
4268
  exports.useLayoutEffect = useLayoutEffect2;
4268
4269
  exports.useMemo = useMemo4;
4269
- exports.useReducer = useReducer5;
4270
- exports.useRef = useRef8;
4270
+ exports.useReducer = useReducer6;
4271
+ exports.useRef = useRef9;
4271
4272
  exports.useState = useState9;
4272
4273
  exports.useSyncExternalStore = useSyncExternalStore;
4273
4274
  exports.useTransition = useTransition;
@@ -11978,9 +11979,9 @@ var require_react_reconciler_development = __commonJS({
11978
11979
  module.exports = function $$$reconciler($$$hostConfig) {
11979
11980
  var exports2 = {};
11980
11981
  "use strict";
11981
- var React17 = require_react();
11982
+ var React18 = require_react();
11982
11983
  var Scheduler = require_scheduler();
11983
- var ReactSharedInternals = React17.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
11984
+ var ReactSharedInternals = React18.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
11984
11985
  var suppressWarning = false;
11985
11986
  function setSuppressWarning(newSuppressWarning) {
11986
11987
  {
@@ -12044,7 +12045,7 @@ var require_react_reconciler_development = __commonJS({
12044
12045
  var HostPortal = 4;
12045
12046
  var HostComponent = 5;
12046
12047
  var HostText = 6;
12047
- var Fragment4 = 7;
12048
+ var Fragment7 = 7;
12048
12049
  var Mode = 8;
12049
12050
  var ContextConsumer = 9;
12050
12051
  var ContextProvider = 10;
@@ -12184,7 +12185,7 @@ var require_react_reconciler_development = __commonJS({
12184
12185
  return "DehydratedFragment";
12185
12186
  case ForwardRef:
12186
12187
  return getWrappedName$1(type, type.render, "ForwardRef");
12187
- case Fragment4:
12188
+ case Fragment7:
12188
12189
  return "Fragment";
12189
12190
  case HostComponent:
12190
12191
  return type;
@@ -15318,7 +15319,7 @@ var require_react_reconciler_development = __commonJS({
15318
15319
  }
15319
15320
  }
15320
15321
  function updateFragment2(returnFiber, current2, fragment, lanes, key) {
15321
- if (current2 === null || current2.tag !== Fragment4) {
15322
+ if (current2 === null || current2.tag !== Fragment7) {
15322
15323
  var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);
15323
15324
  created.return = returnFiber;
15324
15325
  return created;
@@ -15721,7 +15722,7 @@ var require_react_reconciler_development = __commonJS({
15721
15722
  if (child.key === key) {
15722
15723
  var elementType = element.type;
15723
15724
  if (elementType === REACT_FRAGMENT_TYPE) {
15724
- if (child.tag === Fragment4) {
15725
+ if (child.tag === Fragment7) {
15725
15726
  deleteRemainingChildren(returnFiber, child.sibling);
15726
15727
  var existing = useFiber(child, element.props.children);
15727
15728
  existing.return = returnFiber;
@@ -16969,7 +16970,7 @@ var require_react_reconciler_development = __commonJS({
16969
16970
  function basicStateReducer(state, action) {
16970
16971
  return typeof action === "function" ? action(state) : action;
16971
16972
  }
16972
- function mountReducer(reducer4, initialArg, init) {
16973
+ function mountReducer(reducer5, initialArg, init) {
16973
16974
  var hook = mountWorkInProgressHook();
16974
16975
  var initialState;
16975
16976
  if (init !== void 0) {
@@ -16983,20 +16984,20 @@ var require_react_reconciler_development = __commonJS({
16983
16984
  interleaved: null,
16984
16985
  lanes: NoLanes,
16985
16986
  dispatch: null,
16986
- lastRenderedReducer: reducer4,
16987
+ lastRenderedReducer: reducer5,
16987
16988
  lastRenderedState: initialState
16988
16989
  };
16989
16990
  hook.queue = queue;
16990
16991
  var dispatch = queue.dispatch = dispatchReducerAction.bind(null, currentlyRenderingFiber$1, queue);
16991
16992
  return [hook.memoizedState, dispatch];
16992
16993
  }
16993
- function updateReducer(reducer4, initialArg, init) {
16994
+ function updateReducer(reducer5, initialArg, init) {
16994
16995
  var hook = updateWorkInProgressHook();
16995
16996
  var queue = hook.queue;
16996
16997
  if (queue === null) {
16997
16998
  throw new Error("Should have a queue. This is likely a bug in React. Please file an issue.");
16998
16999
  }
16999
- queue.lastRenderedReducer = reducer4;
17000
+ queue.lastRenderedReducer = reducer5;
17000
17001
  var current2 = currentHook;
17001
17002
  var baseQueue = current2.baseQueue;
17002
17003
  var pendingQueue = queue.pending;
@@ -17058,7 +17059,7 @@ var require_react_reconciler_development = __commonJS({
17058
17059
  newState = update.eagerState;
17059
17060
  } else {
17060
17061
  var action = update.action;
17061
- newState = reducer4(newState, action);
17062
+ newState = reducer5(newState, action);
17062
17063
  }
17063
17064
  }
17064
17065
  update = update.next;
@@ -17091,13 +17092,13 @@ var require_react_reconciler_development = __commonJS({
17091
17092
  var dispatch = queue.dispatch;
17092
17093
  return [hook.memoizedState, dispatch];
17093
17094
  }
17094
- function rerenderReducer(reducer4, initialArg, init) {
17095
+ function rerenderReducer(reducer5, initialArg, init) {
17095
17096
  var hook = updateWorkInProgressHook();
17096
17097
  var queue = hook.queue;
17097
17098
  if (queue === null) {
17098
17099
  throw new Error("Should have a queue. This is likely a bug in React. Please file an issue.");
17099
17100
  }
17100
- queue.lastRenderedReducer = reducer4;
17101
+ queue.lastRenderedReducer = reducer5;
17101
17102
  var dispatch = queue.dispatch;
17102
17103
  var lastRenderPhaseUpdate = queue.pending;
17103
17104
  var newState = hook.memoizedState;
@@ -17107,7 +17108,7 @@ var require_react_reconciler_development = __commonJS({
17107
17108
  var update = firstRenderPhaseUpdate;
17108
17109
  do {
17109
17110
  var action = update.action;
17110
- newState = reducer4(newState, action);
17111
+ newState = reducer5(newState, action);
17111
17112
  update = update.next;
17112
17113
  } while (update !== firstRenderPhaseUpdate);
17113
17114
  if (!objectIs(newState, hook.memoizedState)) {
@@ -17787,13 +17788,13 @@ var require_react_reconciler_development = __commonJS({
17787
17788
  ReactCurrentDispatcher$1.current = prevDispatcher;
17788
17789
  }
17789
17790
  },
17790
- useReducer: function(reducer4, initialArg, init) {
17791
+ useReducer: function(reducer5, initialArg, init) {
17791
17792
  currentHookNameInDev = "useReducer";
17792
17793
  mountHookTypesDev();
17793
17794
  var prevDispatcher = ReactCurrentDispatcher$1.current;
17794
17795
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
17795
17796
  try {
17796
- return mountReducer(reducer4, initialArg, init);
17797
+ return mountReducer(reducer5, initialArg, init);
17797
17798
  } finally {
17798
17799
  ReactCurrentDispatcher$1.current = prevDispatcher;
17799
17800
  }
@@ -17891,13 +17892,13 @@ var require_react_reconciler_development = __commonJS({
17891
17892
  ReactCurrentDispatcher$1.current = prevDispatcher;
17892
17893
  }
17893
17894
  },
17894
- useReducer: function(reducer4, initialArg, init) {
17895
+ useReducer: function(reducer5, initialArg, init) {
17895
17896
  currentHookNameInDev = "useReducer";
17896
17897
  updateHookTypesDev();
17897
17898
  var prevDispatcher = ReactCurrentDispatcher$1.current;
17898
17899
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
17899
17900
  try {
17900
- return mountReducer(reducer4, initialArg, init);
17901
+ return mountReducer(reducer5, initialArg, init);
17901
17902
  } finally {
17902
17903
  ReactCurrentDispatcher$1.current = prevDispatcher;
17903
17904
  }
@@ -17995,13 +17996,13 @@ var require_react_reconciler_development = __commonJS({
17995
17996
  ReactCurrentDispatcher$1.current = prevDispatcher;
17996
17997
  }
17997
17998
  },
17998
- useReducer: function(reducer4, initialArg, init) {
17999
+ useReducer: function(reducer5, initialArg, init) {
17999
18000
  currentHookNameInDev = "useReducer";
18000
18001
  updateHookTypesDev();
18001
18002
  var prevDispatcher = ReactCurrentDispatcher$1.current;
18002
18003
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
18003
18004
  try {
18004
- return updateReducer(reducer4, initialArg, init);
18005
+ return updateReducer(reducer5, initialArg, init);
18005
18006
  } finally {
18006
18007
  ReactCurrentDispatcher$1.current = prevDispatcher;
18007
18008
  }
@@ -18099,13 +18100,13 @@ var require_react_reconciler_development = __commonJS({
18099
18100
  ReactCurrentDispatcher$1.current = prevDispatcher;
18100
18101
  }
18101
18102
  },
18102
- useReducer: function(reducer4, initialArg, init) {
18103
+ useReducer: function(reducer5, initialArg, init) {
18103
18104
  currentHookNameInDev = "useReducer";
18104
18105
  updateHookTypesDev();
18105
18106
  var prevDispatcher = ReactCurrentDispatcher$1.current;
18106
18107
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnRerenderInDEV;
18107
18108
  try {
18108
- return rerenderReducer(reducer4, initialArg, init);
18109
+ return rerenderReducer(reducer5, initialArg, init);
18109
18110
  } finally {
18110
18111
  ReactCurrentDispatcher$1.current = prevDispatcher;
18111
18112
  }
@@ -18211,14 +18212,14 @@ var require_react_reconciler_development = __commonJS({
18211
18212
  ReactCurrentDispatcher$1.current = prevDispatcher;
18212
18213
  }
18213
18214
  },
18214
- useReducer: function(reducer4, initialArg, init) {
18215
+ useReducer: function(reducer5, initialArg, init) {
18215
18216
  currentHookNameInDev = "useReducer";
18216
18217
  warnInvalidHookAccess();
18217
18218
  mountHookTypesDev();
18218
18219
  var prevDispatcher = ReactCurrentDispatcher$1.current;
18219
18220
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnMountInDEV;
18220
18221
  try {
18221
- return mountReducer(reducer4, initialArg, init);
18222
+ return mountReducer(reducer5, initialArg, init);
18222
18223
  } finally {
18223
18224
  ReactCurrentDispatcher$1.current = prevDispatcher;
18224
18225
  }
@@ -18332,14 +18333,14 @@ var require_react_reconciler_development = __commonJS({
18332
18333
  ReactCurrentDispatcher$1.current = prevDispatcher;
18333
18334
  }
18334
18335
  },
18335
- useReducer: function(reducer4, initialArg, init) {
18336
+ useReducer: function(reducer5, initialArg, init) {
18336
18337
  currentHookNameInDev = "useReducer";
18337
18338
  warnInvalidHookAccess();
18338
18339
  updateHookTypesDev();
18339
18340
  var prevDispatcher = ReactCurrentDispatcher$1.current;
18340
18341
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
18341
18342
  try {
18342
- return updateReducer(reducer4, initialArg, init);
18343
+ return updateReducer(reducer5, initialArg, init);
18343
18344
  } finally {
18344
18345
  ReactCurrentDispatcher$1.current = prevDispatcher;
18345
18346
  }
@@ -18453,14 +18454,14 @@ var require_react_reconciler_development = __commonJS({
18453
18454
  ReactCurrentDispatcher$1.current = prevDispatcher;
18454
18455
  }
18455
18456
  },
18456
- useReducer: function(reducer4, initialArg, init) {
18457
+ useReducer: function(reducer5, initialArg, init) {
18457
18458
  currentHookNameInDev = "useReducer";
18458
18459
  warnInvalidHookAccess();
18459
18460
  updateHookTypesDev();
18460
18461
  var prevDispatcher = ReactCurrentDispatcher$1.current;
18461
18462
  ReactCurrentDispatcher$1.current = InvalidNestedHooksDispatcherOnUpdateInDEV;
18462
18463
  try {
18463
- return rerenderReducer(reducer4, initialArg, init);
18464
+ return rerenderReducer(reducer5, initialArg, init);
18464
18465
  } finally {
18465
18466
  ReactCurrentDispatcher$1.current = prevDispatcher;
18466
18467
  }
@@ -21212,7 +21213,7 @@ var require_react_reconciler_development = __commonJS({
21212
21213
  var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
21213
21214
  return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2);
21214
21215
  }
21215
- case Fragment4:
21216
+ case Fragment7:
21216
21217
  return updateFragment(current2, workInProgress2, renderLanes2);
21217
21218
  case Mode:
21218
21219
  return updateMode(current2, workInProgress2, renderLanes2);
@@ -21649,7 +21650,7 @@ var require_react_reconciler_development = __commonJS({
21649
21650
  case SimpleMemoComponent:
21650
21651
  case FunctionComponent:
21651
21652
  case ForwardRef:
21652
- case Fragment4:
21653
+ case Fragment7:
21653
21654
  case Mode:
21654
21655
  case Profiler:
21655
21656
  case ContextConsumer:
@@ -26417,7 +26418,7 @@ var require_react_reconciler_development = __commonJS({
26417
26418
  return fiber;
26418
26419
  }
26419
26420
  function createFiberFromFragment(elements, mode, lanes, key) {
26420
- var fiber = createFiber(Fragment4, elements, key, mode);
26421
+ var fiber = createFiber(Fragment7, elements, key, mode);
26421
26422
  fiber.lanes = lanes;
26422
26423
  return fiber;
26423
26424
  }
@@ -37931,7 +37932,7 @@ var require_react_jsx_runtime_development = __commonJS({
37931
37932
  if (process.env.NODE_ENV !== "production") {
37932
37933
  (function() {
37933
37934
  "use strict";
37934
- var React17 = require_react();
37935
+ var React18 = require_react();
37935
37936
  var REACT_ELEMENT_TYPE = Symbol.for("react.element");
37936
37937
  var REACT_PORTAL_TYPE = Symbol.for("react.portal");
37937
37938
  var REACT_FRAGMENT_TYPE = Symbol.for("react.fragment");
@@ -37957,7 +37958,7 @@ var require_react_jsx_runtime_development = __commonJS({
37957
37958
  }
37958
37959
  return null;
37959
37960
  }
37960
- var ReactSharedInternals = React17.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
37961
+ var ReactSharedInternals = React18.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
37961
37962
  function error(format) {
37962
37963
  {
37963
37964
  {
@@ -38807,11 +38808,11 @@ var require_react_jsx_runtime_development = __commonJS({
38807
38808
  return jsxWithValidation(type, props, key, false);
38808
38809
  }
38809
38810
  }
38810
- var jsx11 = jsxWithValidationDynamic;
38811
- var jsxs13 = jsxWithValidationStatic;
38811
+ var jsx12 = jsxWithValidationDynamic;
38812
+ var jsxs14 = jsxWithValidationStatic;
38812
38813
  exports.Fragment = REACT_FRAGMENT_TYPE;
38813
- exports.jsx = jsx11;
38814
- exports.jsxs = jsxs13;
38814
+ exports.jsx = jsx12;
38815
+ exports.jsxs = jsxs14;
38815
38816
  })();
38816
38817
  }
38817
38818
  }
@@ -39030,7 +39031,7 @@ async function callAnalyzeAPI(packages, config, onProgress) {
39030
39031
  results.push(result);
39031
39032
  }
39032
39033
  if (process.env.DG_PERF) console.error(`[CLI-PERF] total: ${packages.length} packages \u2192 ${Date.now() - tTotal}ms`);
39033
- return mergeResponses(results, config);
39034
+ return mergeResponses(results);
39034
39035
  }
39035
39036
  async function callBatchWithRetry(packages, config) {
39036
39037
  for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
@@ -39053,10 +39054,10 @@ async function callBatchWithRetry(packages, config) {
39053
39054
  }
39054
39055
  throw new Error("Exhausted retries");
39055
39056
  }
39056
- function mergeResponses(results, config) {
39057
+ function mergeResponses(results) {
39057
39058
  const allPackages = results.flatMap((r) => r.packages);
39058
39059
  const maxScore = Math.max(0, ...allPackages.map((p) => p.score));
39059
- const action = maxScore >= config.blockThreshold ? "block" : maxScore >= config.warnThreshold ? "warn" : "pass";
39060
+ const action = maxScore >= 70 ? "block" : maxScore >= 60 ? "warn" : "pass";
39060
39061
  const safeVersions = {};
39061
39062
  for (const r of results) {
39062
39063
  Object.assign(safeVersions, r.safeVersions);
@@ -39077,11 +39078,7 @@ async function callAnalyzeBatch(packages, config) {
39077
39078
  version: p.version,
39078
39079
  previousVersion: p.previousVersion,
39079
39080
  isNew: p.isNew
39080
- })),
39081
- config: {
39082
- blockThreshold: config.blockThreshold,
39083
- warnThreshold: config.warnThreshold
39084
- }
39081
+ }))
39085
39082
  };
39086
39083
  const controller = new AbortController();
39087
39084
  const timeoutId = setTimeout(() => controller.abort(), 18e4);
@@ -39149,7 +39146,7 @@ async function callPyPIAnalyzeAPI(packages, config, onProgress) {
39149
39146
  if (onProgress) onProgress(completed, packages.length);
39150
39147
  results.push(result);
39151
39148
  }
39152
- return mergeResponses(results, config);
39149
+ return mergeResponses(results);
39153
39150
  }
39154
39151
  async function callPyPIBatch(packages, config) {
39155
39152
  const url = `${config.apiUrl}/v1/pypi/analyze`;
@@ -39159,11 +39156,7 @@ async function callPyPIBatch(packages, config) {
39159
39156
  version: p.version,
39160
39157
  previousVersion: p.previousVersion ?? null,
39161
39158
  isNew: p.isNew ?? true
39162
- })),
39163
- config: {
39164
- blockThreshold: config.blockThreshold,
39165
- warnThreshold: config.warnThreshold
39166
- }
39159
+ }))
39167
39160
  };
39168
39161
  const controller = new AbortController();
39169
39162
  const timeoutId = setTimeout(() => controller.abort(), 18e4);
@@ -39249,13 +39242,15 @@ function parseLockfile(content) {
39249
39242
  const name = extractPackageName(path);
39250
39243
  if (name && !packages.has(name)) {
39251
39244
  const e = entry;
39245
+ const deps = e.dependencies;
39252
39246
  packages.set(name, {
39253
39247
  version: e.version ?? "",
39254
39248
  resolved: e.resolved,
39255
39249
  integrity: e.integrity,
39256
39250
  dev: e.dev,
39257
39251
  optional: e.optional,
39258
- hasPlatformRestriction: !!(e.os || e.cpu)
39252
+ hasPlatformRestriction: !!(e.os || e.cpu),
39253
+ dependencies: deps && typeof deps === "object" ? deps : void 0
39259
39254
  });
39260
39255
  }
39261
39256
  }
@@ -39493,8 +39488,13 @@ function discoverChanges(cwd2, config) {
39493
39488
  }
39494
39489
  const lockfileInfo = findLockfile(cwd2);
39495
39490
  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: [] };
39495
+ }
39496
39496
  throw new Error(
39497
- "No lockfile found (package-lock.json, yarn.lock, or pnpm-lock.yaml). Run from your project root or use --base-lockfile."
39497
+ "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."
39498
39498
  );
39499
39499
  }
39500
39500
  const headContent = readFileSafe(lockfileInfo.path);
@@ -39505,6 +39505,7 @@ function discoverChanges(cwd2, config) {
39505
39505
  for (const [name, entry] of headParsed.packages) {
39506
39506
  if (packages2.length >= config.maxPackages) break;
39507
39507
  if (entry.optional && entry.hasPlatformRestriction) continue;
39508
+ if (name === SELF_PACKAGE) continue;
39508
39509
  packages2.push({
39509
39510
  name,
39510
39511
  version: entry.version,
@@ -39522,7 +39523,7 @@ function discoverChanges(cwd2, config) {
39522
39523
  const baseParsed = parseLockfile(baseContent2);
39523
39524
  const diff2 = diffLockfiles(baseParsed, headParsed, config.maxPackages, directDeps);
39524
39525
  return {
39525
- packages: diff2.changes.map(toPackageInput),
39526
+ packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
39526
39527
  method: "base-lockfile",
39527
39528
  skipped: diff2.skipped
39528
39529
  };
@@ -39532,7 +39533,7 @@ function discoverChanges(cwd2, config) {
39532
39533
  const baseParsed = parseLockfile(baseContent);
39533
39534
  const diff2 = diffLockfiles(baseParsed, headParsed, config.maxPackages, directDeps);
39534
39535
  return {
39535
- packages: diff2.changes.map(toPackageInput),
39536
+ packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
39536
39537
  method: "git-diff",
39537
39538
  skipped: diff2.skipped
39538
39539
  };
@@ -39551,7 +39552,7 @@ function discoverChanges(cwd2, config) {
39551
39552
  };
39552
39553
  });
39553
39554
  return {
39554
- packages: resolved.map(toPackageInput),
39555
+ packages: resolved.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
39555
39556
  method: "fallback",
39556
39557
  skipped: []
39557
39558
  };
@@ -39561,6 +39562,7 @@ function discoverChanges(cwd2, config) {
39561
39562
  for (const [name, entry] of headParsed.packages) {
39562
39563
  if (packages.length >= config.maxPackages) break;
39563
39564
  if (entry.optional && entry.hasPlatformRestriction) continue;
39565
+ if (name === SELF_PACKAGE) continue;
39564
39566
  packages.push({
39565
39567
  name,
39566
39568
  version: entry.version,
@@ -39703,7 +39705,7 @@ function parsePythonDepFile(projectDir, depFile) {
39703
39705
  }
39704
39706
  return packages;
39705
39707
  }
39706
- var MAX_LOCKFILE_BYTES;
39708
+ var MAX_LOCKFILE_BYTES, SELF_PACKAGE;
39707
39709
  var init_lockfile = __esm({
39708
39710
  "src/lockfile.ts"() {
39709
39711
  "use strict";
@@ -39713,6 +39715,207 @@ var init_lockfile = __esm({
39713
39715
  init_diff2();
39714
39716
  init_parse_package_json();
39715
39717
  MAX_LOCKFILE_BYTES = 50 * 1024 * 1024;
39718
+ SELF_PACKAGE = "@westbayberry/dg";
39719
+ }
39720
+ });
39721
+
39722
+ // src/pip-wrapper.ts
39723
+ import { spawn as spawn4 } from "node:child_process";
39724
+ import { readFileSync as readFileSync7, existsSync as existsSync6 } from "node:fs";
39725
+ function parsePipArgs(args) {
39726
+ let dgForce = false;
39727
+ const filtered = [];
39728
+ for (const arg of args) {
39729
+ if (arg === "--dg-force") {
39730
+ dgForce = true;
39731
+ } else {
39732
+ filtered.push(arg);
39733
+ }
39734
+ }
39735
+ const command = filtered[0] ?? "";
39736
+ const shouldScan = INSTALL_COMMANDS2.has(command);
39737
+ const packages = [];
39738
+ let requirementsFile;
39739
+ if (shouldScan) {
39740
+ for (let i = 1; i < filtered.length; i++) {
39741
+ const arg = filtered[i];
39742
+ if (arg === "-r" || arg === "--requirement") {
39743
+ if (i + 1 < filtered.length) {
39744
+ requirementsFile = filtered[i + 1];
39745
+ i++;
39746
+ }
39747
+ continue;
39748
+ }
39749
+ if (arg.startsWith("-")) {
39750
+ if (pipFlagTakesValue(arg)) i++;
39751
+ continue;
39752
+ }
39753
+ packages.push(arg);
39754
+ }
39755
+ }
39756
+ return {
39757
+ command,
39758
+ packages,
39759
+ rawArgs: filtered,
39760
+ dgForce,
39761
+ shouldScan,
39762
+ requirementsFile
39763
+ };
39764
+ }
39765
+ function pipFlagTakesValue(flag) {
39766
+ const valueFlags = [
39767
+ "--index-url",
39768
+ "-i",
39769
+ "--extra-index-url",
39770
+ "--constraint",
39771
+ "-c",
39772
+ "--requirement",
39773
+ "-r",
39774
+ "--target",
39775
+ "-t",
39776
+ "--prefix",
39777
+ "--src",
39778
+ "--root",
39779
+ "--config-settings"
39780
+ ];
39781
+ for (const f of valueFlags) {
39782
+ if (flag === f) return true;
39783
+ }
39784
+ return false;
39785
+ }
39786
+ function parseRequirementsFile(filePath) {
39787
+ if (!existsSync6(filePath)) return [];
39788
+ try {
39789
+ const content = readFileSync7(filePath, "utf-8");
39790
+ const specs = [];
39791
+ for (const rawLine of content.split("\n")) {
39792
+ let line = rawLine.trim();
39793
+ if (!line) continue;
39794
+ if (line.startsWith("#")) continue;
39795
+ if (line.startsWith("-e") || line.startsWith("--editable")) continue;
39796
+ if (/^(git|svn|hg|bzr)\+/.test(line)) continue;
39797
+ if (line.startsWith("-r") || line.startsWith("--requirement")) continue;
39798
+ if (line.startsWith("--")) continue;
39799
+ const commentIdx = line.indexOf(" #");
39800
+ if (commentIdx !== -1) line = line.slice(0, commentIdx).trim();
39801
+ const markerIdx = line.indexOf(";");
39802
+ if (markerIdx !== -1) line = line.slice(0, markerIdx).trim();
39803
+ if (line) specs.push(line);
39804
+ }
39805
+ return specs;
39806
+ } catch {
39807
+ return [];
39808
+ }
39809
+ }
39810
+ function parsePipSpec(spec) {
39811
+ const match = spec.match(/^([a-zA-Z0-9][-a-zA-Z0-9._]*)(([><=!~]=?).+)?$/);
39812
+ if (!match) return { name: spec, versionSpec: null };
39813
+ return {
39814
+ name: match[1],
39815
+ versionSpec: match[2] ?? null
39816
+ };
39817
+ }
39818
+ async function resolvePipVersion(spec) {
39819
+ const { name, versionSpec } = parsePipSpec(spec);
39820
+ if (versionSpec?.startsWith("==")) {
39821
+ const version = versionSpec.slice(2);
39822
+ try {
39823
+ const controller = new AbortController();
39824
+ const timer = setTimeout(() => controller.abort(), 15e3);
39825
+ const resp = await fetch(`https://pypi.org/pypi/${name}/${version}/json`, {
39826
+ signal: controller.signal
39827
+ });
39828
+ clearTimeout(timer);
39829
+ if (resp.ok) return version;
39830
+ return null;
39831
+ } catch {
39832
+ return null;
39833
+ }
39834
+ }
39835
+ try {
39836
+ const controller = new AbortController();
39837
+ const timer = setTimeout(() => controller.abort(), 15e3);
39838
+ const resp = await fetch(`https://pypi.org/pypi/${name}/json`, {
39839
+ signal: controller.signal
39840
+ });
39841
+ clearTimeout(timer);
39842
+ if (!resp.ok) return null;
39843
+ const data = await resp.json();
39844
+ return data.info?.version ?? null;
39845
+ } catch {
39846
+ return null;
39847
+ }
39848
+ }
39849
+ async function resolvePackages2(specs) {
39850
+ const results = await Promise.allSettled(
39851
+ specs.map(async (spec) => {
39852
+ const { name } = parsePipSpec(spec);
39853
+ const version = await resolvePipVersion(spec);
39854
+ return { spec, name, version };
39855
+ })
39856
+ );
39857
+ const resolved = [];
39858
+ const failed = [];
39859
+ for (const result of results) {
39860
+ if (result.status === "rejected") {
39861
+ failed.push("unknown");
39862
+ continue;
39863
+ }
39864
+ const { spec, name, version } = result.value;
39865
+ if (version) {
39866
+ resolved.push({
39867
+ name,
39868
+ version,
39869
+ previousVersion: null,
39870
+ isNew: true
39871
+ });
39872
+ } else {
39873
+ failed.push(spec);
39874
+ }
39875
+ }
39876
+ return { resolved, failed };
39877
+ }
39878
+ async function detectPipBinary() {
39879
+ if (cachedPipBinary) return cachedPipBinary;
39880
+ const candidates = ["python3 -m pip", "python -m pip", "pip3", "pip"];
39881
+ for (const cmd of candidates) {
39882
+ try {
39883
+ const parts = cmd.split(" ");
39884
+ const code = await new Promise((resolve) => {
39885
+ const child = spawn4(parts[0], [...parts.slice(1), "--version"], {
39886
+ stdio: ["pipe", "pipe", "pipe"],
39887
+ timeout: 5e3
39888
+ });
39889
+ child.on("close", (c) => resolve(c ?? 1));
39890
+ child.on("error", () => resolve(1));
39891
+ });
39892
+ if (code === 0) {
39893
+ cachedPipBinary = cmd;
39894
+ return cmd;
39895
+ }
39896
+ } catch {
39897
+ }
39898
+ }
39899
+ throw new Error("pip not found. Install pip or ensure 'python -m pip' is available.");
39900
+ }
39901
+ async function runPip(args) {
39902
+ const pipCmd = await detectPipBinary();
39903
+ const parts = pipCmd.split(" ");
39904
+ return new Promise((resolve) => {
39905
+ const child = spawn4(parts[0], [...parts.slice(1), ...args], {
39906
+ stdio: "inherit",
39907
+ shell: false
39908
+ });
39909
+ child.on("close", (code) => resolve(code ?? 1));
39910
+ child.on("error", () => resolve(1));
39911
+ });
39912
+ }
39913
+ var INSTALL_COMMANDS2, cachedPipBinary;
39914
+ var init_pip_wrapper = __esm({
39915
+ "src/pip-wrapper.ts"() {
39916
+ "use strict";
39917
+ INSTALL_COMMANDS2 = /* @__PURE__ */ new Set(["install", "update"]);
39918
+ cachedPipBinary = null;
39716
39919
  }
39717
39920
  });
39718
39921
 
@@ -39721,7 +39924,7 @@ var discover_exports = {};
39721
39924
  __export(discover_exports, {
39722
39925
  discoverProjects: () => discoverProjects
39723
39926
  });
39724
- import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync, lstatSync } from "node:fs";
39927
+ import { existsSync as existsSync7, readFileSync as readFileSync8, readdirSync, lstatSync } from "node:fs";
39725
39928
  import { join as join6, relative, basename } from "node:path";
39726
39929
  function discoverProjects(root) {
39727
39930
  const projects = [];
@@ -39732,7 +39935,7 @@ function walk(dir, root, depth, out) {
39732
39935
  if (depth > MAX_DEPTH) return;
39733
39936
  for (const lockfile of NPM_LOCKFILES) {
39734
39937
  const lockPath = join6(dir, lockfile);
39735
- if (existsSync6(lockPath)) {
39938
+ if (existsSync7(lockPath)) {
39736
39939
  const count = countNpmPackages(lockPath);
39737
39940
  if (count > 0) {
39738
39941
  out.push({
@@ -39748,7 +39951,7 @@ function walk(dir, root, depth, out) {
39748
39951
  }
39749
39952
  for (const depFile of PYTHON_DEPFILES) {
39750
39953
  const depPath = join6(dir, depFile);
39751
- if (existsSync6(depPath)) {
39954
+ if (existsSync7(depPath)) {
39752
39955
  const count = countPythonPackages(depPath, depFile);
39753
39956
  if (count > 0) {
39754
39957
  out.push({
@@ -39783,7 +39986,7 @@ function walk(dir, root, depth, out) {
39783
39986
  function countNpmPackages(lockPath) {
39784
39987
  try {
39785
39988
  const name = basename(lockPath);
39786
- const content = readFileSync7(lockPath, "utf-8");
39989
+ const content = readFileSync8(lockPath, "utf-8");
39787
39990
  if (name === "yarn.lock") {
39788
39991
  return (content.match(/^\S.*:$/gm) || []).length;
39789
39992
  }
@@ -39804,7 +40007,7 @@ function countNpmPackages(lockPath) {
39804
40007
  }
39805
40008
  function countPythonPackages(depPath, depFile) {
39806
40009
  try {
39807
- const content = readFileSync7(depPath, "utf-8");
40010
+ const content = readFileSync8(depPath, "utf-8");
39808
40011
  if (depFile === "Pipfile.lock") {
39809
40012
  const parsed = JSON.parse(content);
39810
40013
  const defaultCount = Object.keys(parsed.default || {}).length;
@@ -39861,40 +40064,50 @@ __export(static_output_exports, {
39861
40064
  renderResultStatic: () => renderResultStatic,
39862
40065
  runStatic: () => runStatic,
39863
40066
  runStaticLogin: () => runStaticLogin,
39864
- runStaticNpm: () => runStaticNpm
40067
+ runStaticNpm: () => runStaticNpm,
40068
+ runStaticPip: () => runStaticPip
39865
40069
  });
39866
40070
  function printTrialBanner(result) {
39867
40071
  if (result.trialScansRemaining === void 0) return;
39868
- const remaining = result.trialScansRemaining;
39869
- if (remaining > 0) {
39870
- process.stderr.write(
39871
- import_chalk4.default.dim(` ${remaining} free scan${remaining !== 1 ? "s" : ""} remaining. `) + import_chalk4.default.dim(`Run \`dg login\` for unlimited scans.
39872
- `)
39873
- );
39874
- } else {
39875
- process.stderr.write(
39876
- import_chalk4.default.yellow(` No free scans remaining. `) + import_chalk4.default.yellow(`Run \`dg login\` to continue scanning.
40072
+ process.stderr.write(
40073
+ import_chalk4.default.dim(` Free tier \xB7 Run \`dg login\` for finding details and higher rate limits.
39877
40074
  `)
39878
- );
39879
- }
40075
+ );
39880
40076
  }
39881
- function handleTrialExhausted2(error) {
40077
+ function handleTrialExhausted2(error, jsonMode = false) {
39882
40078
  if (error instanceof TrialExhaustedError) {
39883
- process.stderr.write(
39884
- 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")
39885
- );
40079
+ let hasKey = false;
40080
+ try {
40081
+ const { getStoredApiKey: getStoredApiKey2 } = (init_auth(), __toCommonJS(auth_exports));
40082
+ hasKey = !!getStoredApiKey2();
40083
+ } catch {
40084
+ }
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.";
40086
+ if (jsonMode) {
40087
+ process.stdout.write(JSON.stringify({
40088
+ error: true,
40089
+ code: "trial_exhausted",
40090
+ message,
40091
+ scansUsed: error.scansUsed,
40092
+ maxScans: error.maxScans
40093
+ }, null, 2) + "\n");
40094
+ } else {
40095
+ if (hasKey) {
40096
+ process.stderr.write(import_chalk4.default.yellow(`
40097
+ ${message}
40098
+
40099
+ `));
40100
+ } else {
40101
+ 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")
40103
+ );
40104
+ }
40105
+ }
39886
40106
  process.exit(1);
39887
40107
  return true;
39888
40108
  }
39889
40109
  return false;
39890
40110
  }
39891
- function severityColor(sev) {
39892
- if (sev >= 5) return (s) => import_chalk4.default.bold.red(s);
39893
- if (sev >= 4) return import_chalk4.default.red;
39894
- if (sev >= 3) return import_chalk4.default.yellow;
39895
- if (sev >= 2) return import_chalk4.default.cyan;
39896
- return import_chalk4.default.dim;
39897
- }
39898
40111
  function actionColor(action) {
39899
40112
  if (action === "block") return import_chalk4.default.red;
39900
40113
  if (action === "warn") return import_chalk4.default.yellow;
@@ -39917,9 +40130,9 @@ function groupPackages(packages) {
39917
40130
  }
39918
40131
  return [...map.values()].map((pkgs) => ({ packages: pkgs, key: pkgs[0].name })).sort((a, b) => b.packages[0].score - a.packages[0].score);
39919
40132
  }
39920
- function actionBadge(score, config) {
39921
- if (score >= config.blockThreshold) return { label: "BLOCK", color: import_chalk4.default.red };
39922
- if (score >= config.warnThreshold) return { label: "WARN", color: import_chalk4.default.yellow };
40133
+ 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 };
39923
40136
  return { label: "pass", color: import_chalk4.default.green };
39924
40137
  }
39925
40138
  function renderResultStatic(result, config) {
@@ -39949,6 +40162,15 @@ function renderResultStatic(result, config) {
39949
40162
  ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk4.default.dim("\u2502")} ${import_chalk4.default.green("all clean")}`
39950
40163
  );
39951
40164
  }
40165
+ const licensedPkgs = result.packages.filter((p) => p.license);
40166
+ const licenseIssues = licensedPkgs.filter(
40167
+ (p) => p.license && p.license.riskCategory !== "permissive"
40168
+ );
40169
+ if (licenseIssues.length > 0) {
40170
+ 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`)}`
40172
+ );
40173
+ }
39952
40174
  lines.push("");
39953
40175
  if (total === 0) {
39954
40176
  lines.push(" No packages to scan.");
@@ -39961,10 +40183,13 @@ function renderResultStatic(result, config) {
39961
40183
  lines.push(` ${import_chalk4.default.dim("\u2500".repeat(60))}`);
39962
40184
  for (const group of groups) {
39963
40185
  const rep = group.packages[0];
39964
- const { label, color } = actionBadge(rep.score, config);
40186
+ const { label, color } = actionBadge(rep.score);
39965
40187
  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
+ const lcInfo = rep.license;
40189
+ 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;
39966
40191
  lines.push(
39967
- ` ${color(pad(label, 7))}${import_chalk4.default.bold(pad(truncate(names, 50), 52))}${import_chalk4.default.dim(`score ${rep.score}`)}`
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}`)}`
39968
40193
  );
39969
40194
  }
39970
40195
  lines.push("");
@@ -39975,46 +40200,6 @@ function renderResultStatic(result, config) {
39975
40200
  );
39976
40201
  lines.push("");
39977
40202
  }
39978
- for (const group of groups) {
39979
- const rep = group.packages[0];
39980
- 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`;
39981
- lines.push(
39982
- ` ${import_chalk4.default.dim("\u2500\u2500")} ${import_chalk4.default.bold(`${names} (score: ${rep.score})`)}`
39983
- );
39984
- if (group.packages.length > 3) {
39985
- lines.push(
39986
- ` ${import_chalk4.default.dim("Affects: " + group.packages.map((p) => p.name).join(", "))}`
39987
- );
39988
- }
39989
- lines.push("");
39990
- const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
39991
- for (const finding of visibleFindings) {
39992
- const sevLabel = SEVERITY_LABELS[finding.severity] ?? "INFO";
39993
- const colorFn = severityColor(finding.severity);
39994
- lines.push(
39995
- ` ${colorFn(pad(sevLabel, 10))}${finding.id} \u2014 ${finding.title}`
39996
- );
39997
- const evidenceLimit = 3;
39998
- for (let i = 0; i < Math.min(finding.evidence.length, evidenceLimit); i++) {
39999
- lines.push(
40000
- ` ${" ".repeat(10)}${import_chalk4.default.dim(truncate(finding.evidence[i], 76))}`
40001
- );
40002
- }
40003
- if (finding.evidence.length > evidenceLimit) {
40004
- lines.push(
40005
- ` ${" ".repeat(10)}${import_chalk4.default.dim(`... and ${finding.evidence.length - evidenceLimit} more`)}`
40006
- );
40007
- }
40008
- lines.push("");
40009
- }
40010
- const safeVersion = result.safeVersions[rep.name];
40011
- if (safeVersion) {
40012
- lines.push(
40013
- ` ${import_chalk4.default.green(`Safe version: ${rep.name}@${safeVersion}`)}`
40014
- );
40015
- lines.push("");
40016
- }
40017
- }
40018
40203
  if (result.durationMs) {
40019
40204
  lines.push(
40020
40205
  ` ${import_chalk4.default.dim(`Completed in ${(result.durationMs / 1e3).toFixed(1)}s`)}`
@@ -40036,7 +40221,7 @@ async function runStatic(config) {
40036
40221
  process.exit(0);
40037
40222
  }
40038
40223
  dbg(
40039
- `mode=${config.mode} block=${config.blockThreshold} warn=${config.warnThreshold} max=${config.maxPackages}`
40224
+ `mode=${config.mode} max=${config.maxPackages}`
40040
40225
  );
40041
40226
  dbg(`api=${config.apiUrl}`);
40042
40227
  process.stderr.write(import_chalk4.default.dim(" Discovering package changes...\n"));
@@ -40063,15 +40248,7 @@ async function runStatic(config) {
40063
40248
  }
40064
40249
  process.exit(0);
40065
40250
  }
40066
- const packages = discovery.packages.filter(
40067
- (p) => !config.allowlist.includes(p.name.toLowerCase())
40068
- );
40069
- if (packages.length === 0) {
40070
- process.stderr.write(
40071
- import_chalk4.default.dim(" All changed packages are allowlisted.\n")
40072
- );
40073
- process.exit(0);
40074
- }
40251
+ const packages = discovery.packages;
40075
40252
  process.stderr.write(
40076
40253
  import_chalk4.default.dim(
40077
40254
  ` Scanning ${packages.length} package${packages.length !== 1 ? "s" : ""} (${discovery.method})...
@@ -40100,7 +40277,7 @@ async function runStatic(config) {
40100
40277
  `API responded in ${Date.now() - startMs}ms, action=${result.action}, score=${result.score}`
40101
40278
  );
40102
40279
  } catch (error) {
40103
- if (handleTrialExhausted2(error)) return;
40280
+ if (handleTrialExhausted2(error, config.json)) return;
40104
40281
  throw error;
40105
40282
  }
40106
40283
  const output = renderResultStatic(result, config);
@@ -40172,24 +40349,16 @@ async function runStaticNpm(npmArgs, config) {
40172
40349
  return scanAndInstallStatic(resolved, parsed, config);
40173
40350
  }
40174
40351
  async function scanAndInstallStatic(resolved, parsed, config) {
40175
- const toScan = resolved.filter((p) => !config.allowlist.includes(p.name.toLowerCase()));
40176
- if (toScan.length === 0) {
40177
- process.stderr.write(
40178
- import_chalk4.default.dim(" All packages are allowlisted. Passing through to npm.\n")
40179
- );
40180
- const code = await runNpm(parsed.rawArgs);
40181
- process.exit(code);
40182
- }
40183
40352
  process.stderr.write(
40184
40353
  import_chalk4.default.dim(
40185
- ` Scanning ${toScan.length} package${toScan.length !== 1 ? "s" : ""}...
40354
+ ` Scanning ${resolved.length} package${resolved.length !== 1 ? "s" : ""}...
40186
40355
  `
40187
40356
  )
40188
40357
  );
40189
40358
  let result;
40190
40359
  try {
40191
40360
  const startMs = Date.now();
40192
- result = await callAnalyzeAPI(toScan, config);
40361
+ result = await callAnalyzeAPI(resolved, config);
40193
40362
  const elapsed = Date.now() - startMs;
40194
40363
  if (config.debug) {
40195
40364
  process.stderr.write(
@@ -40200,7 +40369,7 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40200
40369
  );
40201
40370
  }
40202
40371
  } catch (error) {
40203
- if (handleTrialExhausted2(error)) return;
40372
+ if (handleTrialExhausted2(error, config.json)) return;
40204
40373
  const msg = error instanceof Error ? error.message : String(error);
40205
40374
  process.stderr.write(
40206
40375
  import_chalk4.default.yellow(
@@ -40215,7 +40384,7 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40215
40384
  if (result.action === "pass") {
40216
40385
  process.stderr.write(
40217
40386
  import_chalk4.default.green(
40218
- ` ${import_chalk4.default.bold("\u2713")} ${toScan.length} package${toScan.length !== 1 ? "s" : ""} scanned \u2014 all clear
40387
+ ` ${import_chalk4.default.bold("\u2713")} ${resolved.length} package${resolved.length !== 1 ? "s" : ""} scanned \u2014 all clear
40219
40388
  `
40220
40389
  )
40221
40390
  );
@@ -40255,6 +40424,102 @@ async function scanAndInstallStatic(resolved, parsed, config) {
40255
40424
  process.exit(2);
40256
40425
  }
40257
40426
  }
40427
+ async function runStaticPip(pipArgs, config) {
40428
+ const parsed = parsePipArgs(pipArgs);
40429
+ if (!parsed.shouldScan) {
40430
+ const code = await runPip(parsed.rawArgs);
40431
+ process.exit(code);
40432
+ }
40433
+ let specs = parsed.packages;
40434
+ if (specs.length === 0 && parsed.requirementsFile) {
40435
+ specs = parseRequirementsFile(parsed.requirementsFile);
40436
+ }
40437
+ if (specs.length === 0) {
40438
+ process.stderr.write(
40439
+ import_chalk4.default.dim(" Dependency Guardian: no packages to scan, passing through to pip.\n")
40440
+ );
40441
+ const code = await runPip(parsed.rawArgs);
40442
+ process.exit(code);
40443
+ }
40444
+ process.stderr.write(
40445
+ import_chalk4.default.dim(
40446
+ ` Resolving ${specs.length} package${specs.length !== 1 ? "s" : ""} from PyPI...
40447
+ `
40448
+ )
40449
+ );
40450
+ const { resolved, failed } = await resolvePackages2(specs);
40451
+ if (failed.length > 0) {
40452
+ process.stderr.write(
40453
+ import_chalk4.default.yellow(` Warning: Could not resolve versions for: ${failed.join(", ")}
40454
+ `)
40455
+ );
40456
+ }
40457
+ if (resolved.length === 0) {
40458
+ process.stderr.write(
40459
+ import_chalk4.default.dim(" No packages to scan. Passing through to pip.\n")
40460
+ );
40461
+ const code = await runPip(parsed.rawArgs);
40462
+ process.exit(code);
40463
+ }
40464
+ process.stderr.write(
40465
+ import_chalk4.default.dim(
40466
+ ` Scanning ${resolved.length} Python package${resolved.length !== 1 ? "s" : ""}...
40467
+ `
40468
+ )
40469
+ );
40470
+ let result;
40471
+ try {
40472
+ result = await callPyPIAnalyzeAPI(resolved, config);
40473
+ } catch (error) {
40474
+ if (handleTrialExhausted2(error, config.json)) return;
40475
+ const msg = error instanceof Error ? error.message : String(error);
40476
+ process.stderr.write(
40477
+ import_chalk4.default.yellow(` Warning: Scan failed (${msg}). Proceeding with install.
40478
+ `)
40479
+ );
40480
+ const code = await runPip(parsed.rawArgs);
40481
+ process.exit(code);
40482
+ return;
40483
+ }
40484
+ if (result.action === "pass") {
40485
+ 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
40488
+ `
40489
+ )
40490
+ );
40491
+ printTrialBanner(result);
40492
+ process.stderr.write("\n");
40493
+ const code = await runPip(parsed.rawArgs);
40494
+ process.exit(code);
40495
+ }
40496
+ const output = renderResultStatic(result, config);
40497
+ process.stdout.write(output + "\n");
40498
+ printTrialBanner(result);
40499
+ if (result.action === "warn") {
40500
+ process.stderr.write(
40501
+ import_chalk4.default.yellow(" Warnings detected. Proceeding with install.\n\n")
40502
+ );
40503
+ const code = await runPip(parsed.rawArgs);
40504
+ process.exit(code);
40505
+ }
40506
+ if (result.action === "block") {
40507
+ if (parsed.dgForce) {
40508
+ process.stderr.write(
40509
+ import_chalk4.default.yellow(import_chalk4.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
40510
+ );
40511
+ const code = await runPip(parsed.rawArgs);
40512
+ process.exit(code);
40513
+ }
40514
+ process.stderr.write(
40515
+ import_chalk4.default.red(import_chalk4.default.bold(" BLOCKED: ")) + import_chalk4.default.red("High-risk packages detected. Install aborted.\n")
40516
+ );
40517
+ process.stderr.write(
40518
+ import_chalk4.default.dim(" Use --dg-force to bypass this check.\n\n")
40519
+ );
40520
+ process.exit(2);
40521
+ }
40522
+ }
40258
40523
  async function runStaticLogin() {
40259
40524
  const {
40260
40525
  createAuthSession: createAuthSession2,
@@ -40332,7 +40597,7 @@ async function runStaticLogin() {
40332
40597
  );
40333
40598
  process.exit(1);
40334
40599
  }
40335
- var import_chalk4, SEVERITY_LABELS;
40600
+ var import_chalk4;
40336
40601
  var init_static_output = __esm({
40337
40602
  "src/static-output.ts"() {
40338
40603
  "use strict";
@@ -40340,13 +40605,7 @@ var init_static_output = __esm({
40340
40605
  init_api();
40341
40606
  init_lockfile();
40342
40607
  init_npm_wrapper();
40343
- SEVERITY_LABELS = {
40344
- 5: "CRITICAL",
40345
- 4: "HIGH",
40346
- 3: "MEDIUM",
40347
- 2: "LOW",
40348
- 1: "INFO"
40349
- };
40608
+ init_pip_wrapper();
40350
40609
  }
40351
40610
  });
40352
40611
 
@@ -40357,8 +40616,8 @@ __export(hook_exports, {
40357
40616
  });
40358
40617
  import { execFileSync as execFileSync3 } from "node:child_process";
40359
40618
  import {
40360
- existsSync as existsSync7,
40361
- readFileSync as readFileSync8,
40619
+ existsSync as existsSync8,
40620
+ readFileSync as readFileSync9,
40362
40621
  writeFileSync as writeFileSync3,
40363
40622
  mkdirSync,
40364
40623
  chmodSync as chmodSync2,
@@ -40380,8 +40639,8 @@ function installHook() {
40380
40639
  const hooksDir = join7(gitDir, "hooks");
40381
40640
  const hookPath = join7(hooksDir, "pre-commit");
40382
40641
  mkdirSync(hooksDir, { recursive: true });
40383
- if (existsSync7(hookPath)) {
40384
- const existing = readFileSync8(hookPath, "utf-8");
40642
+ if (existsSync8(hookPath)) {
40643
+ const existing = readFileSync9(hookPath, "utf-8");
40385
40644
  if (existing.includes(HOOK_MARKER)) {
40386
40645
  process.stderr.write(" Hook already installed.\n");
40387
40646
  return;
@@ -40402,11 +40661,11 @@ function installHook() {
40402
40661
  function uninstallHook() {
40403
40662
  const gitDir = findGitDir();
40404
40663
  const hookPath = join7(gitDir, "hooks", "pre-commit");
40405
- if (!existsSync7(hookPath)) {
40664
+ if (!existsSync8(hookPath)) {
40406
40665
  process.stderr.write(" No hook to remove.\n");
40407
40666
  return;
40408
40667
  }
40409
- const content = readFileSync8(hookPath, "utf-8");
40668
+ const content = readFileSync9(hookPath, "utf-8");
40410
40669
  if (!content.includes(HOOK_MARKER)) {
40411
40670
  process.stderr.write(
40412
40671
  " No Dependency Guardian hook found in pre-commit.\n"
@@ -40601,19 +40860,10 @@ function useNpmWrapper(npmArgs, config) {
40601
40860
  dispatch({ type: "DONE", exitCode: code });
40602
40861
  return;
40603
40862
  }
40604
- const toScan = resolved.filter(
40605
- (p) => !config.allowlist.includes(p.name.toLowerCase())
40606
- );
40607
- if (toScan.length === 0) {
40608
- dispatch({ type: "INSTALLING" });
40609
- const code = await runNpm(parsed.rawArgs);
40610
- dispatch({ type: "DONE", exitCode: code });
40611
- return;
40612
- }
40613
- dispatch({ type: "SCANNING", count: toScan.length });
40614
- const result = await callAnalyzeAPI(toScan, config);
40863
+ dispatch({ type: "SCANNING", count: resolved.length });
40864
+ const result = await callAnalyzeAPI(resolved, config);
40615
40865
  if (result.action === "pass") {
40616
- dispatch({ type: "PASS", count: toScan.length });
40866
+ dispatch({ type: "PASS", count: resolved.length });
40617
40867
  dispatch({ type: "INSTALLING" });
40618
40868
  const code = await runNpm(parsed.rawArgs);
40619
40869
  dispatch({ type: "DONE", exitCode: code });
@@ -40886,16 +41136,16 @@ function groupPackages2(packages) {
40886
41136
  }
40887
41137
  return [...map.values()].map((pkgs) => ({ packages: pkgs, key: pkgs[0].name })).sort((a, b) => b.packages[0].score - a.packages[0].score);
40888
41138
  }
40889
- function severityColor2(sev) {
41139
+ function severityColor(sev) {
40890
41140
  if (sev >= 5) return (s) => import_chalk6.default.bold.red(s);
40891
41141
  if (sev >= 4) return import_chalk6.default.magenta;
40892
41142
  if (sev >= 3) return import_chalk6.default.yellow;
40893
41143
  if (sev >= 2) return import_chalk6.default.dim;
40894
41144
  return import_chalk6.default.dim;
40895
41145
  }
40896
- function actionBadge2(score, config) {
40897
- if (score >= config.blockThreshold) return { label: "BLOCK", color: import_chalk6.default.red };
40898
- if (score >= config.warnThreshold) return { label: "WARN", color: import_chalk6.default.yellow };
41146
+ 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 };
40899
41149
  return { label: "PASS", color: import_chalk6.default.green };
40900
41150
  }
40901
41151
  function truncate2(s, max) {
@@ -40904,7 +41154,7 @@ function truncate2(s, max) {
40904
41154
  function pad2(s, len) {
40905
41155
  return s + " ".repeat(Math.max(0, len - s.length));
40906
41156
  }
40907
- var import_chalk6, import_jsx_runtime5, SEVERITY_LABELS2, EVIDENCE_LIMIT, ResultsView;
41157
+ var import_chalk6, import_jsx_runtime5, SEVERITY_LABELS, EVIDENCE_LIMIT, ResultsView;
40908
41158
  var init_ResultsView = __esm({
40909
41159
  async "src/ui/components/ResultsView.tsx"() {
40910
41160
  "use strict";
@@ -40913,7 +41163,7 @@ var init_ResultsView = __esm({
40913
41163
  await init_ScoreHeader();
40914
41164
  await init_DurationLine();
40915
41165
  import_jsx_runtime5 = __toESM(require_jsx_runtime());
40916
- SEVERITY_LABELS2 = {
41166
+ SEVERITY_LABELS = {
40917
41167
  5: "CRITICAL",
40918
41168
  4: "HIGH",
40919
41169
  3: "MEDIUM",
@@ -40952,7 +41202,7 @@ var init_ResultsView = __esm({
40952
41202
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { dimColor: true, children: "\u2500".repeat(60) }),
40953
41203
  groups.map((group) => {
40954
41204
  const rep = group.packages[0];
40955
- const { label, color } = actionBadge2(rep.score, config);
41205
+ const { label, color } = actionBadge2(rep.score);
40956
41206
  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`;
40957
41207
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Text, { children: [
40958
41208
  " ",
@@ -40988,8 +41238,8 @@ var init_ResultsView = __esm({
40988
41238
  ] }),
40989
41239
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: " " }),
40990
41240
  visibleFindings.map((finding, idx) => {
40991
- const sevLabel = SEVERITY_LABELS2[finding.severity] ?? "INFO";
40992
- const colorFn = severityColor2(finding.severity);
41241
+ const sevLabel = SEVERITY_LABELS[finding.severity] ?? "INFO";
41242
+ const colorFn = severityColor(finding.severity);
40993
41243
  const evidenceSlice = finding.evidence.slice(0, EVIDENCE_LIMIT);
40994
41244
  const overflow = finding.evidence.length - EVIDENCE_LIMIT;
40995
41245
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", children: [
@@ -41247,22 +41497,349 @@ var init_NpmWrapperApp = __esm({
41247
41497
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ErrorView, { error: new Error(state.message) });
41248
41498
  case "passthrough":
41249
41499
  return null;
41250
- case "trial_exhausted":
41251
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
41500
+ case "trial_exhausted": {
41501
+ let hasKey = false;
41502
+ try {
41503
+ const { getStoredApiKey: getStoredApiKey2 } = (init_auth(), __toCommonJS(auth_exports));
41504
+ hasKey = !!getStoredApiKey2();
41505
+ } catch {
41506
+ }
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: [
41510
+ "Run ",
41511
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
41512
+ " then ",
41513
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41514
+ " to re-authenticate."
41515
+ ] })
41516
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(import_jsx_runtime8.Fragment, { children: [
41252
41517
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
41253
41518
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Text, { children: [
41254
41519
  "Run ",
41255
41520
  /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41256
41521
  " to create a free account and continue scanning."
41257
41522
  ] })
41523
+ ] }) });
41524
+ }
41525
+ }
41526
+ };
41527
+ }
41528
+ });
41529
+
41530
+ // src/ui/hooks/usePipWrapper.ts
41531
+ function reducer3(_state, action) {
41532
+ switch (action.type) {
41533
+ case "PASSTHROUGH":
41534
+ return { phase: "passthrough" };
41535
+ case "RESOLVING":
41536
+ return { phase: "resolving", count: action.count };
41537
+ case "SCANNING":
41538
+ return { phase: "scanning", count: action.count };
41539
+ case "PASS":
41540
+ return { phase: "pass", count: action.count };
41541
+ case "WARN":
41542
+ return { phase: "warn", result: action.result };
41543
+ case "BLOCKED":
41544
+ return { phase: "blocked", result: action.result, dgForce: action.dgForce };
41545
+ case "INSTALLING":
41546
+ return { phase: "installing" };
41547
+ case "DONE":
41548
+ return { phase: "done", exitCode: action.exitCode };
41549
+ case "ERROR":
41550
+ return { phase: "error", message: action.message, proceed: action.proceed };
41551
+ case "TRIAL_EXHAUSTED":
41552
+ return { phase: "trial_exhausted" };
41553
+ }
41554
+ }
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);
41561
+ const confirmInstall = () => {
41562
+ if (pendingInstall.current) {
41563
+ pendingInstall.current();
41564
+ pendingInstall.current = null;
41565
+ rejectRef.current = null;
41566
+ }
41567
+ };
41568
+ const rejectInstall = () => {
41569
+ if (rejectRef.current) {
41570
+ rejectRef.current();
41571
+ pendingInstall.current = null;
41572
+ rejectRef.current = null;
41573
+ }
41574
+ };
41575
+ (0, import_react27.useEffect)(() => {
41576
+ if (started.current) return;
41577
+ started.current = true;
41578
+ const parsed = parsedRef.current;
41579
+ (async () => {
41580
+ try {
41581
+ if (!parsed.shouldScan) {
41582
+ dispatch({ type: "PASSTHROUGH" });
41583
+ const code = await runPip(parsed.rawArgs);
41584
+ dispatch({ type: "DONE", exitCode: code });
41585
+ return;
41586
+ }
41587
+ let specs;
41588
+ if (parsed.packages.length === 0 && parsed.requirementsFile) {
41589
+ specs = parseRequirementsFile(parsed.requirementsFile);
41590
+ if (specs.length === 0) {
41591
+ dispatch({ type: "PASSTHROUGH" });
41592
+ const code = await runPip(parsed.rawArgs);
41593
+ dispatch({ type: "DONE", exitCode: code });
41594
+ return;
41595
+ }
41596
+ } else if (parsed.packages.length === 0) {
41597
+ dispatch({ type: "PASSTHROUGH" });
41598
+ const code = await runPip(parsed.rawArgs);
41599
+ dispatch({ type: "DONE", exitCode: code });
41600
+ return;
41601
+ } else {
41602
+ specs = parsed.packages;
41603
+ }
41604
+ dispatch({ type: "RESOLVING", count: specs.length });
41605
+ const { resolved, failed } = await resolvePackages2(specs);
41606
+ if (resolved.length === 0) {
41607
+ dispatch({ type: "PASSTHROUGH" });
41608
+ const code = await runPip(parsed.rawArgs);
41609
+ dispatch({ type: "DONE", exitCode: code });
41610
+ return;
41611
+ }
41612
+ dispatch({ type: "SCANNING", count: resolved.length });
41613
+ const result = await callPyPIAnalyzeAPI(resolved, config);
41614
+ if (result.action === "pass") {
41615
+ dispatch({ type: "PASS", count: resolved.length });
41616
+ dispatch({ type: "INSTALLING" });
41617
+ const code = await runPip(parsed.rawArgs);
41618
+ dispatch({ type: "DONE", exitCode: code });
41619
+ return;
41620
+ }
41621
+ if (result.action === "warn") {
41622
+ dispatch({ type: "WARN", result });
41623
+ process.stdout.write(renderResultStatic(result, config) + "\n");
41624
+ dispatch({ type: "INSTALLING" });
41625
+ const code = await runPip(parsed.rawArgs);
41626
+ dispatch({ type: "DONE", exitCode: code });
41627
+ return;
41628
+ }
41629
+ if (result.action === "block") {
41630
+ process.stdout.write(renderResultStatic(result, config) + "\n");
41631
+ if (parsed.dgForce) {
41632
+ dispatch({ type: "BLOCKED", result, dgForce: true });
41633
+ dispatch({ type: "INSTALLING" });
41634
+ const code = await runPip(parsed.rawArgs);
41635
+ dispatch({ type: "DONE", exitCode: code });
41636
+ return;
41637
+ }
41638
+ dispatch({ type: "BLOCKED", result, dgForce: false });
41639
+ const shouldProceed = await new Promise((resolve) => {
41640
+ pendingInstall.current = () => resolve(true);
41641
+ rejectRef.current = () => resolve(false);
41642
+ });
41643
+ if (shouldProceed) {
41644
+ dispatch({ type: "INSTALLING" });
41645
+ const code = await runPip(parsed.rawArgs);
41646
+ dispatch({ type: "DONE", exitCode: code });
41647
+ } else {
41648
+ dispatch({ type: "DONE", exitCode: 2 });
41649
+ }
41650
+ return;
41651
+ }
41652
+ } catch (error) {
41653
+ if (error instanceof TrialExhaustedError) {
41654
+ dispatch({ type: "TRIAL_EXHAUSTED" });
41655
+ return;
41656
+ }
41657
+ const message = error instanceof Error ? error.message : String(error);
41658
+ dispatch({ type: "ERROR", message, proceed: true });
41659
+ dispatch({ type: "INSTALLING" });
41660
+ const code = await runPip(parsedRef.current.rawArgs);
41661
+ dispatch({ type: "DONE", exitCode: code });
41662
+ }
41663
+ })();
41664
+ }, [pipArgs, config]);
41665
+ return { state, confirmInstall, rejectInstall };
41666
+ }
41667
+ var import_react27;
41668
+ var init_usePipWrapper = __esm({
41669
+ "src/ui/hooks/usePipWrapper.ts"() {
41670
+ "use strict";
41671
+ import_react27 = __toESM(require_react());
41672
+ init_pip_wrapper();
41673
+ init_api();
41674
+ init_static_output();
41675
+ }
41676
+ });
41677
+
41678
+ // src/ui/PipWrapperApp.tsx
41679
+ var PipWrapperApp_exports = {};
41680
+ __export(PipWrapperApp_exports, {
41681
+ PipWrapperApp: () => PipWrapperApp
41682
+ });
41683
+ var import_react28, import_jsx_runtime9, PipWrapperApp;
41684
+ var init_PipWrapperApp = __esm({
41685
+ async "src/ui/PipWrapperApp.tsx"() {
41686
+ "use strict";
41687
+ import_react28 = __toESM(require_react());
41688
+ await init_build2();
41689
+ init_usePipWrapper();
41690
+ await init_Spinner();
41691
+ await init_ResultsView();
41692
+ await init_ConfirmPrompt();
41693
+ await init_ErrorView();
41694
+ import_jsx_runtime9 = __toESM(require_jsx_runtime());
41695
+ PipWrapperApp = ({
41696
+ pipArgs,
41697
+ config
41698
+ }) => {
41699
+ const { state, confirmInstall, rejectInstall } = usePipWrapper(pipArgs, config);
41700
+ const { exit } = use_app_default();
41701
+ (0, import_react28.useEffect)(() => {
41702
+ if (state.phase === "done") {
41703
+ process.exitCode = state.exitCode;
41704
+ const timer = setTimeout(() => exit(), 0);
41705
+ return () => clearTimeout(timer);
41706
+ }
41707
+ if (state.phase === "trial_exhausted") {
41708
+ process.exitCode = 1;
41709
+ const timer = setTimeout(() => exit(), 0);
41710
+ return () => clearTimeout(timer);
41711
+ }
41712
+ if (state.phase === "passthrough") {
41713
+ }
41714
+ }, [state, exit]);
41715
+ const handleConfirm = (0, import_react28.useCallback)(() => {
41716
+ confirmInstall();
41717
+ }, [confirmInstall]);
41718
+ const handleReject = (0, import_react28.useCallback)(() => {
41719
+ rejectInstall();
41720
+ }, [rejectInstall]);
41721
+ switch (state.phase) {
41722
+ case "resolving":
41723
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41724
+ Spinner2,
41725
+ {
41726
+ label: `Resolving ${state.count} package${state.count !== 1 ? "s" : ""} from PyPI...`
41727
+ }
41728
+ );
41729
+ case "scanning":
41730
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41731
+ Spinner2,
41732
+ {
41733
+ label: `Scanning ${state.count} Python package${state.count !== 1 ? "s" : ""}...`
41734
+ }
41735
+ );
41736
+ case "pass":
41737
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "green", children: [
41738
+ "\u2713",
41739
+ " ",
41740
+ state.count,
41741
+ " package",
41742
+ state.count !== 1 ? "s" : "",
41743
+ " scanned",
41744
+ " \u2014 ",
41745
+ "all clear"
41746
+ ] });
41747
+ case "warn":
41748
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41749
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41750
+ ResultsView,
41751
+ {
41752
+ result: state.result,
41753
+ config,
41754
+ durationMs: state.result.durationMs
41755
+ }
41756
+ ),
41757
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", children: "Warnings detected. Proceeding with install..." })
41758
+ ] });
41759
+ case "blocked":
41760
+ if (state.dgForce) {
41761
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41762
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41763
+ ResultsView,
41764
+ {
41765
+ result: state.result,
41766
+ config,
41767
+ durationMs: state.result.durationMs
41768
+ }
41769
+ ),
41770
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "yellow", bold: true, children: "--dg-force: Bypassing block. Install at your own risk." })
41771
+ ] });
41772
+ }
41773
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", children: [
41774
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41775
+ ResultsView,
41776
+ {
41777
+ result: state.result,
41778
+ config,
41779
+ durationMs: state.result.durationMs
41780
+ }
41781
+ ),
41782
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "red", bold: true, children: [
41783
+ "BLOCKED:",
41784
+ " ",
41785
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "red", children: "High-risk packages detected." })
41786
+ ] }),
41787
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
41788
+ ConfirmPrompt,
41789
+ {
41790
+ message: "Proceed with install anyway?",
41791
+ onConfirm: handleConfirm,
41792
+ onReject: handleReject
41793
+ }
41794
+ )
41258
41795
  ] });
41796
+ case "installing":
41797
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Spinner2, { label: "Installing with pip..." });
41798
+ case "done":
41799
+ return null;
41800
+ case "error":
41801
+ if (state.proceed) {
41802
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { color: "yellow", children: [
41803
+ "Warning: Scan failed (",
41804
+ state.message,
41805
+ "). Proceeding with install."
41806
+ ] });
41807
+ }
41808
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ErrorView, { error: new Error(state.message) });
41809
+ case "passthrough":
41810
+ return null;
41811
+ case "trial_exhausted": {
41812
+ let hasKey = false;
41813
+ try {
41814
+ const { getStoredApiKey: getStoredApiKey2 } = (init_auth(), __toCommonJS(auth_exports));
41815
+ hasKey = !!getStoredApiKey2();
41816
+ } catch {
41817
+ }
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: [
41821
+ "Run ",
41822
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg logout" }),
41823
+ " then ",
41824
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41825
+ " to re-authenticate."
41826
+ ] })
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: [
41830
+ "Run ",
41831
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
41832
+ " to create a free account and continue scanning."
41833
+ ] })
41834
+ ] }) });
41835
+ }
41259
41836
  }
41260
41837
  };
41261
41838
  }
41262
41839
  });
41263
41840
 
41264
41841
  // src/ui/hooks/useScan.ts
41265
- function reducer3(_state, action) {
41842
+ function reducer4(_state, action) {
41266
41843
  switch (action.type) {
41267
41844
  case "PROJECTS_FOUND":
41268
41845
  return { phase: "selecting", projects: action.projects };
@@ -41283,10 +41860,10 @@ function reducer3(_state, action) {
41283
41860
  }
41284
41861
  }
41285
41862
  function useScan(config) {
41286
- const [state, dispatch] = (0, import_react27.useReducer)(reducer3, { phase: "discovering" });
41287
- const started = (0, import_react27.useRef)(false);
41288
- const [multiProjects, setMultiProjects] = (0, import_react27.useState)(null);
41289
- (0, import_react27.useEffect)(() => {
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)(() => {
41290
41867
  if (started.current) return;
41291
41868
  started.current = true;
41292
41869
  const projects = discoverProjects(process.cwd());
@@ -41297,10 +41874,9 @@ function useScan(config) {
41297
41874
  }
41298
41875
  try {
41299
41876
  const discovery = discoverChanges(process.cwd(), config);
41300
- const packages = discovery.packages.filter((p) => !config.allowlist.includes(p.name.toLowerCase()));
41877
+ const packages = discovery.packages;
41301
41878
  if (packages.length === 0) {
41302
- const message = discovery.packages.length === 0 ? "No package changes detected." : "All changed packages are allowlisted.";
41303
- dispatch({ type: "DISCOVERY_EMPTY", message });
41879
+ dispatch({ type: "DISCOVERY_EMPTY", message: "No package changes detected." });
41304
41880
  return;
41305
41881
  }
41306
41882
  dispatch({ type: "DISCOVERY_COMPLETE", packages, skippedCount: discovery.skipped.length });
@@ -41314,11 +41890,11 @@ function useScan(config) {
41314
41890
  scanProjects(projects, config, dispatch);
41315
41891
  }
41316
41892
  }, [config]);
41317
- const scanSelectedProjects = (0, import_react27.useCallback)((projects) => {
41893
+ const scanSelectedProjects = (0, import_react29.useCallback)((projects) => {
41318
41894
  dispatch({ type: "DISCOVERY_COMPLETE", packages: [], skippedCount: 0 });
41319
41895
  scanProjects(projects, config, dispatch);
41320
41896
  }, [config]);
41321
- const restartSelection = (0, import_react27.useCallback)(() => {
41897
+ const restartSelection = (0, import_react29.useCallback)(() => {
41322
41898
  if (!multiProjects) return;
41323
41899
  dispatch({ type: "RESTART_SELECTION", projects: multiProjects });
41324
41900
  }, [multiProjects]);
@@ -41359,7 +41935,7 @@ async function scanProjects(projects, config, dispatch) {
41359
41935
  const discovery = discoverChanges(proj.path, fullScanConfig);
41360
41936
  for (const pkg of discovery.packages) {
41361
41937
  const key = `${pkg.name}@${pkg.version}`;
41362
- if (!config.allowlist.includes(pkg.name.toLowerCase()) && !seenNpm.has(key)) {
41938
+ if (!seenNpm.has(key)) {
41363
41939
  seenNpm.add(key);
41364
41940
  npmPackages.push(pkg);
41365
41941
  }
@@ -41372,7 +41948,7 @@ async function scanProjects(projects, config, dispatch) {
41372
41948
  const packages = parsePythonDepFile(proj.path, proj.depFile);
41373
41949
  for (const pkg of packages) {
41374
41950
  const key = `${pkg.name}@${pkg.version}`;
41375
- if (!config.allowlist.includes(pkg.name.toLowerCase()) && !seenPypi.has(key)) {
41951
+ if (!seenPypi.has(key)) {
41376
41952
  seenPypi.add(key);
41377
41953
  pypiPackages.push(pkg);
41378
41954
  }
@@ -41421,7 +41997,7 @@ async function scanProjects(projects, config, dispatch) {
41421
41997
  }
41422
41998
  const allPackages = results.flatMap((r) => r.packages);
41423
41999
  const maxScore = Math.max(0, ...allPackages.map((p) => p.score));
41424
- const action = maxScore >= config.blockThreshold ? "block" : maxScore >= config.warnThreshold ? "warn" : "pass";
42000
+ const action = maxScore >= 70 ? "block" : maxScore >= 60 ? "warn" : "pass";
41425
42001
  const safeVersions = {};
41426
42002
  for (const r of results) Object.assign(safeVersions, r.safeVersions);
41427
42003
  const merged = {
@@ -41440,11 +42016,11 @@ async function scanProjects(projects, config, dispatch) {
41440
42016
  dispatch({ type: "ERROR", error: error instanceof Error ? error : new Error(String(error)) });
41441
42017
  }
41442
42018
  }
41443
- var import_react27;
42019
+ var import_react29;
41444
42020
  var init_useScan = __esm({
41445
42021
  "src/ui/hooks/useScan.ts"() {
41446
42022
  "use strict";
41447
- import_react27 = __toESM(require_react());
42023
+ import_react29 = __toESM(require_react());
41448
42024
  init_lockfile();
41449
42025
  init_api();
41450
42026
  init_discover();
@@ -41454,7 +42030,7 @@ var init_useScan = __esm({
41454
42030
 
41455
42031
  // src/ui/components/ProgressBar.tsx
41456
42032
  function estimateScanSeconds(packageCount) {
41457
- return Math.ceil(8 + packageCount * 0.12);
42033
+ return Math.ceil(Math.max(5, packageCount * 0.35 - 10));
41458
42034
  }
41459
42035
  function formatTime(seconds) {
41460
42036
  if (seconds < 60) return `${seconds}s`;
@@ -41462,23 +42038,23 @@ function formatTime(seconds) {
41462
42038
  const s = seconds % 60;
41463
42039
  return s > 0 ? `${m}m ${s}s` : `${m}m`;
41464
42040
  }
41465
- var import_react28, import_chalk9, import_jsx_runtime9, ProgressBar;
42041
+ var import_react30, import_chalk9, import_jsx_runtime10, ProgressBar;
41466
42042
  var init_ProgressBar = __esm({
41467
42043
  async "src/ui/components/ProgressBar.tsx"() {
41468
42044
  "use strict";
41469
- import_react28 = __toESM(require_react());
42045
+ import_react30 = __toESM(require_react());
41470
42046
  await init_build2();
41471
42047
  await init_build3();
41472
42048
  import_chalk9 = __toESM(require_source());
41473
- import_jsx_runtime9 = __toESM(require_jsx_runtime());
42049
+ import_jsx_runtime10 = __toESM(require_jsx_runtime());
41474
42050
  ProgressBar = ({
41475
42051
  value,
41476
42052
  total,
41477
42053
  label
41478
42054
  }) => {
41479
- const startRef = (0, import_react28.useRef)(Date.now());
41480
- const [elapsed, setElapsed] = (0, import_react28.useState)(0);
41481
- (0, import_react28.useEffect)(() => {
42055
+ const startRef = (0, import_react30.useRef)(Date.now());
42056
+ const [elapsed, setElapsed] = (0, import_react30.useState)(0);
42057
+ (0, import_react30.useEffect)(() => {
41482
42058
  const timer = setInterval(() => {
41483
42059
  setElapsed(Math.floor((Date.now() - startRef.current) / 1e3));
41484
42060
  }, 1e3);
@@ -41495,32 +42071,32 @@ var init_ProgressBar = __esm({
41495
42071
  const empty = barWidth - filled;
41496
42072
  const filledBar = "\u2501".repeat(filled);
41497
42073
  const emptyBar = "\u2501".repeat(empty);
41498
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
41499
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
42074
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
42075
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41500
42076
  import_chalk9.default.cyan("\u25C6"),
41501
42077
  " ",
41502
42078
  import_chalk9.default.bold("Dependency Guardian")
41503
42079
  ] }),
41504
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: "" }),
41505
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
41506
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "cyan", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(build_default, { type: "dots" }) }),
41507
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
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: [
41508
42084
  " Scanning ",
41509
42085
  total,
41510
42086
  " packages... "
41511
42087
  ] }),
41512
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { dimColor: true, children: timeInfo })
42088
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: timeInfo })
41513
42089
  ] }),
41514
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box_default, { children: [
41515
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { children: " " }),
41516
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { color: "green", children: filledBar }),
41517
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Text, { dimColor: true, children: emptyBar }),
41518
- /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { children: [
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: [
41519
42095
  " ",
41520
42096
  counter
41521
42097
  ] })
41522
42098
  ] }),
41523
- label && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Text, { dimColor: true, children: [
42099
+ label && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41524
42100
  " ",
41525
42101
  import_chalk9.default.dim("\u203A"),
41526
42102
  " ",
@@ -41533,9 +42109,9 @@ var init_ProgressBar = __esm({
41533
42109
 
41534
42110
  // src/ui/hooks/useExpandAnimation.ts
41535
42111
  function useExpandAnimation(targetHeight, active, durationMs = 180) {
41536
- const [visibleLines, setVisibleLines] = (0, import_react29.useState)(0);
41537
- const timerRef = (0, import_react29.useRef)(null);
41538
- (0, import_react29.useEffect)(() => {
42112
+ const [visibleLines, setVisibleLines] = (0, import_react31.useState)(0);
42113
+ const timerRef = (0, import_react31.useRef)(null);
42114
+ (0, import_react31.useEffect)(() => {
41539
42115
  if (timerRef.current) {
41540
42116
  clearInterval(timerRef.current);
41541
42117
  timerRef.current = null;
@@ -41569,22 +42145,22 @@ function useExpandAnimation(targetHeight, active, durationMs = 180) {
41569
42145
  isAnimating: active && visibleLines > 0 && visibleLines < targetHeight
41570
42146
  };
41571
42147
  }
41572
- var import_react29;
42148
+ var import_react31;
41573
42149
  var init_useExpandAnimation = __esm({
41574
42150
  "src/ui/hooks/useExpandAnimation.ts"() {
41575
42151
  "use strict";
41576
- import_react29 = __toESM(require_react());
42152
+ import_react31 = __toESM(require_react());
41577
42153
  }
41578
42154
  });
41579
42155
 
41580
42156
  // src/ui/hooks/useTerminalSize.ts
41581
42157
  function useTerminalSize() {
41582
42158
  const { stdout } = use_stdout_default();
41583
- const [size, setSize] = (0, import_react30.useState)({
42159
+ const [size, setSize] = (0, import_react32.useState)({
41584
42160
  rows: stdout?.rows ?? process.stdout.rows ?? 24,
41585
42161
  cols: stdout?.columns ?? process.stdout.columns ?? 80
41586
42162
  });
41587
- (0, import_react30.useEffect)(() => {
42163
+ (0, import_react32.useEffect)(() => {
41588
42164
  const handle = () => {
41589
42165
  const rows = process.stdout.rows ?? 24;
41590
42166
  const cols = process.stdout.columns ?? 80;
@@ -41602,11 +42178,11 @@ function useTerminalSize() {
41602
42178
  }, []);
41603
42179
  return size;
41604
42180
  }
41605
- var import_react30;
42181
+ var import_react32;
41606
42182
  var init_useTerminalSize = __esm({
41607
42183
  async "src/ui/hooks/useTerminalSize.ts"() {
41608
42184
  "use strict";
41609
- import_react30 = __toESM(require_react());
42185
+ import_react32 = __toESM(require_react());
41610
42186
  await init_build2();
41611
42187
  }
41612
42188
  });
@@ -41622,10 +42198,10 @@ function groupPackages3(packages) {
41622
42198
  }
41623
42199
  return [...map.entries()].map(([fingerprint, pkgs]) => ({ packages: pkgs, key: fingerprint })).sort((a, b) => b.packages[0].score - a.packages[0].score);
41624
42200
  }
41625
- function actionBadge3(score, config) {
41626
- if (score >= config.blockThreshold)
42201
+ function actionBadge3(score) {
42202
+ if (score >= 70)
41627
42203
  return { label: "BLOCK", color: import_chalk10.default.red };
41628
- if (score >= config.warnThreshold)
42204
+ if (score >= 60)
41629
42205
  return { label: "WARN", color: import_chalk10.default.yellow };
41630
42206
  return { label: "PASS", color: import_chalk10.default.green };
41631
42207
  }
@@ -41639,6 +42215,7 @@ function findingsSummaryHeight(group) {
41639
42215
  const rep = group.packages[0];
41640
42216
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical);
41641
42217
  let h = visibleFindings.length;
42218
+ if (rep.license) h += 1;
41642
42219
  if (visibleFindings.length === 0 && rep.score > 0) {
41643
42220
  h += (rep.reasons ?? []).length;
41644
42221
  h += 1;
@@ -41650,6 +42227,7 @@ function findingsDetailHeight(group, safeVersions) {
41650
42227
  const rep = group.packages[0];
41651
42228
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
41652
42229
  let h = 0;
42230
+ if (rep.license) h += 1;
41653
42231
  if (group.packages.length > 3) h += 1;
41654
42232
  if (visibleFindings.length === 0 && rep.score > 0) {
41655
42233
  h += (rep.reasons ?? []).length;
@@ -41691,88 +42269,26 @@ function buildDetailLines(group, safeVersion, maxWidth) {
41691
42269
  const evidenceWidth = Math.max(30, maxWidth - 12);
41692
42270
  if (group.packages.length > 3) {
41693
42271
  lines.push(
41694
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42272
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
41695
42273
  "Affects: ",
41696
42274
  affectsLine(group)
41697
42275
  ] }, "affects")
41698
42276
  );
41699
- lines.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }, "affects-gap"));
42277
+ lines.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }, "affects-gap"));
41700
42278
  }
41701
- if (visibleFindings.length === 0 && rep.score > 0) {
41702
- const reasons = rep.reasons ?? [];
41703
- for (let i = 0; i < reasons.length; i++) {
41704
- lines.push(
41705
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: truncate3(reasons[i], maxWidth - 4) }, `reason-${i}`)
41706
- );
41707
- }
42279
+ if (rep.score > 0) {
41708
42280
  lines.push(
41709
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41710
- import_chalk10.default.yellow("\u2192"),
41711
- " ",
41712
- import_chalk10.default.yellow("Upgrade to Pro"),
41713
- " ",
41714
- import_chalk10.default.dim("to see finding details \u2014 dg login")
41715
- ] }, "upgrade")
41716
- );
41717
- return lines;
41718
- }
41719
- const hasEvidence = visibleFindings.some((f) => f.evidence && f.evidence.length > 0);
41720
- for (let idx = 0; idx < visibleFindings.length; idx++) {
41721
- const finding = visibleFindings[idx];
41722
- const sevLabel = SEVERITY_LABELS3[finding.severity] ?? "INFO";
41723
- const sevColor = SEVERITY_COLORS[finding.severity] ?? SEVERITY_COLORS[1];
41724
- const evidence = finding.evidence ?? [];
41725
- const findingId = finding.id ?? finding.category ?? "";
41726
- if (idx > 0) lines.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }, `gap-${idx}`));
41727
- lines.push(
41728
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41729
- sevColor(pad3(sevLabel, 5)),
41730
- " ",
41731
- findingId
41732
- ] }, `${findingId}-${idx}-badge`)
41733
- );
41734
- lines.push(
41735
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41736
- " ",
41737
- finding.title
41738
- ] }, `${findingId}-${idx}-title`)
41739
- );
41740
- const evidenceCap = Math.min(evidence.length, DETAIL_EVIDENCE_LIMIT);
41741
- for (let i = 0; i < evidenceCap; i++) {
41742
- lines.push(
41743
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41744
- " ",
41745
- import_chalk10.default.dim("\u203A"),
41746
- " ",
41747
- truncate3(evidence[i], evidenceWidth)
41748
- ] }, `${findingId}-${idx}-ev-${i}`)
41749
- );
41750
- }
41751
- if (evidence.length > DETAIL_EVIDENCE_LIMIT) {
41752
- lines.push(
41753
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
41754
- " ",
41755
- import_chalk10.default.dim(`+${evidence.length - DETAIL_EVIDENCE_LIMIT} more`)
41756
- ] }, `${findingId}-${idx}-overflow`)
41757
- );
41758
- }
41759
- }
41760
- if (visibleFindings.length > 0 && !hasEvidence) {
41761
- lines.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }, "upgrade-gap"));
41762
- lines.push(
41763
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
41764
- import_chalk10.default.yellow("\u2192"),
41765
- " ",
41766
- import_chalk10.default.yellow("Upgrade to Team"),
41767
- " ",
41768
- import_chalk10.default.dim("for evidence and file locations")
41769
- ] }, "upgrade-evidence")
42281
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42282
+ "Score: ",
42283
+ rep.score,
42284
+ "/100"
42285
+ ] }, "score-info")
41770
42286
  );
41771
42287
  }
41772
42288
  if (rep.recommendation) {
41773
- lines.push(/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }, "rec-gap"));
42289
+ lines.push(/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }, "rec-gap"));
41774
42290
  lines.push(
41775
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42291
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
41776
42292
  import_chalk10.default.dim("Rec:"),
41777
42293
  " ",
41778
42294
  import_chalk10.default.cyan(truncate3(rep.recommendation, maxWidth - 8))
@@ -41781,7 +42297,7 @@ function buildDetailLines(group, safeVersion, maxWidth) {
41781
42297
  }
41782
42298
  if (safeVersion) {
41783
42299
  lines.push(
41784
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: import_chalk10.default.green(`Safe: ${rep.name}@${safeVersion}`) }, "safe")
42300
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: import_chalk10.default.green(`Safe: ${rep.name}@${safeVersion}`) }, "safe")
41785
42301
  );
41786
42302
  }
41787
42303
  return lines;
@@ -41796,18 +42312,34 @@ function viewReducer(_state, action) {
41796
42312
  return { cursor: action.cursor, expandedIndex: action.expandedIndex, expandLevel: action.expandLevel, viewport: action.viewport };
41797
42313
  }
41798
42314
  }
41799
- var import_react31, import_chalk10, import_jsx_runtime10, SEVERITY_LABELS3, SEVERITY_COLORS, EVIDENCE_LIMIT2, FIXED_CHROME, DETAIL_PANE_CHROME, DETAIL_EVIDENCE_LIMIT, InteractiveResultsView, T, FindingsSummary;
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;
41800
42332
  var init_InteractiveResultsView = __esm({
41801
42333
  async "src/ui/components/InteractiveResultsView.tsx"() {
41802
42334
  "use strict";
41803
- import_react31 = __toESM(require_react());
42335
+ import_react33 = __toESM(require_react());
41804
42336
  await init_build2();
41805
42337
  import_chalk10 = __toESM(require_source());
41806
42338
  await init_ScoreHeader();
41807
42339
  init_useExpandAnimation();
41808
42340
  await init_useTerminalSize();
41809
- import_jsx_runtime10 = __toESM(require_jsx_runtime());
41810
- SEVERITY_LABELS3 = {
42341
+ import_jsx_runtime11 = __toESM(require_jsx_runtime());
42342
+ SEVERITY_LABELS2 = {
41811
42343
  5: "CRIT",
41812
42344
  4: "HIGH",
41813
42345
  3: "MED",
@@ -41824,7 +42356,6 @@ var init_InteractiveResultsView = __esm({
41824
42356
  EVIDENCE_LIMIT2 = 2;
41825
42357
  FIXED_CHROME = 21;
41826
42358
  DETAIL_PANE_CHROME = 20;
41827
- DETAIL_EVIDENCE_LIMIT = 10;
41828
42359
  InteractiveResultsView = ({
41829
42360
  result,
41830
42361
  config,
@@ -41833,24 +42364,24 @@ var init_InteractiveResultsView = __esm({
41833
42364
  onBack,
41834
42365
  discoveredTotal
41835
42366
  }) => {
41836
- const flagged = (0, import_react31.useMemo)(
42367
+ const flagged = (0, import_react33.useMemo)(
41837
42368
  () => result.packages.filter((p) => p.score > 0),
41838
42369
  [result.packages]
41839
42370
  );
41840
- const clean = (0, import_react31.useMemo)(
42371
+ const clean = (0, import_react33.useMemo)(
41841
42372
  () => result.packages.filter((p) => p.score === 0),
41842
42373
  [result.packages]
41843
42374
  );
41844
42375
  const total = result.packages.length;
41845
- const [searchQuery, setSearchQuery] = (0, import_react31.useState)("");
41846
- const allGroups = (0, import_react31.useMemo)(() => groupPackages3(flagged), [flagged]);
42376
+ const [searchQuery, setSearchQuery] = (0, import_react33.useState)("");
42377
+ const allGroups = (0, import_react33.useMemo)(() => groupPackages3(flagged), [flagged]);
41847
42378
  const allGroupCount = allGroups.length;
41848
- const groups = (0, import_react31.useMemo)(() => {
42379
+ const groups = (0, import_react33.useMemo)(() => {
41849
42380
  if (!searchQuery) return allGroups;
41850
42381
  const q = searchQuery.toLowerCase();
41851
42382
  return allGroups.filter((g) => g.packages.some((p) => p.name.toLowerCase().includes(q)));
41852
42383
  }, [allGroups, searchQuery]);
41853
- const severityCounts = (0, import_react31.useMemo)(() => {
42384
+ const severityCounts = (0, import_react33.useMemo)(() => {
41854
42385
  const counts = {};
41855
42386
  for (const pkg of flagged) {
41856
42387
  const maxSev = pkg.findings.reduce((m, f) => Math.max(m, f.severity), 0);
@@ -41858,28 +42389,28 @@ var init_InteractiveResultsView = __esm({
41858
42389
  }
41859
42390
  return counts;
41860
42391
  }, [flagged]);
41861
- const [view, dispatchView] = (0, import_react31.useReducer)(viewReducer, {
42392
+ const [view, dispatchView] = (0, import_react33.useReducer)(viewReducer, {
41862
42393
  cursor: 0,
41863
42394
  expandLevel: null,
41864
42395
  expandedIndex: null,
41865
42396
  viewport: 0
41866
42397
  });
41867
- const viewRef = (0, import_react31.useRef)(view);
42398
+ const viewRef = (0, import_react33.useRef)(view);
41868
42399
  viewRef.current = view;
41869
- const [detailPane, setDetailPane] = (0, import_react31.useState)(null);
41870
- const detailPaneRef = (0, import_react31.useRef)(detailPane);
42400
+ const [detailPane, setDetailPane] = (0, import_react33.useState)(null);
42401
+ const detailPaneRef = (0, import_react33.useRef)(detailPane);
41871
42402
  detailPaneRef.current = detailPane;
41872
- const [showHelp, setShowHelp] = (0, import_react31.useState)(false);
41873
- const showHelpRef = (0, import_react31.useRef)(showHelp);
42403
+ const [showHelp, setShowHelp] = (0, import_react33.useState)(false);
42404
+ const showHelpRef = (0, import_react33.useRef)(showHelp);
41874
42405
  showHelpRef.current = showHelp;
41875
- const [searchMode, setSearchMode] = (0, import_react31.useState)(false);
41876
- const searchModeRef = (0, import_react31.useRef)(searchMode);
42406
+ const [searchMode, setSearchMode] = (0, import_react33.useState)(false);
42407
+ const searchModeRef = (0, import_react33.useRef)(searchMode);
41877
42408
  searchModeRef.current = searchMode;
41878
42409
  const { rows: termRows, cols: termCols } = useTerminalSize();
41879
42410
  const availableRows = Math.max(5, termRows - FIXED_CHROME);
41880
42411
  const innerWidth = Math.max(40, termCols - 6);
41881
42412
  const detailGroupIdx = detailPane?.groupIndex ?? -1;
41882
- const detailLines = (0, import_react31.useMemo)(() => {
42413
+ const detailLines = (0, import_react33.useMemo)(() => {
41883
42414
  if (detailGroupIdx < 0) return [];
41884
42415
  const group = groups[detailGroupIdx];
41885
42416
  if (!group) return [];
@@ -41889,7 +42420,7 @@ var init_InteractiveResultsView = __esm({
41889
42420
  const getLevel = (idx) => {
41890
42421
  return view.expandedIndex === idx ? view.expandLevel : null;
41891
42422
  };
41892
- const expandTargetHeight = (0, import_react31.useMemo)(() => {
42423
+ const expandTargetHeight = (0, import_react33.useMemo)(() => {
41893
42424
  if (view.expandedIndex === null || view.expandLevel === null) return 0;
41894
42425
  const group = groups[view.expandedIndex];
41895
42426
  if (!group) return 0;
@@ -41905,7 +42436,7 @@ var init_InteractiveResultsView = __esm({
41905
42436
  if (idx === view.expandedIndex) return 1 + animVisibleLines;
41906
42437
  return groupRowHeight(group, level, result.safeVersions);
41907
42438
  };
41908
- const visibleEnd = (0, import_react31.useMemo)(() => {
42439
+ const visibleEnd = (0, import_react33.useMemo)(() => {
41909
42440
  let consumed = 0;
41910
42441
  let end = view.viewport;
41911
42442
  while (end < groups.length) {
@@ -41937,14 +42468,14 @@ var init_InteractiveResultsView = __esm({
41937
42468
  }
41938
42469
  return newStart;
41939
42470
  };
41940
- (0, import_react31.useEffect)(() => {
42471
+ (0, import_react33.useEffect)(() => {
41941
42472
  if (groups.length === 0) return;
41942
42473
  const { cursor, expandedIndex, expandLevel, viewport } = viewRef.current;
41943
42474
  const clamped = Math.min(viewport, Math.max(0, groups.length - 1));
41944
42475
  const newVp = adjustViewport(cursor, expandedIndex, expandLevel, clamped);
41945
42476
  dispatchView({ type: "MOVE", cursor, viewport: newVp });
41946
42477
  }, [availableRows]);
41947
- (0, import_react31.useEffect)(() => {
42478
+ (0, import_react33.useEffect)(() => {
41948
42479
  const dp = detailPaneRef.current;
41949
42480
  if (dp && detailLines.length > 0) {
41950
42481
  const maxScroll = Math.max(0, detailLines.length - detailContentRows);
@@ -41994,7 +42525,7 @@ var init_InteractiveResultsView = __esm({
41994
42525
  setDetailPane({ groupIndex: dp.groupIndex, scroll: 0 });
41995
42526
  } else if (input === "G") {
41996
42527
  setDetailPane({ groupIndex: dp.groupIndex, scroll: maxScroll });
41997
- } else if (input === "e" || input === "b" || key.escape) {
42528
+ } else if (input === " " || input === "e" || input === "b" || key.escape) {
41998
42529
  setDetailPane(null);
41999
42530
  } else if (input === "q") {
42000
42531
  onExit();
@@ -42042,7 +42573,7 @@ var init_InteractiveResultsView = __esm({
42042
42573
  }
42043
42574
  const newVp = adjustViewport(cursor, newExpIdx, newExpLvl, vpStart);
42044
42575
  dispatchView({ type: "EXPAND", expandedIndex: newExpIdx, expandLevel: newExpLvl, viewport: newVp });
42045
- } else if (input === "e") {
42576
+ } else if (input === " " || input === "e") {
42046
42577
  setDetailPane({ groupIndex: view.cursor, scroll: 0 });
42047
42578
  } else if (input === "/") {
42048
42579
  setSearchMode(true);
@@ -42055,12 +42586,13 @@ var init_InteractiveResultsView = __esm({
42055
42586
  const visibleGroups = groups.slice(view.viewport, visibleEnd);
42056
42587
  const aboveCount = view.viewport;
42057
42588
  const belowCount = groups.length - visibleEnd;
42058
- const nameCol = Math.max(20, innerWidth - 22);
42589
+ const lcCol = 16;
42590
+ const nameCol = Math.max(20, innerWidth - 22 - lcCol);
42059
42591
  const clampedCursor = groups.length > 0 ? Math.min(view.cursor, groups.length - 1) : 0;
42060
42592
  if (showHelp) {
42061
42593
  const isDetail = detailPane !== null;
42062
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42063
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
42594
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42595
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42064
42596
  ScoreHeader,
42065
42597
  {
42066
42598
  score: result.score,
@@ -42071,7 +42603,7 @@ var init_InteractiveResultsView = __esm({
42071
42603
  severityCounts
42072
42604
  }
42073
42605
  ),
42074
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
42606
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42075
42607
  Box_default,
42076
42608
  {
42077
42609
  flexDirection: "column",
@@ -42081,82 +42613,82 @@ var init_InteractiveResultsView = __esm({
42081
42613
  paddingRight: 2,
42082
42614
  width: "100%",
42083
42615
  children: [
42084
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { bold: true, children: [
42616
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { bold: true, children: [
42085
42617
  import_chalk10.default.cyan("\u25C6"),
42086
42618
  " Keyboard Shortcuts"
42087
42619
  ] }),
42088
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }),
42089
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { bold: true, children: " Navigation" }),
42090
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
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: [
42091
42623
  " ",
42092
42624
  import_chalk10.default.cyan("\u2191 k"),
42093
42625
  " ",
42094
42626
  import_chalk10.default.dim("Move up")
42095
42627
  ] }),
42096
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42628
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42097
42629
  " ",
42098
42630
  import_chalk10.default.cyan("\u2193 j"),
42099
42631
  " ",
42100
42632
  import_chalk10.default.dim("Move down")
42101
42633
  ] }),
42102
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42634
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42103
42635
  " ",
42104
42636
  import_chalk10.default.cyan("g"),
42105
42637
  " ",
42106
42638
  import_chalk10.default.dim("Jump to top")
42107
42639
  ] }),
42108
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42640
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42109
42641
  " ",
42110
42642
  import_chalk10.default.cyan("G"),
42111
42643
  " ",
42112
42644
  import_chalk10.default.dim("Jump to bottom")
42113
42645
  ] }),
42114
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42646
+ !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42115
42647
  " ",
42116
42648
  import_chalk10.default.cyan("PgUp"),
42117
42649
  " ",
42118
42650
  import_chalk10.default.dim("Page up")
42119
42651
  ] }),
42120
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42652
+ !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42121
42653
  " ",
42122
42654
  import_chalk10.default.cyan("PgDn"),
42123
42655
  " ",
42124
42656
  import_chalk10.default.dim("Page down")
42125
42657
  ] }),
42126
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }),
42127
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { bold: true, children: " Actions" }),
42128
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
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: [
42129
42661
  " ",
42130
42662
  import_chalk10.default.cyan("\u23CE"),
42131
42663
  " ",
42132
42664
  import_chalk10.default.dim("Toggle summary")
42133
42665
  ] }),
42134
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42666
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42667
+ " ",
42668
+ import_chalk10.default.cyan("space"),
42135
42669
  " ",
42136
- import_chalk10.default.cyan("e"),
42137
- " ",
42138
42670
  import_chalk10.default.dim(isDetail ? "Back to list" : "Open detail view")
42139
42671
  ] }),
42140
- !isDetail && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42672
+ !isDetail && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42141
42673
  " ",
42142
42674
  import_chalk10.default.cyan("/"),
42143
42675
  " ",
42144
42676
  import_chalk10.default.dim("Search packages")
42145
42677
  ] }),
42146
- !isDetail && onBack && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42678
+ !isDetail && onBack && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42147
42679
  " ",
42148
42680
  import_chalk10.default.cyan("b"),
42149
42681
  " ",
42150
42682
  import_chalk10.default.dim("Back to project selector")
42151
42683
  ] }),
42152
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42684
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42153
42685
  " ",
42154
42686
  import_chalk10.default.cyan("q"),
42155
42687
  " ",
42156
42688
  import_chalk10.default.dim("Quit")
42157
42689
  ] }),
42158
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: "" }),
42159
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42690
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42691
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42160
42692
  " Press ",
42161
42693
  import_chalk10.default.bold.cyan("?"),
42162
42694
  " or ",
@@ -42174,13 +42706,13 @@ var init_InteractiveResultsView = __esm({
42174
42706
  setDetailPane(null);
42175
42707
  } else {
42176
42708
  const dpRep = dpGroup.packages[0];
42177
- const { color: dpColor } = actionBadge3(dpRep.score, config);
42709
+ const { color: dpColor } = actionBadge3(dpRep.score);
42178
42710
  const dpScroll = detailPane.scroll;
42179
42711
  const dpAbove = dpScroll;
42180
42712
  const dpBelow = Math.max(0, detailLines.length - dpScroll - detailContentRows);
42181
42713
  const dpVisible = detailLines.slice(dpScroll, dpScroll + detailContentRows);
42182
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42183
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
42714
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42715
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42184
42716
  ScoreHeader,
42185
42717
  {
42186
42718
  score: result.score,
@@ -42191,7 +42723,7 @@ var init_InteractiveResultsView = __esm({
42191
42723
  severityCounts
42192
42724
  }
42193
42725
  ),
42194
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
42726
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42195
42727
  Box_default,
42196
42728
  {
42197
42729
  flexDirection: "column",
@@ -42201,18 +42733,21 @@ var init_InteractiveResultsView = __esm({
42201
42733
  paddingRight: 1,
42202
42734
  width: "100%",
42203
42735
  children: [
42204
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { justifyContent: "space-between", children: [
42205
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { bold: true, children: groupNames(dpGroup) }),
42206
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { children: dpColor(`score ${dpRep.score}`) })
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}`) })
42207
42742
  ] }),
42208
- dpAbove > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42743
+ dpAbove > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42209
42744
  import_chalk10.default.cyan(" \u2191"),
42210
42745
  " ",
42211
42746
  dpAbove,
42212
42747
  " more above"
42213
42748
  ] }),
42214
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: dpVisible }),
42215
- dpBelow > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
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: [
42216
42751
  import_chalk10.default.cyan(" \u2193"),
42217
42752
  " ",
42218
42753
  dpBelow,
@@ -42221,7 +42756,7 @@ var init_InteractiveResultsView = __esm({
42221
42756
  ]
42222
42757
  }
42223
42758
  ),
42224
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
42759
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42225
42760
  Box_default,
42226
42761
  {
42227
42762
  flexDirection: "column",
@@ -42231,36 +42766,31 @@ var init_InteractiveResultsView = __esm({
42231
42766
  paddingRight: 1,
42232
42767
  width: "100%",
42233
42768
  children: [
42234
- clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42769
+ clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42235
42770
  import_chalk10.default.green("\u2713"),
42236
42771
  " ",
42237
42772
  import_chalk10.default.green.bold(String(clean.length)),
42238
42773
  " ",
42239
42774
  import_chalk10.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
42240
42775
  ] }),
42241
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { justifyContent: "space-between", children: [
42242
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42776
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { justifyContent: "space-between", children: [
42777
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42243
42778
  (durationMs / 1e3).toFixed(1),
42244
42779
  "s"
42245
42780
  ] }),
42246
- result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42247
- result.trialScansRemaining,
42248
- " free scan",
42249
- result.trialScansRemaining !== 1 ? "s" : "",
42250
- " remaining"
42251
- ] })
42781
+ result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: "Free tier \xB7 dg login for finding details" })
42252
42782
  ] })
42253
42783
  ]
42254
42784
  }
42255
42785
  ),
42256
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: import_chalk10.default.dim("\u2500".repeat(Math.min(60, termCols - 4))) }),
42257
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
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: [
42258
42788
  " ",
42259
42789
  import_chalk10.default.bold.cyan("\u2191\u2193"),
42260
42790
  " ",
42261
42791
  import_chalk10.default.dim("scroll"),
42262
42792
  " ",
42263
- import_chalk10.default.bold.cyan("e"),
42793
+ import_chalk10.default.bold.cyan("space"),
42264
42794
  " ",
42265
42795
  import_chalk10.default.dim("back"),
42266
42796
  " ",
@@ -42271,8 +42801,8 @@ var init_InteractiveResultsView = __esm({
42271
42801
  ] });
42272
42802
  }
42273
42803
  }
42274
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42275
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
42804
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", children: [
42805
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42276
42806
  ScoreHeader,
42277
42807
  {
42278
42808
  score: result.score,
@@ -42283,7 +42813,7 @@ var init_InteractiveResultsView = __esm({
42283
42813
  severityCounts
42284
42814
  }
42285
42815
  ),
42286
- groups.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
42816
+ groups.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42287
42817
  Box_default,
42288
42818
  {
42289
42819
  flexDirection: "column",
@@ -42293,11 +42823,11 @@ var init_InteractiveResultsView = __esm({
42293
42823
  paddingRight: 1,
42294
42824
  width: "100%",
42295
42825
  children: [
42296
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { justifyContent: "space-between", children: [
42297
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { bold: true, children: "Flagged Packages" }),
42298
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: searchQuery ? `${groups.length} of ${allGroupCount}` : `${clampedCursor + 1}/${groups.length}` })
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}` })
42299
42829
  ] }),
42300
- aboveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42830
+ aboveCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42301
42831
  import_chalk10.default.cyan(" \u2191"),
42302
42832
  " ",
42303
42833
  aboveCount,
@@ -42308,24 +42838,29 @@ var init_InteractiveResultsView = __esm({
42308
42838
  const isCursor = globalIdx === clampedCursor;
42309
42839
  const level = getLevel(globalIdx);
42310
42840
  const rep = group.packages[0];
42311
- const { label, color } = actionBadge3(rep.score, config);
42841
+ const { label, color } = actionBadge3(rep.score);
42312
42842
  const names = groupNames(group);
42313
42843
  const chevron = level !== null ? "\u25BE" : "\u25B8";
42314
42844
  const scoreStr = String(rep.score);
42315
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { flexDirection: "column", children: [
42316
- isCursor ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
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: [
42317
42850
  import_chalk10.default.cyan("\u258C"),
42318
42851
  ` ${chevron} `,
42319
42852
  color(pad3(label, 6)),
42320
42853
  import_chalk10.default.bold(pad3(truncate3(names, nameCol - 2), nameCol)),
42854
+ lcColor(pad3(lcStr, lcCol)),
42321
42855
  color(scoreStr.padStart(3))
42322
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42856
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42323
42857
  ` ${import_chalk10.default.dim(chevron)} `,
42324
42858
  color(pad3(label, 6)),
42325
42859
  pad3(truncate3(names, nameCol - 2), nameCol),
42860
+ lcColor(pad3(lcStr, lcCol)),
42326
42861
  color(scoreStr.padStart(3))
42327
42862
  ] }),
42328
- level === "summary" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
42863
+ level === "summary" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
42329
42864
  FindingsSummary,
42330
42865
  {
42331
42866
  group,
@@ -42335,7 +42870,7 @@ var init_InteractiveResultsView = __esm({
42335
42870
  )
42336
42871
  ] }, group.key);
42337
42872
  }),
42338
- belowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42873
+ belowCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42339
42874
  import_chalk10.default.cyan(" \u2193"),
42340
42875
  " ",
42341
42876
  belowCount,
@@ -42344,7 +42879,7 @@ var init_InteractiveResultsView = __esm({
42344
42879
  ]
42345
42880
  }
42346
42881
  ),
42347
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
42882
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
42348
42883
  Box_default,
42349
42884
  {
42350
42885
  flexDirection: "column",
@@ -42354,14 +42889,14 @@ var init_InteractiveResultsView = __esm({
42354
42889
  paddingRight: 1,
42355
42890
  width: "100%",
42356
42891
  children: [
42357
- clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42892
+ clean.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42358
42893
  import_chalk10.default.green("\u2713"),
42359
42894
  " ",
42360
42895
  import_chalk10.default.green.bold(String(clean.length)),
42361
42896
  " ",
42362
42897
  import_chalk10.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
42363
42898
  ] }),
42364
- discoveredTotal !== void 0 && discoveredTotal > total && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42899
+ discoveredTotal !== void 0 && discoveredTotal > total && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42365
42900
  "Scanned ",
42366
42901
  total,
42367
42902
  " of ",
@@ -42369,23 +42904,18 @@ var init_InteractiveResultsView = __esm({
42369
42904
  " packages ",
42370
42905
  import_chalk10.default.dim("\u2014 dg login for full scans")
42371
42906
  ] }),
42372
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Box_default, { justifyContent: "space-between", children: [
42373
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42907
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { justifyContent: "space-between", children: [
42908
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42374
42909
  (durationMs / 1e3).toFixed(1),
42375
42910
  "s"
42376
42911
  ] }),
42377
- result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42378
- result.trialScansRemaining,
42379
- " free scan",
42380
- result.trialScansRemaining !== 1 ? "s" : "",
42381
- " remaining"
42382
- ] })
42912
+ result.trialScansRemaining !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { dimColor: true, children: "Free tier \xB7 dg login for finding details" })
42383
42913
  ] })
42384
42914
  ]
42385
42915
  }
42386
42916
  ),
42387
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Text, { dimColor: true, children: import_chalk10.default.dim("\u2500".repeat(Math.min(60, termCols - 4))) }),
42388
- searchMode ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
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: [
42389
42919
  " ",
42390
42920
  import_chalk10.default.bold.cyan("/"),
42391
42921
  " ",
@@ -42393,9 +42923,9 @@ var init_InteractiveResultsView = __esm({
42393
42923
  import_chalk10.default.cyan("\u2588"),
42394
42924
  " ",
42395
42925
  import_chalk10.default.dim("Esc clear")
42396
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
42926
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42397
42927
  " ",
42398
- groups.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
42928
+ groups.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
42399
42929
  import_chalk10.default.bold.cyan("\u2191\u2193"),
42400
42930
  " ",
42401
42931
  import_chalk10.default.dim("navigate"),
@@ -42404,7 +42934,7 @@ var init_InteractiveResultsView = __esm({
42404
42934
  " ",
42405
42935
  import_chalk10.default.dim("toggle"),
42406
42936
  " ",
42407
- import_chalk10.default.bold.cyan("e"),
42937
+ import_chalk10.default.bold.cyan("space"),
42408
42938
  " ",
42409
42939
  import_chalk10.default.dim("detail"),
42410
42940
  " ",
@@ -42416,7 +42946,7 @@ var init_InteractiveResultsView = __esm({
42416
42946
  " ",
42417
42947
  import_chalk10.default.dim("help"),
42418
42948
  " ",
42419
- onBack && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
42949
+ onBack && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
42420
42950
  import_chalk10.default.bold.cyan("b"),
42421
42951
  " ",
42422
42952
  import_chalk10.default.dim("back"),
@@ -42425,7 +42955,7 @@ var init_InteractiveResultsView = __esm({
42425
42955
  import_chalk10.default.bold.cyan("q"),
42426
42956
  " ",
42427
42957
  import_chalk10.default.dim("quit")
42428
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
42958
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
42429
42959
  "Press ",
42430
42960
  import_chalk10.default.bold.cyan("q"),
42431
42961
  " or ",
@@ -42442,16 +42972,28 @@ var init_InteractiveResultsView = __esm({
42442
42972
  pipe: import_chalk10.default.dim("\u2502"),
42443
42973
  blank: " "
42444
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
+ };
42445
42985
  FindingsSummary = ({ group, maxWidth, maxLines }) => {
42446
42986
  const rep = group.packages[0];
42447
42987
  const visibleFindings = rep.findings.filter((f) => f.severity > 1 || f.critical).sort((a, b) => b.severity - a.severity);
42448
42988
  const hasAffects = group.packages.length > 3;
42449
42989
  const allLines = [];
42990
+ const lcLine = licenseLine(rep);
42991
+ if (lcLine) allLines.push(lcLine);
42450
42992
  if (visibleFindings.length === 0 && rep.score > 0) {
42451
42993
  const reasons = rep.reasons ?? [];
42452
42994
  for (let i = 0; i < reasons.length; i++) {
42453
42995
  allLines.push(
42454
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
42996
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42455
42997
  i < reasons.length - 1 || hasAffects ? T.branch : T.branch,
42456
42998
  " ",
42457
42999
  truncate3(reasons[i], maxWidth - 8)
@@ -42459,7 +43001,7 @@ var init_InteractiveResultsView = __esm({
42459
43001
  );
42460
43002
  }
42461
43003
  allLines.push(
42462
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
43004
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42463
43005
  import_chalk10.default.yellow(" \u2192"),
42464
43006
  " ",
42465
43007
  import_chalk10.default.yellow("Upgrade to Pro"),
@@ -42472,10 +43014,10 @@ var init_InteractiveResultsView = __esm({
42472
43014
  const f = visibleFindings[idx];
42473
43015
  const isLast = !hasAffects && idx === visibleFindings.length - 1;
42474
43016
  const connector = isLast ? T.last : T.branch;
42475
- const sevLabel = SEVERITY_LABELS3[f.severity] ?? "INFO";
43017
+ const sevLabel = SEVERITY_LABELS2[f.severity] ?? "INFO";
42476
43018
  const sevColor = SEVERITY_COLORS[f.severity] ?? SEVERITY_COLORS[1];
42477
43019
  allLines.push(
42478
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { children: [
43020
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
42479
43021
  connector,
42480
43022
  " ",
42481
43023
  sevColor(pad3(sevLabel, 5)),
@@ -42486,7 +43028,7 @@ var init_InteractiveResultsView = __esm({
42486
43028
  }
42487
43029
  if (hasAffects) {
42488
43030
  allLines.push(
42489
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(Text, { dimColor: true, children: [
43031
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { dimColor: true, children: [
42490
43032
  T.last,
42491
43033
  " ",
42492
43034
  truncate3(affectsLine(group), maxWidth - 8)
@@ -42494,24 +43036,24 @@ var init_InteractiveResultsView = __esm({
42494
43036
  );
42495
43037
  }
42496
43038
  const linesToShow = maxLines !== void 0 ? allLines.slice(0, maxLines) : allLines;
42497
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box_default, { flexDirection: "column", marginLeft: 5, children: linesToShow });
43039
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Box_default, { flexDirection: "column", marginLeft: 5, children: linesToShow });
42498
43040
  };
42499
43041
  }
42500
43042
  });
42501
43043
 
42502
43044
  // src/ui/components/ProjectSelector.tsx
42503
- var import_react32, import_chalk11, import_jsx_runtime11, ProjectSelector;
43045
+ var import_react34, import_chalk11, import_jsx_runtime12, ProjectSelector;
42504
43046
  var init_ProjectSelector = __esm({
42505
43047
  async "src/ui/components/ProjectSelector.tsx"() {
42506
43048
  "use strict";
42507
- import_react32 = __toESM(require_react());
43049
+ import_react34 = __toESM(require_react());
42508
43050
  await init_build2();
42509
43051
  import_chalk11 = __toESM(require_source());
42510
43052
  init_sanitize();
42511
- import_jsx_runtime11 = __toESM(require_jsx_runtime());
43053
+ import_jsx_runtime12 = __toESM(require_jsx_runtime());
42512
43054
  ProjectSelector = ({ projects, onConfirm, onCancel }) => {
42513
- const [cursor, setCursor] = (0, import_react32.useState)(0);
42514
- const [selected, setSelected] = (0, import_react32.useState)(() => new Set(projects.map((_, i) => i)));
43055
+ const [cursor, setCursor] = (0, import_react34.useState)(0);
43056
+ const [selected, setSelected] = (0, import_react34.useState)(() => new Set(projects.map((_, i) => i)));
42515
43057
  use_input_default((input, key) => {
42516
43058
  if (key.upArrow) {
42517
43059
  setCursor((c) => Math.max(0, c - 1));
@@ -42537,26 +43079,26 @@ var init_ProjectSelector = __esm({
42537
43079
  }
42538
43080
  });
42539
43081
  const ecosystemLabel = (eco) => eco === "npm" ? import_chalk11.default.magenta("npm") : import_chalk11.default.blue("pip");
42540
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, children: [
42541
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
43082
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 1, children: [
43083
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { children: [
42542
43084
  import_chalk11.default.cyan("\u25C6"),
42543
43085
  " ",
42544
43086
  import_chalk11.default.bold("Dependency Guardian")
42545
43087
  ] }),
42546
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42547
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { bold: true, children: [
43088
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { children: "" }),
43089
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { bold: true, children: [
42548
43090
  "Found ",
42549
43091
  projects.length,
42550
43092
  " project",
42551
43093
  projects.length !== 1 ? "s" : ""
42552
43094
  ] }),
42553
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
43095
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { children: "" }),
42554
43096
  projects.map((proj, i) => {
42555
43097
  const isCursor = i === cursor;
42556
43098
  const isSelected = selected.has(i);
42557
43099
  const prefix = isCursor ? import_chalk11.default.cyan("\u258C") : " ";
42558
43100
  const check = isSelected ? import_chalk11.default.green("\u25C9") : import_chalk11.default.dim("\u25CB");
42559
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
43101
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { children: [
42560
43102
  prefix,
42561
43103
  check,
42562
43104
  " ",
@@ -42568,10 +43110,10 @@ var init_ProjectSelector = __esm({
42568
43110
  " packages"
42569
43111
  ] }, i);
42570
43112
  }),
42571
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42572
- /* @__PURE__ */ (0, import_jsx_runtime11.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` }),
42573
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
42574
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { children: [
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: [
42575
43117
  import_chalk11.default.bold.cyan("space"),
42576
43118
  " ",
42577
43119
  import_chalk11.default.dim("toggle"),
@@ -42580,9 +43122,9 @@ var init_ProjectSelector = __esm({
42580
43122
  " ",
42581
43123
  import_chalk11.default.dim("all"),
42582
43124
  " ",
42583
- import_chalk11.default.bold.cyan("\u23CE"),
43125
+ import_chalk11.default.bold.hex("#FFD700")("\u23CE"),
42584
43126
  " ",
42585
- import_chalk11.default.dim("scan"),
43127
+ import_chalk11.default.bold.hex("#FFD700")("scan"),
42586
43128
  " ",
42587
43129
  import_chalk11.default.bold.cyan("q"),
42588
43130
  " ",
@@ -42598,11 +43140,11 @@ var App_exports = {};
42598
43140
  __export(App_exports, {
42599
43141
  App: () => App2
42600
43142
  });
42601
- var import_react33, import_jsx_runtime12, App2;
43143
+ var import_react35, import_jsx_runtime13, App2;
42602
43144
  var init_App2 = __esm({
42603
43145
  async "src/ui/App.tsx"() {
42604
43146
  "use strict";
42605
- import_react33 = __toESM(require_react());
43147
+ import_react35 = __toESM(require_react());
42606
43148
  await init_build2();
42607
43149
  init_useScan();
42608
43150
  await init_Spinner();
@@ -42611,17 +43153,19 @@ var init_App2 = __esm({
42611
43153
  await init_ErrorView();
42612
43154
  await init_ProjectSelector();
42613
43155
  await init_useTerminalSize();
42614
- import_jsx_runtime12 = __toESM(require_jsx_runtime());
43156
+ import_jsx_runtime13 = __toESM(require_jsx_runtime());
42615
43157
  App2 = ({ config }) => {
42616
43158
  const { state, scanSelectedProjects, restartSelection } = useScan(config);
42617
43159
  const { exit } = use_app_default();
42618
43160
  useTerminalSize();
42619
- const prevPhaseRef = (0, import_react33.useRef)(state.phase);
42620
- const altScreenActiveRef = (0, import_react33.useRef)(false);
42621
- (0, import_react33.useEffect)(() => {
43161
+ const prevPhaseRef = (0, import_react35.useRef)(state.phase);
43162
+ const altScreenActiveRef = (0, import_react35.useRef)(false);
43163
+ (0, import_react35.useEffect)(() => {
42622
43164
  if (!process.stdout.isTTY) return;
42623
43165
  process.stdout.write("\x1B[?1049h");
42624
43166
  process.stdout.write("\x1B[2J\x1B[H");
43167
+ process.stdout.write("\x1B[?1003l");
43168
+ process.stdout.write("\x1B[?1000l");
42625
43169
  altScreenActiveRef.current = true;
42626
43170
  return () => {
42627
43171
  if (altScreenActiveRef.current) {
@@ -42631,20 +43175,20 @@ var init_App2 = __esm({
42631
43175
  process.stdout.write("\x1B[?25h");
42632
43176
  };
42633
43177
  }, []);
42634
- (0, import_react33.useEffect)(() => {
43178
+ (0, import_react35.useEffect)(() => {
42635
43179
  if (prevPhaseRef.current !== state.phase && process.stdout.isTTY) {
42636
43180
  process.stdout.write("\x1B[2J\x1B[H");
42637
43181
  }
42638
43182
  prevPhaseRef.current = state.phase;
42639
43183
  }, [state.phase]);
42640
- const leaveAltScreen = (0, import_react33.useCallback)(() => {
43184
+ const leaveAltScreen = (0, import_react35.useCallback)(() => {
42641
43185
  if (altScreenActiveRef.current && process.stdout.isTTY) {
42642
43186
  process.stdout.write("\x1B[?1049l");
42643
43187
  altScreenActiveRef.current = false;
42644
43188
  }
42645
43189
  process.stdout.write("\x1B[?25h");
42646
43190
  }, []);
42647
- const handleResultsExit = (0, import_react33.useCallback)(() => {
43191
+ const handleResultsExit = (0, import_react35.useCallback)(() => {
42648
43192
  if (state.phase === "results") {
42649
43193
  const { result } = state;
42650
43194
  if (result.action === "block" && config.mode === "block") {
@@ -42658,13 +43202,13 @@ var init_App2 = __esm({
42658
43202
  leaveAltScreen();
42659
43203
  exit();
42660
43204
  }, [state, config, exit, leaveAltScreen]);
42661
- const exitWithMessage = (0, import_react33.useCallback)((message, exitCode) => {
43205
+ const exitWithMessage = (0, import_react35.useCallback)((message, exitCode) => {
42662
43206
  process.exitCode = exitCode;
42663
43207
  leaveAltScreen();
42664
43208
  process.stderr.write(message);
42665
43209
  return setTimeout(() => exit(), 0);
42666
43210
  }, [exit, leaveAltScreen]);
42667
- (0, import_react33.useEffect)(() => {
43211
+ (0, import_react35.useEffect)(() => {
42668
43212
  if (state.phase === "empty") {
42669
43213
  const timer = exitWithMessage(`${state.message}
42670
43214
  `, 0);
@@ -42676,10 +43220,15 @@ var init_App2 = __esm({
42676
43220
  return () => clearTimeout(timer);
42677
43221
  }
42678
43222
  if (state.phase === "trial_exhausted") {
42679
- const timer = exitWithMessage(
42680
- "Free trial scans used up. Run `dg login` to create a free account and continue scanning.\n",
42681
- 1
42682
- );
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);
42683
43232
  return () => clearTimeout(timer);
42684
43233
  }
42685
43234
  }, [state, exitWithMessage]);
@@ -42695,9 +43244,9 @@ var init_App2 = __esm({
42695
43244
  const content = (() => {
42696
43245
  switch (state.phase) {
42697
43246
  case "discovering":
42698
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Spinner2, { label: `Searching for dependencies in ${process.cwd()} ...` });
43247
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Spinner2, { label: `Searching for dependencies in ${process.cwd()} ...` });
42699
43248
  case "selecting":
42700
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
43249
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
42701
43250
  ProjectSelector,
42702
43251
  {
42703
43252
  projects: state.projects,
@@ -42710,7 +43259,7 @@ var init_App2 = __esm({
42710
43259
  }
42711
43260
  );
42712
43261
  case "scanning":
42713
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
43262
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
42714
43263
  ProgressBar,
42715
43264
  {
42716
43265
  value: state.done,
@@ -42719,7 +43268,7 @@ var init_App2 = __esm({
42719
43268
  }
42720
43269
  );
42721
43270
  case "results":
42722
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
43271
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
42723
43272
  InteractiveResultsView,
42724
43273
  {
42725
43274
  result: state.result,
@@ -42731,21 +43280,37 @@ var init_App2 = __esm({
42731
43280
  }
42732
43281
  );
42733
43282
  case "empty":
42734
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { dimColor: true, children: state.message });
43283
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: state.message });
42735
43284
  case "error":
42736
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ErrorView, { error: state.error });
42737
- case "trial_exhausted":
42738
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
42739
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { color: "yellow", bold: true, children: "Free trial scans used up." }),
42740
- /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Text, { children: [
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: [
42741
43305
  "Run ",
42742
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
43306
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
42743
43307
  " to create a free account and continue scanning."
42744
43308
  ] })
42745
- ] });
43309
+ ] }) });
43310
+ }
42746
43311
  }
42747
43312
  })();
42748
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Box_default, { flexDirection: "column", children: content });
43313
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Box_default, { flexDirection: "column", children: content });
42749
43314
  };
42750
43315
  }
42751
43316
  });
@@ -42876,6 +43441,23 @@ async function runUpdate(currentVersion) {
42876
43441
 
42877
43442
  // src/bin.ts
42878
43443
  var CLI_VERSION = getVersion();
43444
+ function closestCommand(input, commands) {
43445
+ let best = "", bestDist = Infinity;
43446
+ for (const cmd of commands) {
43447
+ const m = input.length, n = cmd.length;
43448
+ const dp = Array.from({ length: m + 1 }, () => new Array(n + 1));
43449
+ for (let i = 0; i <= m; i++) dp[i][0] = i;
43450
+ for (let j = 0; j <= n; j++) dp[0][j] = j;
43451
+ for (let i = 1; i <= m; i++)
43452
+ for (let j = 1; j <= n; j++)
43453
+ dp[i][j] = input[i - 1] === cmd[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
43454
+ if (dp[m][n] < bestDist) {
43455
+ bestDist = dp[m][n];
43456
+ best = cmd;
43457
+ }
43458
+ }
43459
+ return bestDist <= 3 ? best : null;
43460
+ }
42879
43461
  process.on("SIGINT", () => {
42880
43462
  process.stderr.write("\n");
42881
43463
  process.exit(130);
@@ -42900,9 +43482,9 @@ async function main() {
42900
43482
  if (rawCommand === "login") {
42901
43483
  if (isInteractive) {
42902
43484
  const { render: render3 } = await init_build2().then(() => build_exports);
42903
- const React18 = await Promise.resolve().then(() => __toESM(require_react()));
43485
+ const React19 = await Promise.resolve().then(() => __toESM(require_react()));
42904
43486
  const { LoginApp: LoginApp2 } = await init_LoginApp().then(() => LoginApp_exports);
42905
- const { waitUntilExit } = render3(React18.createElement(LoginApp2));
43487
+ const { waitUntilExit } = render3(React19.createElement(LoginApp2));
42906
43488
  await waitUntilExit();
42907
43489
  } else {
42908
43490
  const { runStaticLogin: runStaticLogin2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
@@ -42926,12 +43508,29 @@ async function main() {
42926
43508
  process.stderr.write(chalk10.green(" Logged out.\n"));
42927
43509
  return;
42928
43510
  }
42929
- const config = parseConfig(process.argv);
43511
+ const KNOWN_COMMANDS = ["scan", "npm", "pip", "wrap", "login", "hook", "update", "logout"];
43512
+ if (rawCommand && !rawCommand.startsWith("-") && !KNOWN_COMMANDS.includes(rawCommand)) {
43513
+ const chalk10 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
43514
+ const best = closestCommand(rawCommand, KNOWN_COMMANDS);
43515
+ const hint = best ? ` Did you mean '${best}'?` : "";
43516
+ process.stderr.write(`
43517
+ ${chalk10.bold.red("Error:")} Unknown command '${rawCommand}'.${hint}
43518
+ `);
43519
+ process.stderr.write(chalk10.dim(` Run 'dg --help' for available commands.
43520
+
43521
+ `));
43522
+ process.exit(1);
43523
+ }
43524
+ const strictFlags = rawCommand !== "npm" && rawCommand !== "pip";
43525
+ const config = parseConfig(process.argv, strictFlags);
42930
43526
  const updatePromise = checkForUpdate(CLI_VERSION).catch(() => null);
42931
43527
  if (config.json || !isInteractive) {
42932
43528
  if (rawCommand === "npm") {
42933
43529
  const { runStaticNpm: runStaticNpm2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
42934
43530
  await runStaticNpm2(process.argv.slice(3), config);
43531
+ } else if (rawCommand === "pip") {
43532
+ const { runStaticPip: runStaticPip2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
43533
+ await runStaticPip2(process.argv.slice(3), config);
42935
43534
  } else {
42936
43535
  const { runStatic: runStatic2 } = await Promise.resolve().then(() => (init_static_output(), static_output_exports));
42937
43536
  await runStatic2(config);
@@ -42944,11 +43543,17 @@ async function main() {
42944
43543
  return;
42945
43544
  }
42946
43545
  const { render: render2 } = await init_build2().then(() => build_exports);
42947
- const React17 = await Promise.resolve().then(() => __toESM(require_react()));
43546
+ const React18 = await Promise.resolve().then(() => __toESM(require_react()));
42948
43547
  if (rawCommand === "npm") {
42949
43548
  const { NpmWrapperApp: NpmWrapperApp2 } = await init_NpmWrapperApp().then(() => NpmWrapperApp_exports);
42950
43549
  const { waitUntilExit } = render2(
42951
- React17.createElement(NpmWrapperApp2, { config, npmArgs: process.argv.slice(3) })
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) })
42952
43557
  );
42953
43558
  await waitUntilExit();
42954
43559
  } else {
@@ -42959,7 +43564,7 @@ async function main() {
42959
43564
  }
42960
43565
  const { App: App3 } = await init_App2().then(() => App_exports);
42961
43566
  const { waitUntilExit } = render2(
42962
- React17.createElement(App3, { config })
43567
+ React18.createElement(App3, { config })
42963
43568
  );
42964
43569
  await waitUntilExit();
42965
43570
  }
@@ -42970,17 +43575,25 @@ async function main() {
42970
43575
  }
42971
43576
  }
42972
43577
  main().catch((err) => {
42973
- try {
42974
- const chalk10 = require_source();
42975
- process.stderr.write(`
43578
+ if (process.argv.includes("--json")) {
43579
+ process.stdout.write(JSON.stringify({
43580
+ error: true,
43581
+ code: err.statusCode ? "api_error" : "internal_error",
43582
+ message: err.message
43583
+ }, null, 2) + "\n");
43584
+ } else {
43585
+ try {
43586
+ const chalk10 = require_source();
43587
+ process.stderr.write(`
42976
43588
  ${chalk10.bold.red("Error:")} ${err.message}
42977
43589
 
42978
43590
  `);
42979
- } catch {
42980
- process.stderr.write(`
43591
+ } catch {
43592
+ process.stderr.write(`
42981
43593
  Error: ${err.message}
42982
43594
 
42983
43595
  `);
43596
+ }
42984
43597
  }
42985
43598
  process.exit(3);
42986
43599
  });