@westbayberry/dg 1.1.2 → 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.mjs +285 -189
  2. package/package.json +2 -1
package/dist/index.mjs CHANGED
@@ -1649,7 +1649,7 @@ function initTelemetry(version) {
1649
1649
  });
1650
1650
  }
1651
1651
  function redact(s) {
1652
- return s.replace(/dg_(?:live|test)_[A-Za-z0-9_-]{3,}/gi, "[DG_KEY_REDACTED]").replace(/\/Users\/[^\s:]+/g, "[USER_PATH]").replace(/\/home\/[^\s:]+/g, "[USER_PATH]").replace(/C:\\Users\\[^\s:]+/g, "[USER_PATH]").replace(/Bearer [^\s]+/g, "Bearer [REDACTED]");
1652
+ return s.replace(/(--token(?:=|\s+))\S+/gi, "$1[REDACTED]").replace(/dg_(?:live|test)_[A-Za-z0-9_-]{3,}/gi, "[DG_KEY_REDACTED]").replace(/\/Users\/[^\s:]+/g, "[USER_PATH]").replace(/\/home\/[^\s:]+/g, "[USER_PATH]").replace(/C:\\Users\\[^\s:]+/g, "[USER_PATH]").replace(/Bearer [^\s]+/g, "Bearer [REDACTED]");
1653
1653
  }
1654
1654
  function suppressNudge() {
1655
1655
  return !telemetryEnabled();
@@ -1669,7 +1669,7 @@ function trimStack(raw, debug) {
1669
1669
  }
1670
1670
  function buildIssueUrl(error, ctx) {
1671
1671
  const msg = redact(error.message || error.name || "Unknown error").slice(0, 120);
1672
- const cmd = process.argv.slice(2).join(" ") || "(none)";
1672
+ const cmd = redact(process.argv.slice(2).join(" ")) || "(none)";
1673
1673
  const stack = trimStack(error.stack, false).join("\n");
1674
1674
  const body = [
1675
1675
  "**dg crashed**",
@@ -1730,7 +1730,7 @@ function captureError(error, context) {
1730
1730
  process.exitCode = 1;
1731
1731
  return;
1732
1732
  }
1733
- const cmd = process.argv.slice(2).join(" ") || "(none)";
1733
+ const cmd = redact(process.argv.slice(2).join(" ")) || "(none)";
1734
1734
  process.stderr.write("\n" + chalk18.dim(SEPARATOR) + "\n\n");
1735
1735
  process.stderr.write(
1736
1736
  " " + chalk18.red.bold("\u2718 dg crashed: ") + chalk18.red(redact(err.message || err.name)) + "\n\n"
@@ -1958,49 +1958,64 @@ function authBase() {
1958
1958
  }
1959
1959
  }
1960
1960
  async function createAuthSession() {
1961
- let res;
1961
+ const ctrl = new AbortController();
1962
+ const timer = setTimeout(() => ctrl.abort(), 1e4);
1962
1963
  try {
1963
- res = await globalThis.fetch(`${authBase()}/cli/auth/sessions`, {
1964
- method: "POST",
1965
- headers: { "Content-Type": "application/json" }
1966
- });
1967
- } catch {
1968
- throw new Error("Could not connect to westbayberry.com");
1969
- }
1970
- if (!res.ok) {
1971
- const body = await res.text().catch(() => "");
1972
- throw new Error(
1973
- `Failed to create auth session (HTTP ${res.status})${body ? `: ${body}` : ""}`
1974
- );
1964
+ let res;
1965
+ try {
1966
+ res = await globalThis.fetch(`${authBase()}/cli/auth/sessions`, {
1967
+ method: "POST",
1968
+ headers: { "Content-Type": "application/json" },
1969
+ signal: ctrl.signal
1970
+ });
1971
+ } catch {
1972
+ throw new Error("Could not connect to westbayberry.com");
1973
+ }
1974
+ if (!res.ok) {
1975
+ const body = await res.text().catch(() => "");
1976
+ throw new Error(
1977
+ `Failed to create auth session (HTTP ${res.status})${body ? `: ${body}` : ""}`
1978
+ );
1979
+ }
1980
+ const json = await res.json();
1981
+ return {
1982
+ sessionId: json.session_id,
1983
+ verifyUrl: json.verify_url,
1984
+ expiresIn: json.expires_in
1985
+ };
1986
+ } finally {
1987
+ clearTimeout(timer);
1975
1988
  }
1976
- const json = await res.json();
1977
- return {
1978
- sessionId: json.session_id,
1979
- verifyUrl: json.verify_url,
1980
- expiresIn: json.expires_in
1981
- };
1982
1989
  }
1983
1990
  async function pollAuthSession(sessionId) {
1984
- let res;
1991
+ const ctrl = new AbortController();
1992
+ const timer = setTimeout(() => ctrl.abort(), 8e3);
1985
1993
  try {
1986
- res = await globalThis.fetch(
1987
- `${authBase()}/cli/auth/sessions/${sessionId}/token`
1988
- );
1989
- } catch {
1990
- return { status: "expired" };
1991
- }
1992
- if (res.status === 404) {
1993
- return { status: "expired" };
1994
- }
1995
- if (!res.ok) {
1996
- return { status: "expired" };
1994
+ let res;
1995
+ try {
1996
+ res = await globalThis.fetch(
1997
+ `${authBase()}/cli/auth/sessions/${sessionId}/token`,
1998
+ { signal: ctrl.signal }
1999
+ );
2000
+ } catch (e) {
2001
+ if (e instanceof Error && e.name === "AbortError") return { status: "pending" };
2002
+ return { status: "expired" };
2003
+ }
2004
+ if (res.status === 404) {
2005
+ return { status: "expired" };
2006
+ }
2007
+ if (!res.ok) {
2008
+ return { status: "expired" };
2009
+ }
2010
+ const json = await res.json();
2011
+ return {
2012
+ status: json.status,
2013
+ apiKey: json.api_key,
2014
+ email: json.email
2015
+ };
2016
+ } finally {
2017
+ clearTimeout(timer);
1997
2018
  }
1998
- const json = await res.json();
1999
- return {
2000
- status: json.status,
2001
- apiKey: json.api_key,
2002
- email: json.email
2003
- };
2004
2019
  }
2005
2020
  function configPath() {
2006
2021
  return dgConfigPath();
@@ -2297,7 +2312,7 @@ async function preflightAuthCheck(apiUrl) {
2297
2312
  const cached = readCachedAuthStatus();
2298
2313
  if (cached) {
2299
2314
  if (cached.freeTierCapReached) {
2300
- throw new PreflightFreeCapReachedError(cached.scansUsed, cached.scansLimit ?? cached.scansUsed);
2315
+ throw new PreflightFreeCapReachedError(cached.scansUsed, cached.scansLimit ?? cached.scansUsed, cached.capReason ?? "monthly_limit");
2301
2316
  }
2302
2317
  return cached;
2303
2318
  }
@@ -2331,15 +2346,17 @@ async function preflightAuthCheck(apiUrl) {
2331
2346
  } catch {
2332
2347
  }
2333
2348
  if (body.freeTierCapReached) {
2349
+ const capReason = body.capReason === "prefix_cap" ? "prefix_cap" : "monthly_limit";
2334
2350
  const status2 = {
2335
2351
  authenticated: !!apiKey,
2336
2352
  freeTierCapReached: true,
2337
2353
  scansUsed: body.scansUsed ?? 0,
2338
2354
  scansLimit: body.maxScans ?? 0,
2355
+ capReason,
2339
2356
  fetchedAt: Date.now()
2340
2357
  };
2341
2358
  writeCachedAuthStatus(status2);
2342
- throw new PreflightFreeCapReachedError(status2.scansUsed, status2.scansLimit ?? 0);
2359
+ throw new PreflightFreeCapReachedError(status2.scansUsed, status2.scansLimit ?? 0, capReason);
2343
2360
  }
2344
2361
  }
2345
2362
  if (!resp.ok) {
@@ -2476,10 +2493,13 @@ var init_auth = __esm({
2476
2493
  init_paths();
2477
2494
  DEFAULT_WEB_BASE = "https://westbayberry.com";
2478
2495
  PreflightFreeCapReachedError = class extends Error {
2479
- constructor(scansUsed, maxScans) {
2480
- super("Free tier monthly cap reached. Run `dg upgrade` for Pro.");
2496
+ constructor(scansUsed, maxScans, reason = "monthly_limit") {
2497
+ super(
2498
+ reason === "prefix_cap" ? "Too many anonymous devices from your network this month. Sign in with `dg login` to keep scanning." : "Free tier monthly package limit reached. Run `dg upgrade` for Pro."
2499
+ );
2481
2500
  this.scansUsed = scansUsed;
2482
2501
  this.maxScans = maxScans;
2502
+ this.reason = reason;
2483
2503
  this.name = "PreflightFreeCapReachedError";
2484
2504
  }
2485
2505
  };
@@ -3945,7 +3965,7 @@ unset it manually if you want fully anonymous behavior.
3945
3965
  UPGRADE = `
3946
3966
  dg upgrade \u2014 start Stripe checkout for Pro
3947
3967
 
3948
- Free tier is 1000 scans/mo per device. Pro is 5000/mo + watchlists +
3968
+ Free tier is 50,000 packages/mo per device. Pro is 250,000/mo + watchlists +
3949
3969
  saved reports + Dashboard analytics.
3950
3970
 
3951
3971
  Usage:
@@ -4014,7 +4034,7 @@ async function maybeShowWelcomePanel(opts) {
4014
4034
  if (existsSync9(welcomeShownPath())) return;
4015
4035
  if (!existsSync9(installReceiptPath2())) return;
4016
4036
  try {
4017
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
4037
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
4018
4038
  const lines = [
4019
4039
  "",
4020
4040
  chalk18.bold(" \u2713 Dependency Guardian is active.") + "",
@@ -4065,7 +4085,7 @@ __export(upgrade_exports, {
4065
4085
  handleUpgradeCommand: () => handleUpgradeCommand
4066
4086
  });
4067
4087
  async function handleUpgradeCommand(opts) {
4068
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
4088
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
4069
4089
  const webUrl = opts?.webUrl ?? process.env.DG_WEB_URL ?? "https://westbayberry.com";
4070
4090
  const deviceId = getOrCreateDeviceId();
4071
4091
  const url = `${webUrl}/upgrade?device=${encodeURIComponent(deviceId)}`;
@@ -39038,9 +39058,9 @@ var import_react22, import_jsx_runtime, CHAR_POOL, COLOR_POOL, GRAVITY, DRAG, FR
39038
39058
  var init_Confetti = __esm({
39039
39059
  async "src/ui/components/Confetti.tsx"() {
39040
39060
  "use strict";
39041
- import_react22 = __toESM(require_react());
39061
+ import_react22 = __toESM(require_react(), 1);
39042
39062
  await init_build2();
39043
- import_jsx_runtime = __toESM(require_jsx_runtime());
39063
+ import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
39044
39064
  CHAR_POOL = [
39045
39065
  "*",
39046
39066
  "*",
@@ -39155,7 +39175,7 @@ var import_react23;
39155
39175
  var init_useTerminalSize = __esm({
39156
39176
  async "src/ui/hooks/useTerminalSize.ts"() {
39157
39177
  "use strict";
39158
- import_react23 = __toESM(require_react());
39178
+ import_react23 = __toESM(require_react(), 1);
39159
39179
  await init_build2();
39160
39180
  }
39161
39181
  });
@@ -39169,11 +39189,11 @@ var import_react24, import_jsx_runtime2, LoginCelebrateApp;
39169
39189
  var init_LoginCelebrateApp = __esm({
39170
39190
  async "src/ui/apps/LoginCelebrateApp.tsx"() {
39171
39191
  "use strict";
39172
- import_react24 = __toESM(require_react());
39192
+ import_react24 = __toESM(require_react(), 1);
39173
39193
  await init_build2();
39174
39194
  await init_Confetti();
39175
39195
  await init_useTerminalSize();
39176
- import_jsx_runtime2 = __toESM(require_jsx_runtime());
39196
+ import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
39177
39197
  LoginCelebrateApp = ({ email, durationMs = 2500 }) => {
39178
39198
  const { exit } = use_app_default();
39179
39199
  const { cols, rows } = useTerminalSize();
@@ -39230,7 +39250,7 @@ async function celebrateFirstLoginIfNew(email) {
39230
39250
  if (!shouldCelebrate()) return;
39231
39251
  try {
39232
39252
  const { render: render2 } = await init_build2().then(() => build_exports);
39233
- const React22 = await Promise.resolve().then(() => __toESM(require_react()));
39253
+ const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
39234
39254
  const { LoginCelebrateApp: LoginCelebrateApp2 } = await init_LoginCelebrateApp().then(() => LoginCelebrateApp_exports);
39235
39255
  const { enterTui: enterTui2, leaveTui: leaveTui2 } = await Promise.resolve().then(() => (init_terminal_state(), terminal_state_exports));
39236
39256
  enterTui2();
@@ -39284,7 +39304,7 @@ function parseLoginArgs(args) {
39284
39304
  return { kind: "token", value: token, force };
39285
39305
  }
39286
39306
  async function handleLoginWithToken(raw, opts) {
39287
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
39307
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
39288
39308
  const existing = getStoredApiKey();
39289
39309
  if (existing && !opts.force) {
39290
39310
  process.stderr.write(
@@ -39439,7 +39459,7 @@ var import_react25, POLL_INTERVAL_MS, MAX_POLL_ATTEMPTS;
39439
39459
  var init_useLogin = __esm({
39440
39460
  "src/ui/hooks/useLogin.ts"() {
39441
39461
  "use strict";
39442
- import_react25 = __toESM(require_react());
39462
+ import_react25 = __toESM(require_react(), 1);
39443
39463
  init_auth();
39444
39464
  POLL_INTERVAL_MS = 2e3;
39445
39465
  MAX_POLL_ATTEMPTS = 150;
@@ -41125,7 +41145,7 @@ var init_Spinner = __esm({
41125
41145
  "use strict";
41126
41146
  await init_build2();
41127
41147
  await init_build3();
41128
- import_jsx_runtime3 = __toESM(require_jsx_runtime());
41148
+ import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
41129
41149
  Spinner2 = ({ label }) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { children: [
41130
41150
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "cyan", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(build_default, { type: "dots" }) }),
41131
41151
  /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
@@ -41145,11 +41165,11 @@ var import_react27, import_jsx_runtime4, LoginApp;
41145
41165
  var init_LoginApp = __esm({
41146
41166
  async "src/ui/apps/LoginApp.tsx"() {
41147
41167
  "use strict";
41148
- import_react27 = __toESM(require_react());
41168
+ import_react27 = __toESM(require_react(), 1);
41149
41169
  await init_build2();
41150
41170
  init_useLogin();
41151
41171
  await init_Spinner();
41152
- import_jsx_runtime4 = __toESM(require_jsx_runtime());
41172
+ import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
41153
41173
  LoginApp = () => {
41154
41174
  const { state, openAndPoll } = useLogin();
41155
41175
  const { exit } = use_app_default();
@@ -41289,7 +41309,8 @@ __export(client_exports, {
41289
41309
  callAnalyzeAPI: () => callAnalyzeAPI,
41290
41310
  callPyPIAnalyzeAPI: () => callPyPIAnalyzeAPI,
41291
41311
  fetchLicenses: () => fetchLicenses,
41292
- fetchPyPILicenses: () => fetchPyPILicenses
41312
+ fetchPyPILicenses: () => fetchPyPILicenses,
41313
+ mergeResponses: () => mergeResponses
41293
41314
  });
41294
41315
  import { randomUUID as randomUUID2 } from "node:crypto";
41295
41316
  function batchConcurrency() {
@@ -41328,7 +41349,11 @@ async function handleFreeCapReached(response) {
41328
41349
  const body = await response.json().catch(() => ({}));
41329
41350
  if (body && body.freeTierCapReached) {
41330
41351
  const b = body;
41331
- throw new FreeCapReachedError(b.scansUsed, b.maxScans);
41352
+ throw new FreeCapReachedError(
41353
+ b.scansUsed,
41354
+ b.maxScans,
41355
+ b.capReason === "prefix_cap" ? "prefix_cap" : "monthly_limit"
41356
+ );
41332
41357
  }
41333
41358
  throw new APIError("Forbidden", 403, JSON.stringify(body));
41334
41359
  }
@@ -41467,12 +41492,19 @@ function mergeResponses(results) {
41467
41492
  for (const r of results) {
41468
41493
  Object.assign(safeVersions, r.safeVersions);
41469
41494
  }
41495
+ const remaining = results.map((r) => r.freeScansRemaining).filter((v) => typeof v === "number");
41496
+ const usage = results.map((r) => r.usage).filter((u) => !!u).reduce(
41497
+ (best, u) => best === void 0 || u.used > best.used ? u : best,
41498
+ void 0
41499
+ );
41470
41500
  return {
41471
41501
  score: maxScore,
41472
41502
  action,
41473
41503
  packages: allPackages,
41474
41504
  safeVersions,
41475
- durationMs: results.reduce((s, r) => s + (r.durationMs || 0), 0)
41505
+ durationMs: results.reduce((s, r) => s + (r.durationMs || 0), 0),
41506
+ ...remaining.length > 0 ? { freeScansRemaining: Math.min(...remaining) } : {},
41507
+ ...usage ? { usage } : {}
41476
41508
  };
41477
41509
  }
41478
41510
  function formatApiErrorMessage(status, rawBody, config) {
@@ -41858,10 +41890,13 @@ var init_client = __esm({
41858
41890
  }
41859
41891
  };
41860
41892
  FreeCapReachedError = class extends Error {
41861
- constructor(scansUsed, maxScans) {
41862
- super("Free trial scans used up. Run `dg login` to create a free account and continue scanning.");
41893
+ constructor(scansUsed, maxScans, reason = "monthly_limit") {
41894
+ super(
41895
+ reason === "prefix_cap" ? "Too many anonymous devices from your network this month. Sign in with `dg login` to keep scanning." : "Free tier monthly package limit reached. Run `dg upgrade` for Pro."
41896
+ );
41863
41897
  this.scansUsed = scansUsed;
41864
41898
  this.maxScans = maxScans;
41899
+ this.reason = reason;
41865
41900
  this.name = "FreeCapReachedError";
41866
41901
  }
41867
41902
  };
@@ -42269,13 +42304,17 @@ function discoverChanges(cwd2, config) {
42269
42304
  cwd2 = join7(cwd2, config.workspace);
42270
42305
  }
42271
42306
  const lockfileInfo = findLockfile(cwd2);
42272
- const pythonDepFiles = ["requirements.txt", "Pipfile.lock", "poetry.lock"];
42307
+ const pythonDepFiles = ["requirements.txt", "Pipfile.lock", "poetry.lock", "uv.lock"];
42273
42308
  let pythonPackages = [];
42309
+ const pythonSkipped = [];
42274
42310
  for (const pyFile of pythonDepFiles) {
42275
42311
  if (existsSync12(join7(cwd2, pyFile))) {
42276
42312
  const pyPkgs = parsePythonDepFile(cwd2, pyFile);
42277
42313
  for (const p of pyPkgs) {
42278
- if (p.version === "latest") continue;
42314
+ if (p.version === "latest") {
42315
+ pythonSkipped.push(`${p.name} (unpinned \u2014 pin with == to scan)`);
42316
+ continue;
42317
+ }
42279
42318
  pythonPackages.push({
42280
42319
  name: sanitize(p.name),
42281
42320
  version: sanitize(p.version),
@@ -42287,8 +42326,8 @@ function discoverChanges(cwd2, config) {
42287
42326
  }
42288
42327
  }
42289
42328
  if (!lockfileInfo) {
42290
- if (pythonPackages.length > 0) {
42291
- const skipped2 = [];
42329
+ if (pythonPackages.length > 0 || pythonSkipped.length > 0) {
42330
+ const skipped2 = [...pythonSkipped];
42292
42331
  if (pythonPackages.length > config.maxPackages) {
42293
42332
  skipped2.push(...pythonPackages.slice(config.maxPackages).map((p) => `${p.name}@${p.version}`));
42294
42333
  pythonPackages = pythonPackages.slice(0, config.maxPackages);
@@ -42296,7 +42335,7 @@ function discoverChanges(cwd2, config) {
42296
42335
  return { packages: [], pythonPackages, method: "scan-all", skipped: skipped2 };
42297
42336
  }
42298
42337
  throw new Error(
42299
- "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."
42338
+ "No lockfile found (package-lock.json, yarn.lock, pnpm-lock.yaml, requirements.txt, Pipfile.lock, poetry.lock, or uv.lock). Run from your project root or use --base-lockfile."
42300
42339
  );
42301
42340
  }
42302
42341
  const headContent = readFileSafe(lockfileInfo.path);
@@ -42313,7 +42352,7 @@ function discoverChanges(cwd2, config) {
42313
42352
  packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
42314
42353
  pythonPackages,
42315
42354
  method: "base-lockfile",
42316
- skipped: diff2.skipped
42355
+ skipped: [...diff2.skipped, ...pythonSkipped]
42317
42356
  };
42318
42357
  }
42319
42358
  if (!config.scanAll) {
@@ -42325,7 +42364,7 @@ function discoverChanges(cwd2, config) {
42325
42364
  packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
42326
42365
  pythonPackages,
42327
42366
  method: "git-diff",
42328
- skipped: diff2.skipped
42367
+ skipped: [...diff2.skipped, ...pythonSkipped]
42329
42368
  };
42330
42369
  }
42331
42370
  const pkgJsonPath = join7(cwd2, "package.json");
@@ -42346,7 +42385,7 @@ function discoverChanges(cwd2, config) {
42346
42385
  packages: resolved.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
42347
42386
  pythonPackages,
42348
42387
  method: "fallback",
42349
- skipped: []
42388
+ skipped: [...pythonSkipped]
42350
42389
  };
42351
42390
  }
42352
42391
  }
@@ -42369,7 +42408,7 @@ function discoverChanges(cwd2, config) {
42369
42408
  });
42370
42409
  }
42371
42410
  }
42372
- return { packages, pythonPackages, method: "scan-all", skipped };
42411
+ return { packages, pythonPackages, method: "scan-all", skipped: [...skipped, ...pythonSkipped] };
42373
42412
  }
42374
42413
  function findLockfile(cwd2) {
42375
42414
  const candidates = [
@@ -42476,10 +42515,11 @@ function parsePythonDepFile(projectDir, depFile) {
42476
42515
  return [];
42477
42516
  }
42478
42517
  }
42479
- if (depFile === "poetry.lock") {
42518
+ if (depFile === "poetry.lock" || depFile === "uv.lock") {
42480
42519
  const packages2 = [];
42481
42520
  const blocks = content.split(/^\[\[package\]\]/gm);
42482
42521
  for (const block of blocks) {
42522
+ if (/source\s*=\s*\{[^}]*\b(editable|virtual|directory)\b/.test(block)) continue;
42483
42523
  const nameMatch = block.match(/^name\s*=\s*"([^"]+)"/m);
42484
42524
  const versionMatch = block.match(/^version\s*=\s*"([^"]+)"/m);
42485
42525
  if (nameMatch && versionMatch) {
@@ -43460,6 +43500,24 @@ var init_artifact_integrity = __esm({
43460
43500
  });
43461
43501
 
43462
43502
  // src/ui/format-helpers.ts
43503
+ var format_helpers_exports = {};
43504
+ __export(format_helpers_exports, {
43505
+ USAGE_NEAR_LIMIT_RATIO: () => USAGE_NEAR_LIMIT_RATIO,
43506
+ formatUsage: () => formatUsage,
43507
+ groupPackages: () => groupPackages,
43508
+ pad: () => pad,
43509
+ truncate: () => truncate
43510
+ });
43511
+ function formatUsage(usage) {
43512
+ const used = usage.used.toLocaleString();
43513
+ if (usage.limit === null) {
43514
+ return { text: `${used} packages this month`, nearLimit: false };
43515
+ }
43516
+ return {
43517
+ text: `${used} / ${usage.limit.toLocaleString()} packages this month`,
43518
+ nearLimit: usage.used / usage.limit >= USAGE_NEAR_LIMIT_RATIO
43519
+ };
43520
+ }
43463
43521
  function pad(s, len) {
43464
43522
  return s + " ".repeat(Math.max(0, len - s.length));
43465
43523
  }
@@ -43479,9 +43537,11 @@ function groupPackages(packages, keyBy = "name") {
43479
43537
  key: keyBy === "fingerprint" ? fingerprint : pkgs[0].name
43480
43538
  })).sort((a, b) => b.packages[0].score - a.packages[0].score);
43481
43539
  }
43540
+ var USAGE_NEAR_LIMIT_RATIO;
43482
43541
  var init_format_helpers = __esm({
43483
43542
  "src/ui/format-helpers.ts"() {
43484
43543
  "use strict";
43544
+ USAGE_NEAR_LIMIT_RATIO = 0.8;
43485
43545
  }
43486
43546
  });
43487
43547
 
@@ -43545,11 +43605,11 @@ var import_react28, import_chalk4, import_jsx_runtime5, VISIBLE_ROWS, FileSavePr
43545
43605
  var init_FileSavePrompt = __esm({
43546
43606
  async "src/ui/components/FileSavePrompt.tsx"() {
43547
43607
  "use strict";
43548
- import_react28 = __toESM(require_react());
43608
+ import_react28 = __toESM(require_react(), 1);
43549
43609
  await init_build2();
43550
- import_chalk4 = __toESM(require_source());
43610
+ import_chalk4 = __toESM(require_source(), 1);
43551
43611
  await init_useTerminalSize();
43552
- import_jsx_runtime5 = __toESM(require_jsx_runtime());
43612
+ import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
43553
43613
  VISIBLE_ROWS = 15;
43554
43614
  FileSavePrompt = ({
43555
43615
  defaultName,
@@ -43824,7 +43884,7 @@ async function countPythonPackages(depPath, depFile) {
43824
43884
  const parsed = JSON.parse(content);
43825
43885
  return Object.keys(parsed.default || {}).length + Object.keys(parsed.develop || {}).length;
43826
43886
  }
43827
- if (depFile === "poetry.lock") {
43887
+ if (depFile === "poetry.lock" || depFile === "uv.lock") {
43828
43888
  return (content.match(/^\[\[package\]\]/gm) || []).length;
43829
43889
  }
43830
43890
  return content.split("\n").filter(
@@ -43843,7 +43903,7 @@ var init_count_packages = __esm({
43843
43903
  "src/discover/count-packages.ts"() {
43844
43904
  "use strict";
43845
43905
  NPM_LOCKFILES = ["package-lock.json", "yarn.lock", "pnpm-lock.yaml", "npm-shrinkwrap.json"];
43846
- PYTHON_DEPFILES = ["requirements.txt", "Pipfile.lock", "poetry.lock"];
43906
+ PYTHON_DEPFILES = ["requirements.txt", "Pipfile.lock", "poetry.lock", "uv.lock"];
43847
43907
  }
43848
43908
  });
43849
43909
 
@@ -44385,13 +44445,16 @@ function derivePackageAction(pkg) {
44385
44445
  function overallAction(packages) {
44386
44446
  let hasBlock = false;
44387
44447
  let hasWarn = false;
44448
+ let hasIncomplete = false;
44388
44449
  for (const p of packages) {
44389
- const a = derivePackageActionFromFindings(p);
44450
+ const a = derivePackageAction(p);
44390
44451
  if (a === "block") hasBlock = true;
44391
44452
  else if (a === "warn") hasWarn = true;
44453
+ if (p.action === "analysis_incomplete") hasIncomplete = true;
44392
44454
  }
44393
44455
  if (hasBlock) return "block";
44394
44456
  if (hasWarn) return "warn";
44457
+ if (hasIncomplete) return "analysis_incomplete";
44395
44458
  return "pass";
44396
44459
  }
44397
44460
  function applyAllowlist(allowlist, result, apiKind) {
@@ -44423,6 +44486,7 @@ function applyAllowlist(allowlist, result, apiKind) {
44423
44486
  let suppressedCount = 0;
44424
44487
  const filteredPackages = result.packages.map((pkg) => {
44425
44488
  const matchingEntry = activePackages.find((e) => packageMatches(e, pkg, apiKind));
44489
+ const originalCount = (pkg.findings ?? []).length;
44426
44490
  let findings = pkg.findings ?? [];
44427
44491
  if (matchingEntry) {
44428
44492
  if (!matchingEntry.rules) {
@@ -44437,8 +44501,8 @@ function applyAllowlist(allowlist, result, apiKind) {
44437
44501
  const globallySupressed = findings.filter((f) => activeGlobalRules[findingRuleId(f)] !== void 0);
44438
44502
  suppressedCount += globallySupressed.length;
44439
44503
  findings = findings.filter((f) => activeGlobalRules[findingRuleId(f)] === void 0);
44440
- const newPkg = { ...pkg, findings };
44441
- return newPkg;
44504
+ const action = findings.length !== originalCount ? derivePackageActionFromFindings({ ...pkg, findings }) : pkg.action ?? derivePackageAction(pkg);
44505
+ return { ...pkg, findings, action };
44442
44506
  });
44443
44507
  const newAction = overallAction(filteredPackages);
44444
44508
  return {
@@ -44733,7 +44797,8 @@ __export(static_output_exports, {
44733
44797
  runStatic: () => runStatic,
44734
44798
  runStaticLogin: () => runStaticLogin,
44735
44799
  runStaticNpm: () => runStaticNpm,
44736
- runStaticPip: () => runStaticPip
44800
+ runStaticPip: () => runStaticPip,
44801
+ scanExitCode: () => scanExitCode
44737
44802
  });
44738
44803
  import { writeFileSync as writeFileSync11, readFileSync as readFileSync12, existsSync as existsSync18, mkdirSync as mkdirSync8, lstatSync as lstatSync5 } from "node:fs";
44739
44804
  import { resolve as resolvePath, dirname as dirname12 } from "node:path";
@@ -44806,7 +44871,7 @@ async function handleJsonOutput(result, config) {
44806
44871
  const localDate = (/* @__PURE__ */ new Date()).toLocaleDateString("sv-SE");
44807
44872
  const defaultName = `dg-scan-${localDate}`;
44808
44873
  const { render: render2 } = await init_build2().then(() => build_exports);
44809
- const React22 = await Promise.resolve().then(() => __toESM(require_react()));
44874
+ const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
44810
44875
  const { FileSavePrompt: FileSavePrompt2 } = await init_FileSavePrompt().then(() => FileSavePrompt_exports);
44811
44876
  await new Promise((resolve3) => {
44812
44877
  const inkInstance = render2(
@@ -44874,7 +44939,7 @@ function handleFreeCapReached2(error, jsonMode = false) {
44874
44939
  hasKey = !!getStoredApiKey();
44875
44940
  } catch {
44876
44941
  }
44877
- const message = hasKey ? "Your API key may be invalid or expired. Run `dg logout` then `dg login` to re-authenticate." : `Free tier monthly cap reached (${error.scansUsed}/${error.maxScans}). Run \`dg upgrade\` for Pro (5000/mo) or wait until next month.`;
44942
+ const message = hasKey ? "Your API key may be invalid or expired. Run `dg logout` then `dg login` to re-authenticate." : `Free tier monthly package limit reached (${error.scansUsed.toLocaleString()}/${error.maxScans.toLocaleString()}). Run \`dg upgrade\` for Pro or wait until next month.`;
44878
44943
  if (jsonMode) {
44879
44944
  process.stdout.write(JSON.stringify({
44880
44945
  error: true,
@@ -44892,8 +44957,8 @@ function handleFreeCapReached2(error, jsonMode = false) {
44892
44957
  } else {
44893
44958
  process.stderr.write(
44894
44959
  import_chalk5.default.yellow(`
44895
- Free tier monthly cap reached (${error.scansUsed}/${error.maxScans}).
44896
- `) + import_chalk5.default.white(` Run \`dg upgrade\` for Pro (5000/mo) or wait until next month.
44960
+ Free tier monthly package limit reached (${error.scansUsed.toLocaleString()}/${error.maxScans.toLocaleString()}).
44961
+ `) + import_chalk5.default.white(` Run \`dg upgrade\` for Pro or wait until next month.
44897
44962
 
44898
44963
  `)
44899
44964
  );
@@ -45045,6 +45110,12 @@ function renderResultDetails(result, _config) {
45045
45110
  function renderResultStatic(result, config) {
45046
45111
  return config.details ? renderResultDetails(result, config) : renderResultClean(result, config);
45047
45112
  }
45113
+ function scanExitCode(action, mode) {
45114
+ if (action === "block" && mode === "block") return 2;
45115
+ if (action === "block" || action === "warn") return 1;
45116
+ if (action === "analysis_incomplete") return 4;
45117
+ return 0;
45118
+ }
45048
45119
  async function runStatic(config) {
45049
45120
  const dbg = (msg) => {
45050
45121
  if (config.debug)
@@ -45107,7 +45178,7 @@ async function runStatic(config) {
45107
45178
  `
45108
45179
  )
45109
45180
  );
45110
- if (discovery.skipped.length > 0 && config.maxPackages < 1e4) {
45181
+ if (discovery.skipped.length > 0) {
45111
45182
  note(
45112
45183
  config,
45113
45184
  import_chalk5.default.dim(
@@ -45191,26 +45262,23 @@ async function runStatic(config) {
45191
45262
  process.stdout.write(sarif + "\n");
45192
45263
  }
45193
45264
  printTrialBanner(result, config);
45194
- if (result.action === "block" && config.mode === "block") process.exit(2);
45195
- else if (result.action === "block" || result.action === "warn") process.exit(1);
45196
- process.exit(0);
45265
+ process.exit(scanExitCode(result.action, config.mode));
45197
45266
  }
45198
45267
  const jsonHandled = await handleJsonOutput(result, config);
45199
45268
  if (jsonHandled) {
45200
45269
  printTrialBanner(result, config);
45201
- if (result.action === "block" && config.mode === "block") process.exit(2);
45202
- else if (result.action === "block" || result.action === "warn") process.exit(1);
45203
- process.exit(0);
45270
+ process.exit(scanExitCode(result.action, config.mode));
45204
45271
  }
45205
45272
  const output = renderResultStatic(result, config);
45206
45273
  process.stdout.write(output + "\n");
45207
- printTrialBanner(result, config);
45208
- if (result.action === "block" && config.mode === "block") {
45209
- process.exit(2);
45210
- } else if (result.action === "block" || result.action === "warn") {
45211
- process.exit(1);
45274
+ if (result.usage) {
45275
+ const u = formatUsage(result.usage);
45276
+ process.stdout.write(
45277
+ (u.nearLimit ? import_chalk5.default.yellow(` ${u.text} \u2191 dg upgrade for Pro`) : import_chalk5.default.dim(` ${u.text}`)) + "\n"
45278
+ );
45212
45279
  }
45213
- process.exit(0);
45280
+ printTrialBanner(result, config);
45281
+ process.exit(scanExitCode(result.action, config.mode));
45214
45282
  }
45215
45283
  function mergeProjectConfig(config, _argv) {
45216
45284
  return config;
@@ -45927,7 +45995,7 @@ var import_chalk5, MAX_PACKAGE_LOCK_BYTES, NUDGE_INTERVAL_MS;
45927
45995
  var init_static_output = __esm({
45928
45996
  "src/formatters/static-output.ts"() {
45929
45997
  "use strict";
45930
- import_chalk5 = __toESM(require_source());
45998
+ import_chalk5 = __toESM(require_source(), 1);
45931
45999
  init_paths();
45932
46000
  init_client();
45933
46001
  init_auth();
@@ -46056,7 +46124,7 @@ function isEngineResolvable() {
46056
46124
  }
46057
46125
  }
46058
46126
  async function renderStatusHuman(s) {
46059
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
46127
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
46060
46128
  const out = [];
46061
46129
  out.push("\n");
46062
46130
  out.push(` ${chalk18.bold("Dependency Guardian")} ${chalk18.dim(s.update.current)}
@@ -46074,7 +46142,7 @@ async function renderStatusHuman(s) {
46074
46142
  authGlyph = chalk18.green("\u2713");
46075
46143
  authLine = "signed in";
46076
46144
  } else {
46077
- const usage = s.auth.scansLimit === null ? "unlimited scans" : `${s.auth.scansUsed ?? 0}/${s.auth.scansLimit} scans this month`;
46145
+ const usage = s.auth.scansLimit === null ? "unlimited packages" : `${(s.auth.scansUsed ?? 0).toLocaleString()}/${s.auth.scansLimit.toLocaleString()} packages this month`;
46078
46146
  authGlyph = chalk18.green("\u2713");
46079
46147
  authLine = `${s.auth.tier ?? "free"} tier \xB7 ${usage}`;
46080
46148
  }
@@ -46198,7 +46266,7 @@ var import_chalk6, USAGE2;
46198
46266
  var init_config2 = __esm({
46199
46267
  "src/commands/config.ts"() {
46200
46268
  "use strict";
46201
- import_chalk6 = __toESM(require_source());
46269
+ import_chalk6 = __toESM(require_source(), 1);
46202
46270
  init_auth();
46203
46271
  USAGE2 = `
46204
46272
  dg config \u2014 view or set persisted CLI preferences
@@ -46304,7 +46372,7 @@ var import_chalk7, SINK_RANKS, CSV_FORMULA_PREFIXES;
46304
46372
  var init_license_export = __esm({
46305
46373
  "src/formatters/license-export.ts"() {
46306
46374
  "use strict";
46307
- import_chalk7 = __toESM(require_source());
46375
+ import_chalk7 = __toESM(require_source(), 1);
46308
46376
  SINK_RANKS = { "no-license": 2, unknown: 1 };
46309
46377
  CSV_FORMULA_PREFIXES = /* @__PURE__ */ new Set(["=", "+", "-", "@", " ", "\r"]);
46310
46378
  }
@@ -46367,9 +46435,9 @@ var init_ScoreHeader = __esm({
46367
46435
  async "src/ui/components/ScoreHeader.tsx"() {
46368
46436
  "use strict";
46369
46437
  await init_build2();
46370
- import_chalk8 = __toESM(require_source());
46438
+ import_chalk8 = __toESM(require_source(), 1);
46371
46439
  await init_useTerminalSize();
46372
- import_jsx_runtime6 = __toESM(require_jsx_runtime());
46440
+ import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
46373
46441
  LOGO_DATA = (() => {
46374
46442
  const W = 22, H = 28;
46375
46443
  const grid = Array.from({ length: H }, () => Array(W).fill(0));
@@ -46417,7 +46485,8 @@ var init_ScoreHeader = __esm({
46417
46485
  flagged,
46418
46486
  clean,
46419
46487
  userStatus,
46420
- scanUsage
46488
+ scanUsage,
46489
+ usageNearLimit
46421
46490
  }) => {
46422
46491
  const logo = renderLogo(action);
46423
46492
  const { cols } = useTerminalSize();
@@ -46457,7 +46526,10 @@ var init_ScoreHeader = __esm({
46457
46526
  import_chalk8.default.green("all clean")
46458
46527
  ] })
46459
46528
  ] }),
46460
- scanUsage && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { dimColor: true, children: scanUsage })
46529
+ scanUsage && (usageNearLimit ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Text, { color: "yellow", children: [
46530
+ scanUsage,
46531
+ " \u2191 dg upgrade for Pro"
46532
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { dimColor: true, children: scanUsage }))
46461
46533
  ] })
46462
46534
  ] }),
46463
46535
  showLogo && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Box_default, { flexDirection: "column", marginLeft: 2, children: logo.map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: line }, i)) })
@@ -46510,7 +46582,7 @@ var import_react29;
46510
46582
  var init_useExpandAnimation = __esm({
46511
46583
  "src/ui/hooks/useExpandAnimation.ts"() {
46512
46584
  "use strict";
46513
- import_react29 = __toESM(require_react());
46585
+ import_react29 = __toESM(require_react(), 1);
46514
46586
  }
46515
46587
  });
46516
46588
 
@@ -46683,16 +46755,16 @@ var import_react30, import_chalk9, import_jsx_runtime7, SEVERITY_LABELS, SEVERIT
46683
46755
  var init_InteractiveResultsView = __esm({
46684
46756
  async "src/ui/components/InteractiveResultsView.tsx"() {
46685
46757
  "use strict";
46686
- import_react30 = __toESM(require_react());
46758
+ import_react30 = __toESM(require_react(), 1);
46687
46759
  await init_build2();
46688
- import_chalk9 = __toESM(require_source());
46760
+ import_chalk9 = __toESM(require_source(), 1);
46689
46761
  init_auth();
46690
46762
  await init_ScoreHeader();
46691
46763
  init_useExpandAnimation();
46692
46764
  await init_useTerminalSize();
46693
46765
  init_terminal_state();
46694
46766
  init_format_helpers();
46695
- import_jsx_runtime7 = __toESM(require_jsx_runtime());
46767
+ import_jsx_runtime7 = __toESM(require_jsx_runtime(), 1);
46696
46768
  SEVERITY_LABELS = {
46697
46769
  5: "CRIT",
46698
46770
  4: "HIGH",
@@ -46721,7 +46793,9 @@ var init_InteractiveResultsView = __esm({
46721
46793
  scanUsage: scanUsageProp,
46722
46794
  initialView
46723
46795
  }) => {
46724
- const scanUsage = result.freeScansRemaining !== void 0 ? `${result.freeScansRemaining} scans left` : scanUsageProp;
46796
+ const usageDisplay = result.usage ? formatUsage(result.usage) : null;
46797
+ const scanUsage = usageDisplay ? usageDisplay.text : result.freeScansRemaining !== void 0 ? `${result.freeScansRemaining.toLocaleString()} packages left` : scanUsageProp;
46798
+ const usageNearLimit = usageDisplay?.nearLimit ?? false;
46725
46799
  const flagged = (0, import_react30.useMemo)(
46726
46800
  () => result.packages.filter((p) => p.score > 0),
46727
46801
  [result.packages]
@@ -47422,7 +47496,8 @@ var init_InteractiveResultsView = __esm({
47422
47496
  flagged: flagged.length,
47423
47497
  clean: clean.length,
47424
47498
  userStatus,
47425
- scanUsage
47499
+ scanUsage,
47500
+ usageNearLimit
47426
47501
  }
47427
47502
  ),
47428
47503
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingLeft: 2, paddingRight: 2, children: [
@@ -47466,7 +47541,8 @@ var init_InteractiveResultsView = __esm({
47466
47541
  flagged: flagged.length,
47467
47542
  clean: clean.length,
47468
47543
  userStatus,
47469
- scanUsage
47544
+ scanUsage,
47545
+ usageNearLimit
47470
47546
  }
47471
47547
  ),
47472
47548
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
@@ -47613,7 +47689,8 @@ var init_InteractiveResultsView = __esm({
47613
47689
  flagged: flagged.length,
47614
47690
  clean: clean.length,
47615
47691
  userStatus,
47616
- scanUsage
47692
+ scanUsage,
47693
+ usageNearLimit
47617
47694
  }
47618
47695
  ),
47619
47696
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Box_default, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingLeft: 2, paddingRight: 2, width: "100%", children: [
@@ -47714,7 +47791,8 @@ var init_InteractiveResultsView = __esm({
47714
47791
  flagged: flagged.length,
47715
47792
  clean: clean.length,
47716
47793
  userStatus,
47717
- scanUsage
47794
+ scanUsage,
47795
+ usageNearLimit
47718
47796
  }
47719
47797
  ),
47720
47798
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: import_chalk9.default.dim("\u2500".repeat(Math.max(20, termCols - 4))) }),
@@ -47820,7 +47898,8 @@ var init_InteractiveResultsView = __esm({
47820
47898
  flagged: flagged.length,
47821
47899
  clean: clean.length,
47822
47900
  userStatus,
47823
- scanUsage
47901
+ scanUsage,
47902
+ usageNearLimit
47824
47903
  }
47825
47904
  ),
47826
47905
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: true, children: import_chalk9.default.dim("\u2500".repeat(Math.max(20, termCols - 4))) }),
@@ -47908,7 +47987,8 @@ var init_InteractiveResultsView = __esm({
47908
47987
  flagged: flagged.length,
47909
47988
  clean: clean.length,
47910
47989
  userStatus,
47911
- scanUsage
47990
+ scanUsage,
47991
+ usageNearLimit
47912
47992
  }
47913
47993
  ),
47914
47994
  groups.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
@@ -48260,7 +48340,7 @@ function toAPIResponse(results) {
48260
48340
  };
48261
48341
  }
48262
48342
  async function renderTui(results) {
48263
- const React22 = (await Promise.resolve().then(() => __toESM(require_react()))).default;
48343
+ const React22 = (await Promise.resolve().then(() => __toESM(require_react(), 1))).default;
48264
48344
  const { render: render2, Box: Box2 } = await init_build2().then(() => build_exports);
48265
48345
  const { InteractiveResultsView: InteractiveResultsView2 } = await init_InteractiveResultsView().then(() => InteractiveResultsView_exports);
48266
48346
  const { enterTui: enterTui2, leaveTui: leaveTui2 } = await Promise.resolve().then(() => (init_terminal_state(), terminal_state_exports));
@@ -48302,7 +48382,7 @@ async function handleLicensesCommand() {
48302
48382
  return;
48303
48383
  }
48304
48384
  const config = parseConfig(process.argv, false);
48305
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
48385
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
48306
48386
  let discovery;
48307
48387
  try {
48308
48388
  discovery = await discoverLicenseTargets(process.cwd(), config);
@@ -49661,7 +49741,7 @@ var import_chalk10, PKG_NAME2, FETCH_TIMEOUT_MS, USAGE4;
49661
49741
  var init_update = __esm({
49662
49742
  "src/commands/update.ts"() {
49663
49743
  "use strict";
49664
- import_chalk10 = __toESM(require_source());
49744
+ import_chalk10 = __toESM(require_source(), 1);
49665
49745
  init_paths();
49666
49746
  init_update_check();
49667
49747
  PKG_NAME2 = "@westbayberry/dg";
@@ -50092,7 +50172,7 @@ var import_chalk11, REVOKE_TIMEOUT_MS, USAGE5;
50092
50172
  var init_uninstall = __esm({
50093
50173
  "src/commands/uninstall.ts"() {
50094
50174
  "use strict";
50095
- import_chalk11 = __toESM(require_source());
50175
+ import_chalk11 = __toESM(require_source(), 1);
50096
50176
  init_paths();
50097
50177
  init_hooks_registry();
50098
50178
  init_hook();
@@ -50375,7 +50455,7 @@ var import_chalk12, USAGE6;
50375
50455
  var init_verify = __esm({
50376
50456
  "src/commands/verify.ts"() {
50377
50457
  "use strict";
50378
- import_chalk12 = __toESM(require_source());
50458
+ import_chalk12 = __toESM(require_source(), 1);
50379
50459
  init_config();
50380
50460
  init_client();
50381
50461
  init_npm_wrapper();
@@ -50434,11 +50514,11 @@ var import_react31, import_jsx_runtime8, ConfettiDemoApp;
50434
50514
  var init_ConfettiDemoApp = __esm({
50435
50515
  async "src/ui/apps/ConfettiDemoApp.tsx"() {
50436
50516
  "use strict";
50437
- import_react31 = __toESM(require_react());
50517
+ import_react31 = __toESM(require_react(), 1);
50438
50518
  await init_build2();
50439
50519
  await init_Confetti();
50440
50520
  await init_useTerminalSize();
50441
- import_jsx_runtime8 = __toESM(require_jsx_runtime());
50521
+ import_jsx_runtime8 = __toESM(require_jsx_runtime(), 1);
50442
50522
  ConfettiDemoApp = () => {
50443
50523
  const { exit } = use_app_default();
50444
50524
  const { cols, rows } = useTerminalSize();
@@ -50490,7 +50570,7 @@ var import_react32, USAGE7;
50490
50570
  var init_confetti = __esm({
50491
50571
  "src/commands/confetti.ts"() {
50492
50572
  "use strict";
50493
- import_react32 = __toESM(require_react());
50573
+ import_react32 = __toESM(require_react(), 1);
50494
50574
  USAGE7 = `
50495
50575
  dg confetti \u2014 preview the terminal confetti effect (dev)
50496
50576
 
@@ -50559,7 +50639,7 @@ function reducer3(_state, action) {
50559
50639
  case "ERROR":
50560
50640
  return { phase: "error", error: action.error };
50561
50641
  case "FREE_CAP_REACHED":
50562
- return { phase: "free_cap_reached", scansUsed: action.scansUsed, maxScans: action.maxScans };
50642
+ return { phase: "free_cap_reached", scansUsed: action.scansUsed, maxScans: action.maxScans, capReason: action.capReason };
50563
50643
  }
50564
50644
  }
50565
50645
  function useScan(config) {
@@ -50620,7 +50700,7 @@ async function runNpmScan(packages, skippedCount, config, dispatch) {
50620
50700
  dispatch({ type: "SCAN_COMPLETE", result, durationMs: Date.now() - startMs, skippedCount });
50621
50701
  } catch (error) {
50622
50702
  if (error instanceof FreeCapReachedError) {
50623
- dispatch({ type: "FREE_CAP_REACHED", scansUsed: error.scansUsed, maxScans: error.maxScans });
50703
+ dispatch({ type: "FREE_CAP_REACHED", scansUsed: error.scansUsed, maxScans: error.maxScans, capReason: error.reason });
50624
50704
  return;
50625
50705
  }
50626
50706
  const err = error instanceof Error ? error : new Error(String(error));
@@ -50711,7 +50791,7 @@ async function scanProjects(projects, config, dispatch) {
50711
50791
  dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0, discoveredTotal });
50712
50792
  } catch (error) {
50713
50793
  if (error instanceof FreeCapReachedError) {
50714
- dispatch({ type: "FREE_CAP_REACHED", scansUsed: error.scansUsed, maxScans: error.maxScans });
50794
+ dispatch({ type: "FREE_CAP_REACHED", scansUsed: error.scansUsed, maxScans: error.maxScans, capReason: error.reason });
50715
50795
  return;
50716
50796
  }
50717
50797
  const err = error instanceof Error ? error : new Error(String(error));
@@ -50723,7 +50803,7 @@ var import_react33;
50723
50803
  var init_useScan = __esm({
50724
50804
  "src/ui/hooks/useScan.ts"() {
50725
50805
  "use strict";
50726
- import_react33 = __toESM(require_react());
50806
+ import_react33 = __toESM(require_react(), 1);
50727
50807
  init_lockfile();
50728
50808
  init_client();
50729
50809
  init_walker();
@@ -50761,12 +50841,12 @@ var import_react34, import_chalk13, import_jsx_runtime9, ProgressBar;
50761
50841
  var init_ProgressBar = __esm({
50762
50842
  async "src/ui/components/ProgressBar.tsx"() {
50763
50843
  "use strict";
50764
- import_react34 = __toESM(require_react());
50844
+ import_react34 = __toESM(require_react(), 1);
50765
50845
  await init_build2();
50766
50846
  await init_build3();
50767
- import_chalk13 = __toESM(require_source());
50847
+ import_chalk13 = __toESM(require_source(), 1);
50768
50848
  await init_useTerminalSize();
50769
- import_jsx_runtime9 = __toESM(require_jsx_runtime());
50849
+ import_jsx_runtime9 = __toESM(require_jsx_runtime(), 1);
50770
50850
  ProgressBar = ({
50771
50851
  value,
50772
50852
  total,
@@ -50863,9 +50943,9 @@ var init_ErrorView = __esm({
50863
50943
  async "src/ui/components/ErrorView.tsx"() {
50864
50944
  "use strict";
50865
50945
  await init_build2();
50866
- import_chalk14 = __toESM(require_source());
50946
+ import_chalk14 = __toESM(require_source(), 1);
50867
50947
  init_sanitize();
50868
- import_jsx_runtime10 = __toESM(require_jsx_runtime());
50948
+ import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
50869
50949
  ErrorView = ({ error }) => {
50870
50950
  const hint = getHint(error);
50871
50951
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
@@ -50896,12 +50976,12 @@ var import_react35, import_chalk15, import_jsx_runtime11, ProjectSelector;
50896
50976
  var init_ProjectSelector = __esm({
50897
50977
  async "src/ui/components/ProjectSelector.tsx"() {
50898
50978
  "use strict";
50899
- import_react35 = __toESM(require_react());
50979
+ import_react35 = __toESM(require_react(), 1);
50900
50980
  await init_build2();
50901
- import_chalk15 = __toESM(require_source());
50981
+ import_chalk15 = __toESM(require_source(), 1);
50902
50982
  init_sanitize();
50903
50983
  await init_useTerminalSize();
50904
- import_jsx_runtime11 = __toESM(require_jsx_runtime());
50984
+ import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
50905
50985
  ProjectSelector = ({ projects, onConfirm, onCancel, userStatus }) => {
50906
50986
  const [cursor, setCursor] = (0, import_react35.useState)(0);
50907
50987
  const [selected, setSelected] = (0, import_react35.useState)(() => new Set(projects.map((_, i) => i)));
@@ -50996,7 +51076,7 @@ var init_SetupBanner = __esm({
50996
51076
  async "src/ui/components/SetupBanner.tsx"() {
50997
51077
  "use strict";
50998
51078
  await init_build2();
50999
- import_jsx_runtime12 = __toESM(require_jsx_runtime());
51079
+ import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
51000
51080
  SetupBanner = ({ issues }) => {
51001
51081
  if (issues.length === 0) return null;
51002
51082
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
@@ -51039,7 +51119,7 @@ var import_react36, import_jsx_runtime13, App2;
51039
51119
  var init_App2 = __esm({
51040
51120
  async "src/ui/App.tsx"() {
51041
51121
  "use strict";
51042
- import_react36 = __toESM(require_react());
51122
+ import_react36 = __toESM(require_react(), 1);
51043
51123
  await init_build2();
51044
51124
  init_auth();
51045
51125
  init_useScan();
@@ -51051,7 +51131,7 @@ var init_App2 = __esm({
51051
51131
  await init_SetupBanner();
51052
51132
  await init_useTerminalSize();
51053
51133
  init_terminal_state();
51054
- import_jsx_runtime13 = __toESM(require_jsx_runtime());
51134
+ import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
51055
51135
  App2 = ({ config, userStatus, scanUsage, setupIssues = [] }) => {
51056
51136
  const { state, scanSelectedProjects, restartSelection } = useScan(config);
51057
51137
  const { exit } = use_app_default();
@@ -51135,7 +51215,7 @@ var init_App2 = __esm({
51135
51215
  exit();
51136
51216
  }
51137
51217
  }
51138
- if (state.phase === "trial_exhausted") {
51218
+ if (state.phase === "free_cap_reached") {
51139
51219
  if (input === "q" || key.escape || key.return) {
51140
51220
  process.exitCode = 1;
51141
51221
  leaveAltScreen();
@@ -51188,7 +51268,7 @@ var init_App2 = __esm({
51188
51268
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: state.message });
51189
51269
  case "error":
51190
51270
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ErrorView, { error: state.error });
51191
- case "trial_exhausted": {
51271
+ case "free_cap_reached": {
51192
51272
  let hasKey = false;
51193
51273
  try {
51194
51274
  hasKey = !!getStoredApiKey();
@@ -51205,12 +51285,25 @@ var init_App2 = __esm({
51205
51285
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
51206
51286
  " to re-authenticate."
51207
51287
  ] })
51208
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
51209
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "yellow", bold: true, children: "You've used your 5 free anonymous scans." }),
51288
+ ] }) : state.capReason === "prefix_cap" ? /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
51289
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "yellow", bold: true, children: "Too many anonymous devices from your network this month." }),
51210
51290
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { children: [
51211
- "Run ",
51291
+ "Sign in with ",
51212
51292
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg login" }),
51213
- " to access Dependency Guardian for free."
51293
+ " to keep scanning."
51294
+ ] })
51295
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(import_jsx_runtime13.Fragment, { children: [
51296
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { color: "yellow", bold: true, children: [
51297
+ "Free monthly limit reached (",
51298
+ state.scansUsed.toLocaleString(),
51299
+ "/",
51300
+ state.maxScans.toLocaleString(),
51301
+ " packages)."
51302
+ ] }),
51303
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Text, { children: [
51304
+ "Upgrade to Pro with ",
51305
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { color: "cyan", bold: true, children: "dg upgrade" }),
51306
+ " for 250k packages/month."
51214
51307
  ] })
51215
51308
  ] }),
51216
51309
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: " " }),
@@ -51581,7 +51674,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51581
51674
  const result = await opts.callAnalyze(resolved, config);
51582
51675
  if (result.action === "pass") {
51583
51676
  if (exit) exit();
51584
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
51677
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
51585
51678
  const line = formatPassLine(result, chalk18);
51586
51679
  process.stderr.write(" " + line + "\n\n");
51587
51680
  const code = await opts.runInstall(parsed.rawArgs);
@@ -51700,7 +51793,7 @@ var import_react37, NPM_OPTIONS, PIP_OPTIONS;
51700
51793
  var init_useWrapperBase = __esm({
51701
51794
  "src/ui/hooks/useWrapperBase.ts"() {
51702
51795
  "use strict";
51703
- import_react37 = __toESM(require_react());
51796
+ import_react37 = __toESM(require_react(), 1);
51704
51797
  init_client();
51705
51798
  init_npm_wrapper();
51706
51799
  init_pip_wrapper();
@@ -51732,7 +51825,7 @@ var init_DurationLine = __esm({
51732
51825
  async "src/ui/components/DurationLine.tsx"() {
51733
51826
  "use strict";
51734
51827
  await init_build2();
51735
- import_jsx_runtime14 = __toESM(require_jsx_runtime());
51828
+ import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
51736
51829
  DurationLine = ({ ms }) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Text, { dimColor: true, children: [
51737
51830
  "Completed in ",
51738
51831
  (ms / 1e3).toFixed(1),
@@ -51759,11 +51852,11 @@ var init_ResultsView = __esm({
51759
51852
  async "src/ui/components/ResultsView.tsx"() {
51760
51853
  "use strict";
51761
51854
  await init_build2();
51762
- import_chalk16 = __toESM(require_source());
51855
+ import_chalk16 = __toESM(require_source(), 1);
51763
51856
  await init_ScoreHeader();
51764
51857
  await init_DurationLine();
51765
51858
  init_format_helpers();
51766
- import_jsx_runtime15 = __toESM(require_jsx_runtime());
51859
+ import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
51767
51860
  SEVERITY_LABELS2 = {
51768
51861
  5: "CRITICAL",
51769
51862
  4: "HIGH",
@@ -51883,8 +51976,8 @@ var init_ConfirmPrompt = __esm({
51883
51976
  "use strict";
51884
51977
  await init_build2();
51885
51978
  await init_build2();
51886
- import_chalk17 = __toESM(require_source());
51887
- import_jsx_runtime16 = __toESM(require_jsx_runtime());
51979
+ import_chalk17 = __toESM(require_source(), 1);
51980
+ import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
51888
51981
  ConfirmPrompt = ({
51889
51982
  message,
51890
51983
  onConfirm,
@@ -51946,7 +52039,7 @@ var init_WrapperVerdictLine = __esm({
51946
52039
  async "src/ui/components/WrapperVerdictLine.tsx"() {
51947
52040
  "use strict";
51948
52041
  await init_build2();
51949
- import_jsx_runtime17 = __toESM(require_jsx_runtime());
52042
+ import_jsx_runtime17 = __toESM(require_jsx_runtime(), 1);
51950
52043
  WrapperVerdictLine = ({
51951
52044
  result,
51952
52045
  verdict,
@@ -52043,7 +52136,7 @@ var import_react38, import_jsx_runtime18, LABELS, WrapperApp;
52043
52136
  var init_WrapperApp = __esm({
52044
52137
  async "src/ui/apps/WrapperApp.tsx"() {
52045
52138
  "use strict";
52046
- import_react38 = __toESM(require_react());
52139
+ import_react38 = __toESM(require_react(), 1);
52047
52140
  await init_build2();
52048
52141
  init_auth();
52049
52142
  init_useWrapperBase();
@@ -52052,7 +52145,7 @@ var init_WrapperApp = __esm({
52052
52145
  await init_ConfirmPrompt();
52053
52146
  await init_ErrorView();
52054
52147
  await init_WrapperVerdictLine();
52055
- import_jsx_runtime18 = __toESM(require_jsx_runtime());
52148
+ import_jsx_runtime18 = __toESM(require_jsx_runtime(), 1);
52056
52149
  LABELS = {
52057
52150
  npm: {
52058
52151
  resolving: (n, s) => `Resolving ${n} package${s}...`,
@@ -52080,7 +52173,7 @@ var init_WrapperApp = __esm({
52080
52173
  const timer = setTimeout(() => exit(), 0);
52081
52174
  return () => clearTimeout(timer);
52082
52175
  }
52083
- if (state.phase === "trial_exhausted") {
52176
+ if (state.phase === "free_cap_reached") {
52084
52177
  process.exitCode = 1;
52085
52178
  const timer = setTimeout(() => exit(), 0);
52086
52179
  return () => clearTimeout(timer);
@@ -52123,7 +52216,7 @@ var init_WrapperApp = __esm({
52123
52216
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorView, { error: new Error(state.message) });
52124
52217
  case "passthrough":
52125
52218
  return null;
52126
- case "trial_exhausted": {
52219
+ case "free_cap_reached": {
52127
52220
  let hasKey = false;
52128
52221
  try {
52129
52222
  hasKey = !!getStoredApiKey();
@@ -52215,7 +52308,7 @@ var import_chalk18, INSTALL_COMMANDS3, adapter;
52215
52308
  var init_conda_wrapper = __esm({
52216
52309
  "src/commands/conda-wrapper.ts"() {
52217
52310
  "use strict";
52218
- import_chalk18 = __toESM(require_source());
52311
+ import_chalk18 = __toESM(require_source(), 1);
52219
52312
  init_wrapper_shared();
52220
52313
  init_resolve();
52221
52314
  init_install();
@@ -53028,7 +53121,7 @@ var import_chalk19;
53028
53121
  var init_wrapper_factory = __esm({
53029
53122
  "src/commands/wrapper-factory.ts"() {
53030
53123
  "use strict";
53031
- import_chalk19 = __toESM(require_source());
53124
+ import_chalk19 = __toESM(require_source(), 1);
53032
53125
  init_client();
53033
53126
  init_resolve();
53034
53127
  init_install();
@@ -53352,7 +53445,7 @@ async function maybeShowWiringHint(rawCommand) {
53352
53445
  const hintMarker = dgStatePath2("wiring-hint-shown");
53353
53446
  if (existsSync26(receiptPath) || existsSync26(shimPath)) return;
53354
53447
  if (existsSync26(hintMarker)) return;
53355
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53448
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53356
53449
  process.stderr.write(
53357
53450
  `
53358
53451
  ${chalk18.yellow("\u2139 Shell wiring not detected.")} Reinstall with ${chalk18.cyan("npm install -g @westbayberry/dg")}
@@ -53395,7 +53488,7 @@ async function main() {
53395
53488
  }
53396
53489
  const KNOWN_COMMANDS = ["scan", "licenses", "login", "logout", "upgrade", "status", "hook", "config", "update", "help", "version", "publish-check", "uninstall", "verify", "gallery", "confetti", "__wrap"];
53397
53490
  if (rawCommand && !rawCommand.startsWith("-") && !KNOWN_COMMANDS.includes(rawCommand)) {
53398
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53491
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53399
53492
  const best = closestCommand(rawCommand, KNOWN_COMMANDS);
53400
53493
  const hint = best ? ` Did you mean '${best}'?` : "";
53401
53494
  process.stderr.write(`
@@ -53431,7 +53524,7 @@ async function main() {
53431
53524
  const loginArgs = process.argv.slice(3);
53432
53525
  const parsed = parseLoginArgs2(loginArgs);
53433
53526
  if (parsed.kind === "unknown-flag") {
53434
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53527
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53435
53528
  process.stderr.write(`
53436
53529
  ${chalk18.red("Error:")} Unknown option '${parsed.flag}'.
53437
53530
  `);
@@ -53441,7 +53534,7 @@ async function main() {
53441
53534
  process.exit(1);
53442
53535
  }
53443
53536
  if (parsed.kind === "missing-value") {
53444
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53537
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53445
53538
  process.stderr.write(`
53446
53539
  ${chalk18.red("Error:")} ${parsed.flag} requires a value.
53447
53540
 
@@ -53454,7 +53547,7 @@ async function main() {
53454
53547
  }
53455
53548
  if (isInteractive) {
53456
53549
  const { render: render2 } = await init_build2().then(() => build_exports);
53457
- const React22 = await Promise.resolve().then(() => __toESM(require_react()));
53550
+ const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
53458
53551
  const { LoginApp: LoginApp2 } = await init_LoginApp().then(() => LoginApp_exports);
53459
53552
  const { waitUntilExit } = render2(React22.createElement(LoginApp2));
53460
53553
  await waitUntilExit();
@@ -53513,7 +53606,7 @@ async function main() {
53513
53606
  if (wantJson) {
53514
53607
  process.stdout.write(JSON.stringify({ ok: false, error: out.errorMessage }) + "\n");
53515
53608
  } else {
53516
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53609
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53517
53610
  process.stderr.write(`
53518
53611
  ${chalk18.red("publish-check error:")} ${out.errorMessage}
53519
53612
 
@@ -53557,7 +53650,7 @@ async function main() {
53557
53650
  await handleHookCommand2(process.argv.slice(3));
53558
53651
  const updateMsg = await updatePromise2;
53559
53652
  if (updateMsg) {
53560
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53653
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53561
53654
  process.stderr.write(chalk18.dim(updateMsg));
53562
53655
  }
53563
53656
  return;
@@ -53589,7 +53682,7 @@ async function main() {
53589
53682
  }
53590
53683
  if (rawCommand === "logout") {
53591
53684
  const { getStoredApiKey: getStoredApiKey2, clearCredentials: clearCredentials2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
53592
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53685
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53593
53686
  const apiKey = getStoredApiKey2();
53594
53687
  if (apiKey) {
53595
53688
  const { parseConfig: parseConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
@@ -53616,7 +53709,7 @@ async function main() {
53616
53709
  await preflightAuthCheck2(config.apiUrl);
53617
53710
  } catch (err) {
53618
53711
  if (err instanceof PreflightFreeCapReachedError2) {
53619
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53712
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53620
53713
  const { getStoredApiKey: getStoredApiKey2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
53621
53714
  const hasKey = !!getStoredApiKey2();
53622
53715
  process.stderr.write("\n");
@@ -53624,11 +53717,16 @@ async function main() {
53624
53717
  process.stderr.write(chalk18.yellow(" Your API key may be invalid or expired.\n"));
53625
53718
  process.stderr.write(` Run ${chalk18.cyan("dg logout")} then ${chalk18.cyan("dg login")} to re-authenticate.
53626
53719
 
53720
+ `);
53721
+ } else if (err.reason === "prefix_cap") {
53722
+ process.stderr.write(chalk18.yellow(" Too many anonymous devices from your network this month (anti-abuse limit).\n"));
53723
+ process.stderr.write(` Sign in with ${chalk18.cyan("dg login")} to keep scanning.
53724
+
53627
53725
  `);
53628
53726
  } else {
53629
- process.stderr.write(chalk18.yellow(` Free tier monthly cap reached (${err.scansUsed}/${err.maxScans}).
53727
+ process.stderr.write(chalk18.yellow(` Free tier monthly package limit reached (${err.scansUsed.toLocaleString()}/${err.maxScans.toLocaleString()} packages).
53630
53728
  `));
53631
- process.stderr.write(` Run ${chalk18.cyan("dg upgrade")} for Pro (5000/mo) or wait until next month.
53729
+ process.stderr.write(` Run ${chalk18.cyan("dg upgrade")} for Pro or wait until next month.
53632
53730
 
53633
53731
  `);
53634
53732
  }
@@ -53643,13 +53741,13 @@ async function main() {
53643
53741
  await runStatic2(config);
53644
53742
  } else {
53645
53743
  if (config.mode === "off") {
53646
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53744
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53647
53745
  process.stderr.write(chalk18.dim(" Dependency Guardian: mode is off \u2014 skipping.\n"));
53648
53746
  process.exit(0);
53649
53747
  }
53650
53748
  const { getStoredApiKey: getStoredApiKey2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
53651
53749
  const apiKey = getStoredApiKey2();
53652
- const chalkMod = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53750
+ const chalkMod = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53653
53751
  const loginChip = chalkMod.cyan.bold("dg login");
53654
53752
  const freeTierStatus = `${chalkMod.dim("free tier \xB7")} ${loginChip} ${chalkMod.dim("for more")}`;
53655
53753
  const sessionExpiredStatus = `${chalkMod.dim("session expired \xB7")} ${loginChip}`;
@@ -53667,14 +53765,12 @@ async function main() {
53667
53765
  const tier = data.tier || "free";
53668
53766
  const tierColor = tier === "free" ? chalkMod.yellow(tier) : chalkMod.green(tier);
53669
53767
  userStatus = `${chalkMod.dim(name)} ${chalkMod.dim("\xB7")} ${tierColor}`;
53670
- if (data.scansLimit === null || data.scansLimit === void 0) {
53671
- scanUsage = "unlimited scans";
53672
- } else {
53673
- const used = data.scansUsed ?? 0;
53674
- const limit = data.scansLimit;
53675
- const remaining = limit - used;
53676
- scanUsage = `${remaining}/${limit} scans left`;
53677
- }
53768
+ const { formatUsage: formatUsage2 } = await Promise.resolve().then(() => (init_format_helpers(), format_helpers_exports));
53769
+ scanUsage = formatUsage2({
53770
+ used: data.scansUsed ?? 0,
53771
+ limit: data.scansLimit ?? null,
53772
+ tier
53773
+ }).text;
53678
53774
  } else if (resp.status === 401) {
53679
53775
  userStatus = sessionExpiredStatus;
53680
53776
  } else {
@@ -53687,7 +53783,7 @@ async function main() {
53687
53783
  const { getSetupIssues: getSetupIssues2 } = await Promise.resolve().then(() => (init_setup_status(), setup_status_exports));
53688
53784
  const setupIssues = getSetupIssues2(process.cwd());
53689
53785
  const { render: render2 } = await init_build2().then(() => build_exports);
53690
- const React22 = await Promise.resolve().then(() => __toESM(require_react()));
53786
+ const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
53691
53787
  const { App: App3 } = await init_App2().then(() => App_exports);
53692
53788
  const { setInkInstance: setInkInstance2, resetInkClear: resetInkClear2, initInkInstances: initInkInstances2, patchInkLogForAbsolutePositioning: patchInkLogForAbsolutePositioning2 } = await Promise.resolve().then(() => (init_ink_controls(), ink_controls_exports));
53693
53789
  await initInkInstances2();
@@ -53702,7 +53798,7 @@ async function main() {
53702
53798
  }
53703
53799
  const updateMsg = await updatePromise;
53704
53800
  if (updateMsg) {
53705
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53801
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53706
53802
  process.stderr.write(chalk18.dim(updateMsg));
53707
53803
  }
53708
53804
  try {
@@ -53778,7 +53874,7 @@ async function handleWrapInternal(argv) {
53778
53874
  return 0;
53779
53875
  }
53780
53876
  const { render: render2 } = await init_build2().then(() => build_exports);
53781
- const React22 = await Promise.resolve().then(() => __toESM(require_react()));
53877
+ const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
53782
53878
  const { WrapperApp: WrapperApp2 } = await init_WrapperApp().then(() => WrapperApp_exports);
53783
53879
  const { waitUntilExit } = render2(
53784
53880
  React22.createElement(WrapperApp2, { config, args: wrapperArgs, ecosystem: "npm" })
@@ -53793,7 +53889,7 @@ async function handleWrapInternal(argv) {
53793
53889
  return 0;
53794
53890
  }
53795
53891
  const { render: render2 } = await init_build2().then(() => build_exports);
53796
- const React22 = await Promise.resolve().then(() => __toESM(require_react()));
53892
+ const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
53797
53893
  const { WrapperApp: WrapperApp2 } = await init_WrapperApp().then(() => WrapperApp_exports);
53798
53894
  const { waitUntilExit } = render2(
53799
53895
  React22.createElement(WrapperApp2, { config, args: wrapperArgs, ecosystem: "pypi" })
@@ -53838,7 +53934,7 @@ main().catch(async (err) => {
53838
53934
  authenticated: isAuthed
53839
53935
  });
53840
53936
  await flush();
53841
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source()))).default;
53937
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
53842
53938
  const color = err.securityRelease ? chalk18.bold.red : chalk18.yellow;
53843
53939
  if (process.argv.includes("--json")) {
53844
53940
  process.stdout.write(JSON.stringify({
@@ -53876,7 +53972,7 @@ main().catch(async (err) => {
53876
53972
  }, null, 2) + "\n");
53877
53973
  } else {
53878
53974
  try {
53879
- const chalkMod = await Promise.resolve().then(() => __toESM(require_source()));
53975
+ const chalkMod = await Promise.resolve().then(() => __toESM(require_source(), 1));
53880
53976
  process.stderr.write(`
53881
53977
  ${chalkMod.default.bold.red("Error:")} ${err.message}
53882
53978
 
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@westbayberry/dg",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
+ "type": "module",
4
5
  "description": "Supply chain security scanner for npm and Python dependencies — 35 behavioral detectors catch zero-day attacks CVE databases miss. 99.66% catch rate on 155K packages.",
5
6
  "bin": {
6
7
  "dependency-guardian": "dist/index.mjs",