@westbayberry/dg 1.1.5 → 1.2.0

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.
package/dist/index.mjs CHANGED
@@ -910,15 +910,15 @@ var require_route = __commonJS({
910
910
  };
911
911
  }
912
912
  function wrapConversion(toModel, graph) {
913
- const path2 = [graph[toModel].parent, toModel];
913
+ const path = [graph[toModel].parent, toModel];
914
914
  let fn = conversions[graph[toModel].parent][toModel];
915
915
  let cur = graph[toModel].parent;
916
916
  while (graph[cur].parent) {
917
- path2.unshift(graph[cur].parent);
917
+ path.unshift(graph[cur].parent);
918
918
  fn = link2(conversions[graph[cur].parent][cur], fn);
919
919
  cur = graph[cur].parent;
920
920
  }
921
- fn.conversion = path2;
921
+ fn.conversion = path;
922
922
  return fn;
923
923
  }
924
924
  module.exports = function(fromModel) {
@@ -1590,8 +1590,8 @@ var require_source = __commonJS({
1590
1590
  // src/telemetry.ts
1591
1591
  import { platform, arch } from "node:os";
1592
1592
  function telemetryEnabled() {
1593
- if (process.env.DG_TELEMETRY === "0") return false;
1594
1593
  if (process.env.DO_NOT_TRACK === "1") return false;
1594
+ if (process.env.DG_TELEMETRY === "0") return false;
1595
1595
  return true;
1596
1596
  }
1597
1597
  function classifyError(err) {
@@ -2004,17 +2004,17 @@ function ensureConfigDir() {
2004
2004
  mkdirSync(dir, { recursive: true, mode: 448 });
2005
2005
  }
2006
2006
  }
2007
- function ensureConfigPerms(path2) {
2007
+ function ensureConfigPerms(path) {
2008
2008
  let st;
2009
2009
  try {
2010
- st = lstatSync(path2);
2010
+ st = lstatSync(path);
2011
2011
  } catch {
2012
2012
  return;
2013
2013
  }
2014
2014
  if (!st || typeof st.isSymbolicLink !== "function") return;
2015
2015
  if (st.isSymbolicLink()) {
2016
2016
  process.stderr.write(
2017
- `Warning: ${path2} is a symlink; refusing to chmod (would affect the symlink target). Replace with a regular file to enforce 0o600.
2017
+ `Warning: ${path} is a symlink; refusing to chmod (would affect the symlink target). Replace with a regular file to enforce 0o600.
2018
2018
  `
2019
2019
  );
2020
2020
  return;
@@ -2023,12 +2023,12 @@ function ensureConfigPerms(path2) {
2023
2023
  const mode = (st.mode ?? 384) & 511;
2024
2024
  if (mode === 384) return;
2025
2025
  process.stderr.write(
2026
- `Warning: ${path2} has perms 0o${mode.toString(8)} (expected 0o600); re-tightening.
2026
+ `Warning: ${path} has perms 0o${mode.toString(8)} (expected 0o600); re-tightening.
2027
2027
  `
2028
2028
  );
2029
2029
  let fd;
2030
2030
  try {
2031
- fd = openSync(path2, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
2031
+ fd = openSync(path, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
2032
2032
  fchmodSync(fd, 384);
2033
2033
  } catch {
2034
2034
  } finally {
@@ -2185,11 +2185,11 @@ async function fetchCliPolicy(opts) {
2185
2185
  return null;
2186
2186
  }
2187
2187
  }
2188
- async function postCliEvent(path2, body, apiUrl, apiKey, timeoutMs = 3e3) {
2188
+ async function postCliEvent(path, body, apiUrl, apiKey, timeoutMs = 3e3) {
2189
2189
  try {
2190
2190
  const ctrl = new AbortController();
2191
2191
  const timer = setTimeout(() => ctrl.abort(), timeoutMs);
2192
- await globalThis.fetch(`${apiUrl}${path2}`, {
2192
+ await globalThis.fetch(`${apiUrl}${path}`, {
2193
2193
  method: "POST",
2194
2194
  headers: {
2195
2195
  "Content-Type": "application/json",
@@ -2263,9 +2263,9 @@ function authStatusCachePath() {
2263
2263
  }
2264
2264
  function readCachedAuthStatus() {
2265
2265
  try {
2266
- const path2 = authStatusCachePath();
2267
- if (!existsSync(path2)) return null;
2268
- const raw = readFileSync(path2, "utf-8");
2266
+ const path = authStatusCachePath();
2267
+ if (!existsSync(path)) return null;
2268
+ const raw = readFileSync(path, "utf-8");
2269
2269
  const cached = JSON.parse(raw);
2270
2270
  if (typeof cached.fetchedAt !== "number") return null;
2271
2271
  if (Date.now() - cached.fetchedAt > AUTH_STATUS_TTL_MS) return null;
@@ -2276,10 +2276,10 @@ function readCachedAuthStatus() {
2276
2276
  }
2277
2277
  function writeCachedAuthStatus(status) {
2278
2278
  try {
2279
- const path2 = authStatusCachePath();
2280
- const dir = dirname(path2);
2279
+ const path = authStatusCachePath();
2280
+ const dir = dirname(path);
2281
2281
  if (!existsSync(dir)) mkdirSync(dir, { recursive: true, mode: 448 });
2282
- writeFileSync(path2, JSON.stringify(status), { mode: 384 });
2282
+ writeFileSync(path, JSON.stringify(status), { mode: 384 });
2283
2283
  } catch {
2284
2284
  }
2285
2285
  }
@@ -2369,8 +2369,8 @@ async function preflightAuthCheck(apiUrl) {
2369
2369
  }
2370
2370
  function clearAuthStatusCache() {
2371
2371
  try {
2372
- const path2 = authStatusCachePath();
2373
- if (existsSync(path2)) unlinkSync(path2);
2372
+ const path = authStatusCachePath();
2373
+ if (existsSync(path)) unlinkSync(path);
2374
2374
  } catch {
2375
2375
  }
2376
2376
  }
@@ -2816,7 +2816,7 @@ var init_config = __esm({
2816
2816
  DG_DEBUG=1 Enable debug output
2817
2817
  DG_QUIET=1 Same as passing --quiet
2818
2818
  DG_WORKSPACE Workspace subdirectory to scan
2819
- DG_TELEMETRY=1 Opt in to anonymous crash reports (off by default)
2819
+ DG_TELEMETRY=0 Opt out of anonymous crash reports (on by default; DO_NOT_TRACK=1 also opts out)
2820
2820
  DG_FORCE_POSTINSTALL=1 Force postinstall to run even outside a TTY
2821
2821
  (useful for re-running setup manually)
2822
2822
  DG_NO_RC_EDIT=1 Postinstall installs shims but does not edit
@@ -2865,23 +2865,23 @@ function cacheFile() {
2865
2865
  return dgCachePath("update-check.json");
2866
2866
  }
2867
2867
  function readCache() {
2868
- const path2 = cacheFile();
2868
+ const path = cacheFile();
2869
2869
  let stat = null;
2870
2870
  try {
2871
- stat = lstatSync2(path2, { throwIfNoEntry: false }) ?? null;
2871
+ stat = lstatSync2(path, { throwIfNoEntry: false }) ?? null;
2872
2872
  } catch {
2873
2873
  return null;
2874
2874
  }
2875
2875
  if (!stat) return null;
2876
2876
  if (!stat.isFile() || stat.size > MAX_CACHE_BYTES) {
2877
2877
  try {
2878
- unlinkSync2(path2);
2878
+ unlinkSync2(path);
2879
2879
  } catch {
2880
2880
  }
2881
2881
  return null;
2882
2882
  }
2883
2883
  try {
2884
- const raw = readFileSync3(path2, "utf-8");
2884
+ const raw = readFileSync3(path, "utf-8");
2885
2885
  const data = JSON.parse(raw);
2886
2886
  if (typeof data.latest === "string" && typeof data.checkedAt === "number") {
2887
2887
  return data;
@@ -2892,14 +2892,14 @@ function readCache() {
2892
2892
  }
2893
2893
  function writeCache(entry) {
2894
2894
  try {
2895
- const path2 = cacheFile();
2896
- const parent = dirname3(path2);
2895
+ const path = cacheFile();
2896
+ const parent = dirname3(path);
2897
2897
  if (!existsSync3(parent)) mkdirSync2(parent, { recursive: true, mode: 448 });
2898
2898
  const serialized = JSON.stringify(entry);
2899
2899
  if (serialized.length > MAX_CACHE_BYTES) return;
2900
- writeFileSync2(path2, serialized, { encoding: "utf-8", mode: 384 });
2900
+ writeFileSync2(path, serialized, { encoding: "utf-8", mode: 384 });
2901
2901
  try {
2902
- chmodSync2(path2, 384);
2902
+ chmodSync2(path, 384);
2903
2903
  } catch {
2904
2904
  }
2905
2905
  } catch {
@@ -3050,17 +3050,17 @@ function ensureUnderHome(target) {
3050
3050
  throw new UnsafePathError(`refusing to operate on path outside $HOME: ${target}`, target);
3051
3051
  }
3052
3052
  }
3053
- function lstatNoSymlink(path2) {
3053
+ function lstatNoSymlink(path) {
3054
3054
  let st;
3055
3055
  try {
3056
- st = lstatSync3(path2);
3056
+ st = lstatSync3(path);
3057
3057
  } catch (e) {
3058
3058
  const code = e.code;
3059
3059
  if (code === "ENOENT") return;
3060
3060
  throw e;
3061
3061
  }
3062
3062
  if (st.isSymbolicLink()) {
3063
- throw new UnsafePathError(`refusing: ${path2} is a symlink`, path2);
3063
+ throw new UnsafePathError(`refusing: ${path} is a symlink`, path);
3064
3064
  }
3065
3065
  }
3066
3066
  function safeMkdirRecursive(target, mode = 493) {
@@ -3090,9 +3090,9 @@ function atomicWriteFile(target, content, mode = 420) {
3090
3090
  writeFileSync3(tmp, content, { mode });
3091
3091
  renameSync(tmp, target);
3092
3092
  }
3093
- function isExecutable(path2) {
3093
+ function isExecutable(path) {
3094
3094
  try {
3095
- const st = statSync(path2);
3095
+ const st = statSync(path);
3096
3096
  return st.isFile() && (st.mode & 73) !== 0;
3097
3097
  } catch {
3098
3098
  return false;
@@ -3117,9 +3117,9 @@ var init_safe_fs = __esm({
3117
3117
  "src/shims/safe-fs.ts"() {
3118
3118
  "use strict";
3119
3119
  UnsafePathError = class extends Error {
3120
- constructor(message, path2) {
3120
+ constructor(message, path) {
3121
3121
  super(message);
3122
- this.path = path2;
3122
+ this.path = path;
3123
3123
  this.name = "UnsafePathError";
3124
3124
  }
3125
3125
  };
@@ -3151,16 +3151,29 @@ var init_templates = __esm({
3151
3151
  "mamba"
3152
3152
  ];
3153
3153
  UNIX_SHIM_BODY = `#!/bin/sh
3154
+ nonce=$(cat "$HOME/.dg/state/shim-nonce" 2>/dev/null)
3154
3155
  if [ -n "\${DG_SHIM_ACTIVE:-}" ]; then
3155
3156
  cleaned_path=$(printf '%s' "$PATH" | awk -v RS=':' -v ORS=':' '$0 != ENVIRON["HOME"]"/.dg/shims"' | sed 's/:$//')
3156
- real_bin=$(PATH="$cleaned_path" command -v __ECOSYSTEM__)
3157
- if [ -n "$real_bin" ]; then
3158
- exec "$real_bin" "$@"
3157
+ # Only honor DG_SHIM_ACTIVE as the recursion guard when it equals the
3158
+ # on-disk nonce \u2014 that is the value our own wrapper sets before running the
3159
+ # real installer. A non-matching value was set outside dg (stale or a
3160
+ # bypass attempt) and must NOT skip scanning.
3161
+ if [ -n "$nonce" ] && [ "$DG_SHIM_ACTIVE" = "$nonce" ]; then
3162
+ real_bin=$(PATH="$cleaned_path" command -v __ECOSYSTEM__)
3163
+ if [ -n "$real_bin" ]; then
3164
+ exec "$real_bin" "$@"
3165
+ fi
3166
+ echo "dg: real __ECOSYSTEM__ not found on PATH" >&2
3167
+ exit 127
3159
3168
  fi
3160
- echo "dg: real __ECOSYSTEM__ not found on PATH" >&2
3161
- exit 127
3169
+ if [ -z "$nonce" ]; then
3170
+ echo "dg: shim nonce missing (reinstall dg) \u2014 cannot verify; passing through __ECOSYSTEM__ UNSCANNED." >&2
3171
+ real_bin=$(PATH="$cleaned_path" command -v __ECOSYSTEM__)
3172
+ if [ -n "$real_bin" ]; then exec "$real_bin" "$@"; fi
3173
+ exit 127
3174
+ fi
3175
+ echo "dg: ignoring externally-set DG_SHIM_ACTIVE (nonce mismatch); scanning __ECOSYSTEM__." >&2
3162
3176
  fi
3163
- nonce=$(cat "$HOME/.dg/state/shim-nonce" 2>/dev/null)
3164
3177
  dg_entry=$(cat "$HOME/.dg/state/dg-entry" 2>/dev/null)
3165
3178
  if [ -n "$dg_entry" ] && [ -x "$dg_entry" ]; then
3166
3179
  DG_SHIM_ACTIVE="$nonce" DG_SHIM_PARENT_PATH="$PATH" exec "$dg_entry" __wrap __ECOSYSTEM__ "$@"
@@ -3180,6 +3193,8 @@ exit 127
3180
3193
  `;
3181
3194
  WINDOWS_SHIM_BODY = `@echo off
3182
3195
  setlocal enabledelayedexpansion
3196
+ set "DG_SHIM_NONCE="
3197
+ if exist "%USERPROFILE%\\.dg\\state\\shim-nonce" set /p DG_SHIM_NONCE=<"%USERPROFILE%\\.dg\\state\\shim-nonce"
3183
3198
  if not "%DG_SHIM_ACTIVE%"=="" (
3184
3199
  set "_dg_realpath="
3185
3200
  for /f "tokens=*" %%i in ('where __ECOSYSTEM__ 2^>nul') do (
@@ -3187,15 +3202,25 @@ if not "%DG_SHIM_ACTIVE%"=="" (
3187
3202
  if not defined _dg_realpath set "_dg_realpath=%%i"
3188
3203
  )
3189
3204
  )
3190
- if defined _dg_realpath (
3191
- "!_dg_realpath!" %*
3192
- exit /b !errorlevel!
3205
+ rem Only honor DG_SHIM_ACTIVE as the recursion guard when it equals the nonce.
3206
+ if "%DG_SHIM_ACTIVE%"=="!DG_SHIM_NONCE!" (
3207
+ if defined _dg_realpath (
3208
+ "!_dg_realpath!" %*
3209
+ exit /b !errorlevel!
3210
+ )
3211
+ echo dg: real __ECOSYSTEM__ not found on PATH 1>&2
3212
+ exit /b 127
3193
3213
  )
3194
- echo dg: real __ECOSYSTEM__ not found on PATH 1>&2
3195
- exit /b 127
3214
+ if "!DG_SHIM_NONCE!"=="" (
3215
+ echo dg: shim nonce missing ^(reinstall dg^) -- passing through __ECOSYSTEM__ UNSCANNED. 1>&2
3216
+ if defined _dg_realpath (
3217
+ "!_dg_realpath!" %*
3218
+ exit /b !errorlevel!
3219
+ )
3220
+ exit /b 127
3221
+ )
3222
+ echo dg: ignoring externally-set DG_SHIM_ACTIVE ^(nonce mismatch^); scanning __ECOSYSTEM__. 1>&2
3196
3223
  )
3197
- set "DG_SHIM_NONCE="
3198
- if exist "%USERPROFILE%\\.dg\\state\\shim-nonce" set /p DG_SHIM_NONCE=<"%USERPROFILE%\\.dg\\state\\shim-nonce"
3199
3224
  set "DG_ENTRY="
3200
3225
  if exist "%USERPROFILE%\\.dg\\state\\dg-entry" set /p DG_ENTRY=<"%USERPROFILE%\\.dg\\state\\dg-entry"
3201
3226
  set "DG_SHIM_ACTIVE=!DG_SHIM_NONCE!"
@@ -3237,9 +3262,9 @@ exit /b 127
3237
3262
  import { homedir as homedir3 } from "node:os";
3238
3263
  import { join as join3 } from "node:path";
3239
3264
  import { existsSync as existsSync5, readFileSync as readFileSync4, lstatSync as lstatSync4, appendFileSync, writeFileSync as writeFileSync4 } from "node:fs";
3240
- function expandHome(path2) {
3241
- if (path2.startsWith("~/")) return join3(homedir3(), path2.slice(2));
3242
- return path2;
3265
+ function expandHome(path) {
3266
+ if (path.startsWith("~/")) return join3(homedir3(), path.slice(2));
3267
+ return path;
3243
3268
  }
3244
3269
  function detectShellKind(envShell) {
3245
3270
  const s = (envShell ?? "").toLowerCase();
@@ -3463,6 +3488,7 @@ var init_resolve = __esm({
3463
3488
  var install_exports = {};
3464
3489
  __export(install_exports, {
3465
3490
  bypassLogPath: () => bypassLogPath,
3491
+ childInstallEnv: () => childInstallEnv,
3466
3492
  currentDgEntry: () => currentDgEntry,
3467
3493
  dgShimDir: () => dgShimDir,
3468
3494
  ensureDgEntryRecorded: () => ensureDgEntryRecorded,
@@ -3509,15 +3535,15 @@ function ensureDgEntryRecorded(targetHome = homedir5()) {
3509
3535
  try {
3510
3536
  const entry = currentDgEntry();
3511
3537
  if (!entry) return;
3512
- const path2 = dgEntryStatePath(targetHome);
3538
+ const path = dgEntryStatePath(targetHome);
3513
3539
  let existing = null;
3514
3540
  try {
3515
- existing = readFileSync6(path2, "utf-8").trim();
3541
+ existing = readFileSync6(path, "utf-8").trim();
3516
3542
  } catch {
3517
3543
  }
3518
3544
  if (existing === entry) return;
3519
- safeMkdirRecursive(dirname5(path2), 493);
3520
- safeWriteFile(path2, entry + "\n", 420);
3545
+ safeMkdirRecursive(dirname5(path), 493);
3546
+ safeWriteFile(path, entry + "\n", 420);
3521
3547
  } catch {
3522
3548
  }
3523
3549
  }
@@ -3529,11 +3555,21 @@ function readNonce() {
3529
3555
  return null;
3530
3556
  }
3531
3557
  }
3532
- function chownIfNeeded(path2, uid, gid) {
3558
+ function childInstallEnv() {
3559
+ const env3 = {};
3560
+ for (const [k, v] of Object.entries(process.env)) {
3561
+ if (k.startsWith("DG_")) continue;
3562
+ env3[k] = v;
3563
+ }
3564
+ const nonce = readNonce();
3565
+ if (nonce) env3.DG_SHIM_ACTIVE = nonce;
3566
+ return env3;
3567
+ }
3568
+ function chownIfNeeded(path, uid, gid) {
3533
3569
  if (uid === void 0 || gid === void 0) return;
3534
3570
  if (process.platform === "win32") return;
3535
3571
  try {
3536
- chownSync(path2, uid, gid);
3572
+ chownSync(path, uid, gid);
3537
3573
  } catch {
3538
3574
  }
3539
3575
  }
@@ -28803,10 +28839,10 @@ var require_react_reconciler_development = __commonJS({
28803
28839
  var setErrorHandler = null;
28804
28840
  var setSuspenseHandler = null;
28805
28841
  {
28806
- var copyWithDeleteImpl = function(obj, path2, index2) {
28807
- var key = path2[index2];
28842
+ var copyWithDeleteImpl = function(obj, path, index2) {
28843
+ var key = path[index2];
28808
28844
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
28809
- if (index2 + 1 === path2.length) {
28845
+ if (index2 + 1 === path.length) {
28810
28846
  if (isArray(updated)) {
28811
28847
  updated.splice(key, 1);
28812
28848
  } else {
@@ -28814,11 +28850,11 @@ var require_react_reconciler_development = __commonJS({
28814
28850
  }
28815
28851
  return updated;
28816
28852
  }
28817
- updated[key] = copyWithDeleteImpl(obj[key], path2, index2 + 1);
28853
+ updated[key] = copyWithDeleteImpl(obj[key], path, index2 + 1);
28818
28854
  return updated;
28819
28855
  };
28820
- var copyWithDelete = function(obj, path2) {
28821
- return copyWithDeleteImpl(obj, path2, 0);
28856
+ var copyWithDelete = function(obj, path) {
28857
+ return copyWithDeleteImpl(obj, path, 0);
28822
28858
  };
28823
28859
  var copyWithRenameImpl = function(obj, oldPath, newPath, index2) {
28824
28860
  var oldKey = oldPath[index2];
@@ -28856,17 +28892,17 @@ var require_react_reconciler_development = __commonJS({
28856
28892
  }
28857
28893
  return copyWithRenameImpl(obj, oldPath, newPath, 0);
28858
28894
  };
28859
- var copyWithSetImpl = function(obj, path2, index2, value) {
28860
- if (index2 >= path2.length) {
28895
+ var copyWithSetImpl = function(obj, path, index2, value) {
28896
+ if (index2 >= path.length) {
28861
28897
  return value;
28862
28898
  }
28863
- var key = path2[index2];
28899
+ var key = path[index2];
28864
28900
  var updated = isArray(obj) ? obj.slice() : assign({}, obj);
28865
- updated[key] = copyWithSetImpl(obj[key], path2, index2 + 1, value);
28901
+ updated[key] = copyWithSetImpl(obj[key], path, index2 + 1, value);
28866
28902
  return updated;
28867
28903
  };
28868
- var copyWithSet = function(obj, path2, value) {
28869
- return copyWithSetImpl(obj, path2, 0, value);
28904
+ var copyWithSet = function(obj, path, value) {
28905
+ return copyWithSetImpl(obj, path, 0, value);
28870
28906
  };
28871
28907
  var findHook = function(fiber, id) {
28872
28908
  var currentHook2 = fiber.memoizedState;
@@ -28876,10 +28912,10 @@ var require_react_reconciler_development = __commonJS({
28876
28912
  }
28877
28913
  return currentHook2;
28878
28914
  };
28879
- overrideHookState = function(fiber, id, path2, value) {
28915
+ overrideHookState = function(fiber, id, path, value) {
28880
28916
  var hook = findHook(fiber, id);
28881
28917
  if (hook !== null) {
28882
- var newState = copyWithSet(hook.memoizedState, path2, value);
28918
+ var newState = copyWithSet(hook.memoizedState, path, value);
28883
28919
  hook.memoizedState = newState;
28884
28920
  hook.baseState = newState;
28885
28921
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -28889,10 +28925,10 @@ var require_react_reconciler_development = __commonJS({
28889
28925
  }
28890
28926
  }
28891
28927
  };
28892
- overrideHookStateDeletePath = function(fiber, id, path2) {
28928
+ overrideHookStateDeletePath = function(fiber, id, path) {
28893
28929
  var hook = findHook(fiber, id);
28894
28930
  if (hook !== null) {
28895
- var newState = copyWithDelete(hook.memoizedState, path2);
28931
+ var newState = copyWithDelete(hook.memoizedState, path);
28896
28932
  hook.memoizedState = newState;
28897
28933
  hook.baseState = newState;
28898
28934
  fiber.memoizedProps = assign({}, fiber.memoizedProps);
@@ -28915,8 +28951,8 @@ var require_react_reconciler_development = __commonJS({
28915
28951
  }
28916
28952
  }
28917
28953
  };
28918
- overrideProps = function(fiber, path2, value) {
28919
- fiber.pendingProps = copyWithSet(fiber.memoizedProps, path2, value);
28954
+ overrideProps = function(fiber, path, value) {
28955
+ fiber.pendingProps = copyWithSet(fiber.memoizedProps, path, value);
28920
28956
  if (fiber.alternate) {
28921
28957
  fiber.alternate.pendingProps = fiber.pendingProps;
28922
28958
  }
@@ -28925,8 +28961,8 @@ var require_react_reconciler_development = __commonJS({
28925
28961
  scheduleUpdateOnFiber(root, fiber, SyncLane, NoTimestamp);
28926
28962
  }
28927
28963
  };
28928
- overridePropsDeletePath = function(fiber, path2) {
28929
- fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path2);
28964
+ overridePropsDeletePath = function(fiber, path) {
28965
+ fiber.pendingProps = copyWithDelete(fiber.memoizedProps, path);
28930
28966
  if (fiber.alternate) {
28931
28967
  fiber.alternate.pendingProps = fiber.pendingProps;
28932
28968
  }
@@ -36994,8 +37030,8 @@ var init_ErrorOverview = __esm({
36994
37030
  init_dist3();
36995
37031
  init_Box();
36996
37032
  init_Text();
36997
- cleanupPath = (path2) => {
36998
- return path2?.replace(`file://${cwd()}/`, "");
37033
+ cleanupPath = (path) => {
37034
+ return path?.replace(`file://${cwd()}/`, "");
36999
37035
  };
37000
37036
  stackUtils = new import_stack_utils.default({
37001
37037
  cwd: cwd(),
@@ -41664,18 +41700,19 @@ async function readNdjsonAnalyzeResponse(response, onPackageProgress) {
41664
41700
  }
41665
41701
  buf += decoder.decode();
41666
41702
  if (buf.trim()) processLine(buf);
41667
- if (!finalPayload) {
41703
+ const payload = finalPayload;
41704
+ if (!payload) {
41668
41705
  throw new APIError(
41669
41706
  "Streaming response ended without a result event",
41670
41707
  0,
41671
41708
  ""
41672
41709
  );
41673
41710
  }
41674
- if (typeof finalPayload.score !== "number" || !Array.isArray(finalPayload.packages)) {
41711
+ if (typeof payload.score !== "number" || !Array.isArray(payload.packages)) {
41675
41712
  throw new APIError("Invalid streamed result payload", 0, "");
41676
41713
  }
41677
- checkVersionFloor(finalPayload);
41678
- return sanitizeResponse(finalPayload);
41714
+ checkVersionFloor(payload);
41715
+ return sanitizeResponse(payload);
41679
41716
  }
41680
41717
  async function callPyPIAnalyzeAPI(packages, config, onProgress) {
41681
41718
  const batchSize = config.apiKey ? BATCH_SIZE : ANON_BATCH_SIZE;
@@ -41992,9 +42029,9 @@ function parseLockfile(content) {
41992
42029
  const lockfileVersion = json.lockfileVersion ?? 1;
41993
42030
  const packages = /* @__PURE__ */ new Map();
41994
42031
  if (lockfileVersion >= 2 && json.packages) {
41995
- for (const [path2, entry] of Object.entries(json.packages)) {
41996
- if (path2 === "") continue;
41997
- const pathName = extractPackageName(path2);
42032
+ for (const [path, entry] of Object.entries(json.packages)) {
42033
+ if (path === "") continue;
42034
+ const pathName = extractPackageName(path);
41998
42035
  if (!pathName) continue;
41999
42036
  const e = entry;
42000
42037
  const entryName = typeof e.name === "string" && e.name.length > 0 ? e.name : void 0;
@@ -42266,12 +42303,12 @@ var init_parse_package_json = __esm({
42266
42303
  // src/lockfile/index.ts
42267
42304
  import { readFileSync as readFileSync8, existsSync as existsSync11, statSync as statSync3 } from "node:fs";
42268
42305
  import { join as join6 } from "node:path";
42269
- function readFileSafe(path2) {
42270
- const size = statSync3(path2).size;
42306
+ function readFileSafe(path) {
42307
+ const size = statSync3(path).size;
42271
42308
  if (size > MAX_LOCKFILE_BYTES) {
42272
- throw new Error(`Lockfile too large (${(size / 1024 / 1024).toFixed(0)} MB, max 50 MB): ${path2}`);
42309
+ throw new Error(`Lockfile too large (${(size / 1024 / 1024).toFixed(0)} MB, max 50 MB): ${path}`);
42273
42310
  }
42274
- return readFileSync8(path2, "utf-8");
42311
+ return readFileSync8(path, "utf-8");
42275
42312
  }
42276
42313
  function discoverChanges(cwd2, config) {
42277
42314
  if (config.workspace) {
@@ -42537,6 +42574,12 @@ var init_lockfile = __esm({
42537
42574
  });
42538
42575
 
42539
42576
  // src/commands/wrapper-shared.ts
42577
+ function injectIgnoreScripts(args, opts) {
42578
+ if (!opts.isNpmFamily) return args;
42579
+ if (!(opts.strict || opts.dgNoScripts)) return args;
42580
+ if (args.includes("--ignore-scripts")) return args;
42581
+ return [...args, "--ignore-scripts"];
42582
+ }
42540
42583
  function stripDgFlags(args) {
42541
42584
  let dgForce = false;
42542
42585
  let dgForceReason;
@@ -42619,9 +42662,7 @@ function realNpmBinary() {
42619
42662
  return real;
42620
42663
  }
42621
42664
  function shimSentinelEnv() {
42622
- const nonce = readNonce();
42623
- if (!nonce) return process.env;
42624
- return { ...process.env, DG_SHIM_ACTIVE: nonce };
42665
+ return childInstallEnv();
42625
42666
  }
42626
42667
  function parseNpmArgs(args) {
42627
42668
  const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
@@ -42889,9 +42930,9 @@ function readLockfilePins(cwd2) {
42889
42930
  ...Object.keys(root.optionalDependencies ?? {}),
42890
42931
  ...Object.keys(root.peerDependencies ?? {})
42891
42932
  ]);
42892
- for (const [path2, entry] of Object.entries(lock.packages ?? {})) {
42893
- if (path2 === "") continue;
42894
- const m = path2.match(/^node_modules\/((?:@[^/]+\/)?[^/]+)$/);
42933
+ for (const [path, entry] of Object.entries(lock.packages ?? {})) {
42934
+ if (path === "") continue;
42935
+ const m = path.match(/^node_modules\/((?:@[^/]+\/)?[^/]+)$/);
42895
42936
  if (!m) continue;
42896
42937
  const name = m[1];
42897
42938
  if (!directDeps.has(name)) continue;
@@ -43067,6 +43108,22 @@ function parsePipSpec(spec) {
43067
43108
  versionSpec: match[2] ?? null
43068
43109
  };
43069
43110
  }
43111
+ function pinPipArgs(rawArgs, userSpecs, resolved) {
43112
+ const specNames = new Set(userSpecs.map((s) => parsePipSpec(s).name.toLowerCase()));
43113
+ const pinByName = /* @__PURE__ */ new Map();
43114
+ for (const p of resolved) {
43115
+ const key = p.name.toLowerCase();
43116
+ if (specNames.has(key) && !pinByName.has(key)) {
43117
+ pinByName.set(key, `${p.name}==${p.version}`);
43118
+ }
43119
+ }
43120
+ const specSet = new Set(userSpecs);
43121
+ return rawArgs.map((a) => {
43122
+ if (!specSet.has(a)) return a;
43123
+ const { name } = parsePipSpec(a);
43124
+ return pinByName.get(name.toLowerCase()) ?? a;
43125
+ });
43126
+ }
43070
43127
  async function resolvePipVersion(spec) {
43071
43128
  const { name, versionSpec } = parsePipSpec(spec);
43072
43129
  if (versionSpec?.startsWith("==")) {
@@ -43128,9 +43185,7 @@ async function resolvePackages2(specs) {
43128
43185
  return { resolved, failed };
43129
43186
  }
43130
43187
  function shimSentinelEnv2() {
43131
- const nonce = readNonce();
43132
- if (!nonce) return process.env;
43133
- return { ...process.env, DG_SHIM_ACTIVE: nonce };
43188
+ return childInstallEnv();
43134
43189
  }
43135
43190
  async function detectPipBinary() {
43136
43191
  const py3 = walkPathExcludingShimDir("python3");
@@ -43427,16 +43482,16 @@ function collectNpmLockSha512Hashes(packageLock) {
43427
43482
  const root = packageLock;
43428
43483
  const packages = root["packages"];
43429
43484
  if (packages && typeof packages === "object") {
43430
- for (const [path2, raw] of Object.entries(packages)) {
43431
- if (path2 === "") continue;
43485
+ for (const [path, raw] of Object.entries(packages)) {
43486
+ if (path === "") continue;
43432
43487
  if (!raw || typeof raw !== "object") continue;
43433
43488
  const entry = raw;
43434
43489
  const version = typeof entry.version === "string" ? entry.version : void 0;
43435
43490
  const integrity = typeof entry.integrity === "string" ? entry.integrity : void 0;
43436
43491
  if (!version || !integrity) continue;
43437
- const idx = path2.lastIndexOf("node_modules/");
43492
+ const idx = path.lastIndexOf("node_modules/");
43438
43493
  if (idx < 0) continue;
43439
- const name = path2.slice(idx + "node_modules/".length);
43494
+ const name = path.slice(idx + "node_modules/".length);
43440
43495
  if (!name) continue;
43441
43496
  const hex = npmIntegrityToSha512Hex(integrity);
43442
43497
  if (hex) out.set(`${name}@${version}`, hex);
@@ -43678,7 +43733,7 @@ var init_FileSavePrompt = __esm({
43678
43733
  return;
43679
43734
  }
43680
43735
  if ((key.backspace || key.delete) && !state.filterText) {
43681
- const parentDir = path.dirname(state.directory);
43736
+ const parentDir = dirname8(state.directory);
43682
43737
  if (parentDir !== state.directory) {
43683
43738
  dispatch({ type: "SET_DIRECTORY", directory: parentDir, entries: listDirectory(parentDir) });
43684
43739
  }
@@ -43691,7 +43746,7 @@ var init_FileSavePrompt = __esm({
43691
43746
  if (key.return) {
43692
43747
  const entry = filteredEntries[state.browserCursor];
43693
43748
  if (!entry || !entry.isDirectory) return;
43694
- const newDir = entry.name === ".." ? path.dirname(state.directory) : path.join(state.directory, entry.name);
43749
+ const newDir = entry.name === ".." ? dirname8(state.directory) : join8(state.directory, entry.name);
43695
43750
  dispatch({ type: "SET_DIRECTORY", directory: newDir, entries: listDirectory(newDir) });
43696
43751
  return;
43697
43752
  }
@@ -43967,9 +44022,9 @@ async function scanDir(dir, depth, _root) {
43967
44022
  }
43968
44023
  return { subdirs, lockfileHits };
43969
44024
  }
43970
- async function isSafeRegularFile(path2) {
44025
+ async function isSafeRegularFile(path) {
43971
44026
  try {
43972
- const st = await lstat(path2);
44027
+ const st = await lstat(path);
43973
44028
  return st.isFile() && !st.isSymbolicLink();
43974
44029
  } catch {
43975
44030
  return false;
@@ -44104,9 +44159,9 @@ function discoverProjectsConsolidated(projectPaths, config) {
44104
44159
  const seenPy = /* @__PURE__ */ new Set();
44105
44160
  const unparseable = [];
44106
44161
  let rawCount = 0;
44107
- for (const path2 of projectPaths) {
44162
+ for (const path of projectPaths) {
44108
44163
  try {
44109
- const d = discoverChanges(path2, config);
44164
+ const d = discoverChanges(path, config);
44110
44165
  for (const pkg of d.packages) {
44111
44166
  rawCount++;
44112
44167
  const key = `${pkg.name}@${pkg.version}`;
@@ -44122,7 +44177,7 @@ function discoverProjectsConsolidated(projectPaths, config) {
44122
44177
  pythonPackages.push(pkg);
44123
44178
  }
44124
44179
  } catch {
44125
- unparseable.push(path2);
44180
+ unparseable.push(path);
44126
44181
  }
44127
44182
  }
44128
44183
  return {
@@ -44371,21 +44426,21 @@ function validateAllowlist(raw) {
44371
44426
  return { ok: true, allowlist: { schemaVersion: 1, rules, packages } };
44372
44427
  }
44373
44428
  function loadAllowlist(cwd2) {
44374
- const path2 = findAllowlistFile(cwd2);
44375
- if (!path2) return null;
44429
+ const path = findAllowlistFile(cwd2);
44430
+ if (!path) return null;
44376
44431
  let raw;
44377
44432
  try {
44378
- raw = JSON.parse(readFileSync10(path2, "utf-8"));
44433
+ raw = JSON.parse(readFileSync10(path, "utf-8"));
44379
44434
  } catch (e) {
44380
44435
  process.stderr.write(
44381
- `dg: .dg-allowlist.json at ${path2} is not valid JSON (${e.message}). Ignoring.
44436
+ `dg: .dg-allowlist.json at ${path} is not valid JSON (${e.message}). Ignoring.
44382
44437
  `
44383
44438
  );
44384
44439
  return null;
44385
44440
  }
44386
44441
  const validation = validateAllowlist(raw);
44387
44442
  if (!validation.ok) {
44388
- process.stderr.write(`dg: .dg-allowlist.json at ${path2} failed validation:
44443
+ process.stderr.write(`dg: .dg-allowlist.json at ${path} failed validation:
44389
44444
  `);
44390
44445
  for (const err of validation.errors) {
44391
44446
  process.stderr.write(` ${err.path}: ${err.message}
@@ -44395,7 +44450,7 @@ function loadAllowlist(cwd2) {
44395
44450
  `);
44396
44451
  return null;
44397
44452
  }
44398
- return { ...validation.allowlist, sourcePath: path2 };
44453
+ return { ...validation.allowlist, sourcePath: path };
44399
44454
  }
44400
44455
  function findingRuleId(f) {
44401
44456
  return (f.category ?? f.title ?? "").toString();
@@ -44540,6 +44595,7 @@ function buildSarif(response, opts = {}) {
44540
44595
  });
44541
44596
  }
44542
44597
  const findings = pkg.findings ?? [];
44598
+ let pkgResultCount = 0;
44543
44599
  for (const f of findings) {
44544
44600
  const id = findingId(f);
44545
44601
  const level = severityToLevel(f.severity);
@@ -44563,6 +44619,32 @@ function buildSarif(response, opts = {}) {
44563
44619
  }],
44564
44620
  partialFingerprints: { dg_finding: findingFingerprint(pkg, f) }
44565
44621
  });
44622
+ pkgResultCount++;
44623
+ }
44624
+ if (pkgResultCount === 0 && (pkg.action === "block" || pkg.action === "warn")) {
44625
+ const ruleId = pkg.action === "block" ? "dg.block" : "dg.warn";
44626
+ const level = pkg.action === "block" ? "error" : "warning";
44627
+ if (!ruleMap.has(ruleId)) {
44628
+ ruleMap.set(ruleId, {
44629
+ id: ruleId,
44630
+ name: ruleId,
44631
+ shortDescription: {
44632
+ text: pkg.action === "block" ? "Package blocked by Dependency Guardian" : "Package flagged (warn) by Dependency Guardian"
44633
+ },
44634
+ defaultConfiguration: { level }
44635
+ });
44636
+ }
44637
+ results.push({
44638
+ ruleId,
44639
+ level,
44640
+ message: { text: `${pkg.name} ${pkg.version}: ${pkg.action} verdict from Dependency Guardian (no individual findings surfaced at this tier).` },
44641
+ locations: [{
44642
+ physicalLocation: {
44643
+ artifactLocation: { uri: opts.lockfileUri ?? `dg:${pkg.name}@${pkg.version}` }
44644
+ }
44645
+ }],
44646
+ partialFingerprints: { dg_finding: `${pkg.name}@${pkg.version}#${ruleId}`.slice(0, 240) }
44647
+ });
44566
44648
  }
44567
44649
  }
44568
44650
  return {
@@ -44699,7 +44781,7 @@ function shouldFireAudit(policy, decisionAction) {
44699
44781
  return false;
44700
44782
  }
44701
44783
  function flagPackages(packages) {
44702
- return packages.filter((p) => p.score >= 60);
44784
+ return packages.filter((p) => (p.action ?? "pass") !== "pass");
44703
44785
  }
44704
44786
  async function dispatchPublishCheckAudit(opts) {
44705
44787
  try {
@@ -44726,8 +44808,8 @@ function bypassLogPath2() {
44726
44808
  }
44727
44809
  function recordBypassLocally(record) {
44728
44810
  try {
44729
- const path2 = bypassLogPath2();
44730
- const dir = dirname10(path2);
44811
+ const path = bypassLogPath2();
44812
+ const dir = dirname10(path);
44731
44813
  if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
44732
44814
  const full = {
44733
44815
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -44738,7 +44820,7 @@ function recordBypassLocally(record) {
44738
44820
  reason: record.reason,
44739
44821
  packages: record.packages
44740
44822
  };
44741
- appendFileSync3(path2, JSON.stringify(full) + "\n", { mode: 384 });
44823
+ appendFileSync3(path, JSON.stringify(full) + "\n", { mode: 384 });
44742
44824
  } catch {
44743
44825
  }
44744
44826
  }
@@ -44811,13 +44893,13 @@ function wrapperPackagesFromResult(result, topLevelNames) {
44811
44893
  }));
44812
44894
  }
44813
44895
  function loadPackageLockJson(cwd2 = process.cwd()) {
44814
- const path2 = resolvePath(cwd2, "package-lock.json");
44815
- if (!existsSync17(path2)) return null;
44896
+ const path = resolvePath(cwd2, "package-lock.json");
44897
+ if (!existsSync17(path)) return null;
44816
44898
  try {
44817
- const st = lstatSync5(path2);
44899
+ const st = lstatSync5(path);
44818
44900
  if (!st.isFile()) return null;
44819
44901
  if (st.size > MAX_PACKAGE_LOCK_BYTES) return null;
44820
- return JSON.parse(readFileSync11(path2, "utf8"));
44902
+ return JSON.parse(readFileSync11(path, "utf8"));
44821
44903
  } catch {
44822
44904
  return null;
44823
44905
  }
@@ -44897,7 +44979,7 @@ function maybePrintFirstScanNotice(config) {
44897
44979
  if (getScanNoticeShownAt2() !== null) return;
44898
44980
  process.stderr.write(
44899
44981
  import_chalk5.default.dim(
44900
- " Dependency Guardian sends package names + versions to api.westbayberry.com.\n Anonymous crash reports are on; set DG_TELEMETRY=0 to opt out.\n Terms: https://westbayberry.com/terms \xB7 Privacy: https://westbayberry.com/privacy\n"
44982
+ " Dependency Guardian sends package names + versions to api.westbayberry.com.\n Anonymous crash reports are on to help us fix early bugs (no source, paths, or package names);\n opt out with DG_TELEMETRY=0 or DO_NOT_TRACK=1.\n Terms: https://westbayberry.com/terms \xB7 Privacy: https://westbayberry.com/privacy\n"
44901
44983
  )
44902
44984
  );
44903
44985
  recordScanNoticeShown2();
@@ -45228,14 +45310,7 @@ async function runStatic(config) {
45228
45310
  }
45229
45311
  if (discovery.pythonPackages.length > 0) {
45230
45312
  const pyResult = await callPyPIAnalyzeAPI(discovery.pythonPackages, config);
45231
- result.packages.push(...pyResult.packages);
45232
- result.score = Math.max(result.score, pyResult.score);
45233
- if (pyResult.action === "block" || pyResult.action === "warn" && result.action === "pass") {
45234
- result.action = pyResult.action;
45235
- }
45236
- if (pyResult.freeScansRemaining !== void 0) {
45237
- result.freeScansRemaining = pyResult.freeScansRemaining;
45238
- }
45313
+ result = mergeResponses([result, pyResult]);
45239
45314
  }
45240
45315
  clearSpinner();
45241
45316
  dbg(
@@ -45399,11 +45474,11 @@ function buildInstallArgs(parsed, topLevelSpecs, tree, config) {
45399
45474
  if (tree.length > 0 && topLevelSpecs.length > 0) {
45400
45475
  args = pinTopLevelArgs(args, topLevelSpecs, tree);
45401
45476
  }
45402
- const wantsNoScripts = parsed.dgNoScripts || config.strict;
45403
- if (wantsNoScripts && !args.includes("--ignore-scripts")) {
45404
- args = [...args, "--ignore-scripts"];
45405
- }
45406
- return args;
45477
+ return injectIgnoreScripts(args, {
45478
+ isNpmFamily: true,
45479
+ strict: config.strict,
45480
+ dgNoScripts: parsed.dgNoScripts
45481
+ });
45407
45482
  }
45408
45483
  async function scanAndInstallStatic(resolved, parsed, config) {
45409
45484
  const topLevelSpecs = resolved.map((p) => `${p.name}@${p.version}`);
@@ -45432,6 +45507,14 @@ async function scanAndInstallStatic(resolved, parsed, config) {
45432
45507
  process.stderr.write(
45433
45508
  import_chalk5.default.dim(" Only top-level packages would be scanned; transitive deps would slip through. Use --dg-force to bypass.\n\n")
45434
45509
  );
45510
+ emitWrapperJson(config, {
45511
+ ecosystem: "npm",
45512
+ packages: [],
45513
+ scanVerdict: "scan_failed",
45514
+ installRan: false,
45515
+ installExitCode: null,
45516
+ error: { code: "tree_resolution_failed", message: treeError }
45517
+ });
45435
45518
  process.exit(2);
45436
45519
  }
45437
45520
  process.stderr.write(
@@ -45651,6 +45734,42 @@ ${installLine}
45651
45734
  });
45652
45735
  process.exit(2);
45653
45736
  }
45737
+ if (result.action === "analysis_incomplete") {
45738
+ const topLevel = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
45739
+ const refuse = (config.mode === "block" || config.strict) && !parsed.dgForce;
45740
+ if (refuse) {
45741
+ const specArg = topLevelSpecs.length > 0 ? topLevelSpecs.join(" ") : resolved.map((p) => `${p.name}@${p.version}`).join(" ");
45742
+ process.stderr.write(
45743
+ ` ${import_chalk5.default.cyan("?")} ${import_chalk5.default.bold("DG could not verify")} ${topLevel} \u2014 treating as unverified, not safe.
45744
+ Real install was NOT run (--mode block). To override:
45745
+ ` + import_chalk5.default.dim(` npm install ${specArg} --dg-force --dg-force-reason="<reason>"
45746
+
45747
+ `)
45748
+ );
45749
+ emitWrapperJson(config, {
45750
+ ecosystem: "npm",
45751
+ packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45752
+ scanVerdict: "analysis_incomplete",
45753
+ installRan: false,
45754
+ installExitCode: null
45755
+ });
45756
+ process.exit(4);
45757
+ }
45758
+ process.stderr.write(
45759
+ import_chalk5.default.dim(` DG could not fully verify ${topLevel}; proceeding (mode is not block).
45760
+
45761
+ `)
45762
+ );
45763
+ const code = await runNpm(buildInstallArgs(parsed, topLevelSpecs, tree.packages, config), { stdoutToStderr: !!config.json });
45764
+ emitWrapperJson(config, {
45765
+ ecosystem: "npm",
45766
+ packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45767
+ scanVerdict: "analysis_incomplete",
45768
+ installRan: true,
45769
+ installExitCode: code
45770
+ });
45771
+ process.exit(code);
45772
+ }
45654
45773
  }
45655
45774
  async function runStaticPip(pipArgs, config) {
45656
45775
  config = mergeProjectConfig(config, process.argv.slice(2));
@@ -45740,6 +45859,17 @@ async function runStaticPip(pipArgs, config) {
45740
45859
  )
45741
45860
  );
45742
45861
  }
45862
+ const isRequirementsInstall = !!parsed.requirementsFile;
45863
+ if (isRequirementsInstall && !(pipTreeOk && pipTree.hashes.size > 0) && (config.mode === "block" || config.strict) && !parsed.dgForce) {
45864
+ process.stderr.write(
45865
+ import_chalk5.default.red(import_chalk5.default.bold(" BLOCKED: ")) + import_chalk5.default.red(`a -r requirements install cannot be pinned to exact versions and no dry-run hashes are available to verify the artifacts.
45866
+ `) + import_chalk5.default.dim(` Install aborted${config.strict ? " in --strict" : " in --mode block"} (resolve\u2192install mismatch risk). Use --mode warn or --dg-force to bypass.
45867
+
45868
+ `)
45869
+ );
45870
+ process.exit(2);
45871
+ }
45872
+ const pipInstallArgs = pinPipArgs(parsed.rawArgs, parsed.packages, resolved);
45743
45873
  note(
45744
45874
  config,
45745
45875
  import_chalk5.default.dim(
@@ -45768,14 +45898,14 @@ async function runStaticPip(pipArgs, config) {
45768
45898
  process.stderr.write(
45769
45899
  import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
45770
45900
  );
45771
- const code2 = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45901
+ const code2 = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45772
45902
  process.exit(code2);
45773
45903
  }
45774
45904
  process.stderr.write(
45775
45905
  import_chalk5.default.yellow(` Warning: Scan failed (${msg}). Proceeding with install (mode=${config.mode}).
45776
45906
  `)
45777
45907
  );
45778
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45908
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45779
45909
  process.exit(code);
45780
45910
  return;
45781
45911
  }
@@ -45812,7 +45942,7 @@ ${installLine}
45812
45942
  `);
45813
45943
  printTrialBanner(result, config);
45814
45944
  process.stderr.write("\n");
45815
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45945
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45816
45946
  emitWrapperJson(config, {
45817
45947
  ecosystem: "pypi",
45818
45948
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
@@ -45844,7 +45974,7 @@ ${installLine}
45844
45974
  });
45845
45975
  process.exit(1);
45846
45976
  }
45847
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45977
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45848
45978
  emitWrapperJson(config, {
45849
45979
  ecosystem: "pypi",
45850
45980
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
@@ -45867,7 +45997,7 @@ ${installLine}
45867
45997
  process.stderr.write(
45868
45998
  import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
45869
45999
  );
45870
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
46000
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45871
46001
  emitWrapperJson(config, {
45872
46002
  ecosystem: "pypi",
45873
46003
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
@@ -45902,6 +46032,42 @@ ${installLine}
45902
46032
  });
45903
46033
  process.exit(2);
45904
46034
  }
46035
+ if (result.action === "analysis_incomplete") {
46036
+ const pipTopLevel = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
46037
+ const refuse = (config.mode === "block" || config.strict) && !parsed.dgForce;
46038
+ if (refuse) {
46039
+ const pipSpecArg = resolved.map((p) => `${p.name}==${p.version}`).join(" ");
46040
+ process.stderr.write(
46041
+ ` ${import_chalk5.default.cyan("?")} ${import_chalk5.default.bold("DG could not verify")} ${pipTopLevel} \u2014 treating as unverified, not safe.
46042
+ Real install was NOT run (--mode block). To override:
46043
+ ` + import_chalk5.default.dim(` pip install ${pipSpecArg} --dg-force --dg-force-reason="<reason>"
46044
+
46045
+ `)
46046
+ );
46047
+ emitWrapperJson(config, {
46048
+ ecosystem: "pypi",
46049
+ packages: wrapperPackagesFromResult(result, pipTopLevelNames),
46050
+ scanVerdict: "analysis_incomplete",
46051
+ installRan: false,
46052
+ installExitCode: null
46053
+ });
46054
+ process.exit(4);
46055
+ }
46056
+ process.stderr.write(
46057
+ import_chalk5.default.dim(` DG could not fully verify ${pipTopLevel}; proceeding (mode is not block).
46058
+
46059
+ `)
46060
+ );
46061
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
46062
+ emitWrapperJson(config, {
46063
+ ecosystem: "pypi",
46064
+ packages: wrapperPackagesFromResult(result, pipTopLevelNames),
46065
+ scanVerdict: "analysis_incomplete",
46066
+ installRan: true,
46067
+ installExitCode: code
46068
+ });
46069
+ process.exit(code);
46070
+ }
45905
46071
  }
45906
46072
  async function runStaticLogin() {
45907
46073
  const {
@@ -46014,6 +46180,7 @@ var init_static_output = __esm({
46014
46180
  init_lockfile();
46015
46181
  init_npm_wrapper();
46016
46182
  init_pip_wrapper();
46183
+ init_wrapper_shared();
46017
46184
  init_artifact_integrity();
46018
46185
  init_sanitize();
46019
46186
  init_format_helpers();
@@ -46808,11 +46975,11 @@ var init_InteractiveResultsView = __esm({
46808
46975
  const scanUsage = usageDisplay ? usageDisplay.text : result.freeScansRemaining !== void 0 ? `${result.freeScansRemaining.toLocaleString()} packages left` : scanUsageProp;
46809
46976
  const usageNearLimit = usageDisplay?.nearLimit ?? false;
46810
46977
  const flagged = (0, import_react30.useMemo)(
46811
- () => result.packages.filter((p) => p.score > 0 || p.action === "analysis_incomplete"),
46978
+ () => result.packages.filter((p) => (p.action ?? "pass") !== "pass"),
46812
46979
  [result.packages]
46813
46980
  );
46814
46981
  const clean = (0, import_react30.useMemo)(
46815
- () => result.packages.filter((p) => p.score === 0 && p.action !== "analysis_incomplete"),
46982
+ () => result.packages.filter((p) => (p.action ?? "pass") === "pass"),
46816
46983
  [result.packages]
46817
46984
  );
46818
46985
  const total = result.packages.length;
@@ -47108,8 +47275,8 @@ var init_InteractiveResultsView = __esm({
47108
47275
  const { body, ext } = formatExport(payload, scope, format);
47109
47276
  const scopeTag = scope === "current-license" && currentLicenseIdx !== null ? `${(licenseGroups[currentLicenseIdx]?.spdx ?? "license").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 32)}` : scope;
47110
47277
  const filename = `dg-scan-${ts}-${scopeTag}.${ext}`;
47111
- const path2 = resolvePath2(process.cwd(), filename);
47112
- writeFileSync11(path2, body, "utf-8");
47278
+ const path = resolvePath2(process.cwd(), filename);
47279
+ writeFileSync11(path, body, "utf-8");
47113
47280
  showExportMsg(`\u2713 Exported to ${filename}`);
47114
47281
  } catch (e) {
47115
47282
  showExportMsg(`Export failed: ${e.message}`);
@@ -48506,6 +48673,7 @@ var publish_check_exports = {};
48506
48673
  __export(publish_check_exports, {
48507
48674
  findPypiArtifacts: () => findPypiArtifacts,
48508
48675
  npmPackDryRun: () => npmPackDryRun,
48676
+ publishCheckExitCode: () => publishCheckExitCode,
48509
48677
  renderPublishCheckResult: () => renderPublishCheckResult,
48510
48678
  runNpmPublishCheck: () => runNpmPublishCheck,
48511
48679
  runPypiPublishCheck: () => runPypiPublishCheck,
@@ -48642,6 +48810,12 @@ function summarize(ecosystem, artifact, files, findings) {
48642
48810
  action
48643
48811
  };
48644
48812
  }
48813
+ function publishCheckExitCode(action, force) {
48814
+ if (force) return 0;
48815
+ if (action === "block") return 2;
48816
+ if (action === "warn") return 1;
48817
+ return 0;
48818
+ }
48645
48819
  async function runNpmPublishCheck(cwd2 = process.cwd()) {
48646
48820
  const pack = await npmPackDryRun(cwd2);
48647
48821
  if (!pack.ok) return { ok: false, errorMessage: pack.errorMessage };
@@ -48703,10 +48877,10 @@ function parseTar(buf) {
48703
48877
  }
48704
48878
  return out;
48705
48879
  }
48706
- async function readGzipped(path2) {
48880
+ async function readGzipped(path) {
48707
48881
  return new Promise((resolve3, reject) => {
48708
48882
  const chunks = [];
48709
- const stream = createReadStream(path2).pipe(createGunzip());
48883
+ const stream = createReadStream(path).pipe(createGunzip());
48710
48884
  stream.on("data", (c) => chunks.push(c));
48711
48885
  stream.on("end", () => resolve3(Buffer.concat(chunks)));
48712
48886
  stream.on("error", reject);
@@ -48939,11 +49113,11 @@ function validateEntry(raw) {
48939
49113
  };
48940
49114
  }
48941
49115
  function readRegistry() {
48942
- const path2 = registryPath();
48943
- if (!existsSync20(path2)) return [];
49116
+ const path = registryPath();
49117
+ if (!existsSync20(path)) return [];
48944
49118
  let raw;
48945
49119
  try {
48946
- raw = readFileSync14(path2, "utf-8");
49120
+ raw = readFileSync14(path, "utf-8");
48947
49121
  } catch {
48948
49122
  return [];
48949
49123
  }
@@ -48964,13 +49138,13 @@ function readRegistry() {
48964
49138
  return out;
48965
49139
  }
48966
49140
  function writeRegistry(entries) {
48967
- const path2 = registryPath();
48968
- const parent = dirname12(path2);
49141
+ const path = registryPath();
49142
+ const parent = dirname12(path);
48969
49143
  if (!existsSync20(parent)) mkdirSync8(parent, { recursive: true, mode: 448 });
48970
49144
  const payload = { version: 1, entries };
48971
- writeFileSync12(path2, JSON.stringify(payload, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
49145
+ writeFileSync12(path, JSON.stringify(payload, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
48972
49146
  try {
48973
- chmodSync4(path2, 384);
49147
+ chmodSync4(path, 384);
48974
49148
  } catch {
48975
49149
  }
48976
49150
  }
@@ -49569,9 +49743,9 @@ function installPrefix(resolvedBinPath) {
49569
49743
  if (idx < 0) return null;
49570
49744
  return resolvedBinPath.slice(0, idx);
49571
49745
  }
49572
- function canWrite(path2) {
49746
+ function canWrite(path) {
49573
49747
  try {
49574
- accessSync(path2, constants2.W_OK);
49748
+ accessSync(path, constants2.W_OK);
49575
49749
  return true;
49576
49750
  } catch {
49577
49751
  return false;
@@ -49994,9 +50168,9 @@ async function revokeApiKey(apiKey) {
49994
50168
  return { ok: false, reason: e.message };
49995
50169
  }
49996
50170
  }
49997
- function rmFile(path2) {
50171
+ function rmFile(path) {
49998
50172
  try {
49999
- unlinkSync7(path2);
50173
+ unlinkSync7(path);
50000
50174
  return { ok: true };
50001
50175
  } catch (e) {
50002
50176
  const code = e.code;
@@ -50004,9 +50178,9 @@ function rmFile(path2) {
50004
50178
  return { ok: false, reason: e.message };
50005
50179
  }
50006
50180
  }
50007
- function rmTree(path2) {
50181
+ function rmTree(path) {
50008
50182
  try {
50009
- rmSync2(path2, { recursive: true, force: true });
50183
+ rmSync2(path, { recursive: true, force: true });
50010
50184
  return { ok: true };
50011
50185
  } catch (e) {
50012
50186
  return { ok: false, reason: e.message };
@@ -50995,8 +51169,8 @@ var init_ProjectSelector = __esm({
50995
51169
  const ecoCountPlainLen = `${proj.ecosystem} ${proj.packageCount} packages`.length;
50996
51170
  const fixedPrefixLen = 4;
50997
51171
  const pathColWidth = Math.max(20, termCols - fixedPrefixLen - ecoCountPlainLen - 3);
50998
- const path2 = sanitize(proj.relativePath);
50999
- const pathTruncated = path2.length > pathColWidth ? path2.slice(0, Math.max(1, pathColWidth - 1)) + "\u2026" : path2.padEnd(pathColWidth);
51172
+ const path = sanitize(proj.relativePath);
51173
+ const pathTruncated = path.length > pathColWidth ? path.slice(0, Math.max(1, pathColWidth - 1)) + "\u2026" : path.padEnd(pathColWidth);
51000
51174
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { backgroundColor: isCursor ? "#1a1a2e" : void 0, wrap: "truncate-end", children: [
51001
51175
  prefix,
51002
51176
  check,
@@ -51091,6 +51265,7 @@ var init_App2 = __esm({
51091
51265
  await init_ProjectSelector();
51092
51266
  await init_SetupBanner();
51093
51267
  await init_useTerminalSize();
51268
+ init_static_output();
51094
51269
  init_terminal_state();
51095
51270
  import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
51096
51271
  App2 = ({ config, userStatus, scanUsage, setupIssues = [] }) => {
@@ -51129,16 +51304,7 @@ var init_App2 = __esm({
51129
51304
  }, []);
51130
51305
  const handleResultsExit = (0, import_react36.useCallback)(() => {
51131
51306
  if (state.phase === "results") {
51132
- const { result } = state;
51133
- if (result.action === "block" && config.mode === "block") {
51134
- process.exitCode = 2;
51135
- } else if (result.action === "block" || result.action === "warn") {
51136
- process.exitCode = 1;
51137
- } else if (result.action === "analysis_incomplete") {
51138
- process.exitCode = 4;
51139
- } else {
51140
- process.exitCode = 0;
51141
- }
51307
+ process.exitCode = scanExitCode(state.result.action, config.mode);
51142
51308
  }
51143
51309
  leaveAltScreen();
51144
51310
  exit();
@@ -51167,7 +51333,10 @@ var init_App2 = __esm({
51167
51333
  `, 3);
51168
51334
  return () => clearTimeout(timer);
51169
51335
  }
51170
- }, [state, exitWithMessage]);
51336
+ if (state.phase === "results") {
51337
+ process.exitCode = scanExitCode(state.result.action, config.mode);
51338
+ }
51339
+ }, [state, config, exitWithMessage]);
51171
51340
  use_input_default((input, key) => {
51172
51341
  if (state.phase === "discovering" || state.phase === "scanning") {
51173
51342
  if (input === "q" || key.escape) {
@@ -51317,9 +51486,9 @@ function locateInkInstancesPath() {
51317
51486
  async function initInkInstances() {
51318
51487
  if (realInstances) return;
51319
51488
  try {
51320
- const path2 = locateInkInstancesPath();
51321
- if (!path2) return;
51322
- const mod = await import(path2);
51489
+ const path = locateInkInstancesPath();
51490
+ if (!path) return;
51491
+ const mod = await import(path);
51323
51492
  realInstances = mod.default ?? null;
51324
51493
  } catch {
51325
51494
  realInstances = null;
@@ -51569,6 +51738,8 @@ function reducer4(_state, action) {
51569
51738
  return { phase: "warn", result: action.result, dgForce: action.dgForce };
51570
51739
  case "BLOCKED":
51571
51740
  return { phase: "blocked", result: action.result, dgForce: action.dgForce };
51741
+ case "INCOMPLETE":
51742
+ return { phase: "incomplete", result: action.result, message: action.message, proceed: action.proceed };
51572
51743
  case "INSTALLING":
51573
51744
  return { phase: "installing" };
51574
51745
  case "DONE":
@@ -51603,6 +51774,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51603
51774
  if (started.current) return;
51604
51775
  started.current = true;
51605
51776
  const parsed = parsedRef.current;
51777
+ let installArgs = parsed.rawArgs;
51606
51778
  (async () => {
51607
51779
  try {
51608
51780
  if (!parsed.shouldScan) {
@@ -51631,14 +51803,45 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51631
51803
  dispatch({ type: "DONE", exitCode: code });
51632
51804
  return;
51633
51805
  }
51634
- dispatch({ type: "SCANNING", count: resolved.length });
51635
- const result = await opts.callAnalyze(resolved, config);
51806
+ const isRequirementsInstall = opts.ecosystem === "pypi" && (parsed.rawArgs.includes("-r") || parsed.rawArgs.includes("--requirement"));
51807
+ if (isRequirementsInstall && (config.mode === "block" || config.strict) && !parsed.dgForce) {
51808
+ dispatch({
51809
+ type: "ERROR",
51810
+ message: `A -r requirements install cannot be pinned to the exact scanned versions; refusing in ${config.strict ? "--strict" : "--mode block"} (resolve\u2192install mismatch risk). Use --mode warn or --dg-force to bypass.`,
51811
+ proceed: false
51812
+ });
51813
+ dispatch({ type: "DONE", exitCode: 2 });
51814
+ return;
51815
+ }
51816
+ const pinnedArgs = isRequirementsInstall ? parsed.rawArgs : opts.ecosystem === "npm" ? pinTopLevelArgs(parsed.rawArgs, parsed.packages, resolved) : pinPipArgs(parsed.rawArgs, parsed.packages, resolved);
51817
+ installArgs = injectIgnoreScripts(pinnedArgs, {
51818
+ isNpmFamily: opts.ecosystem === "npm",
51819
+ strict: config.strict,
51820
+ dgNoScripts: parsed.dgNoScripts
51821
+ });
51822
+ let scanSet = resolved;
51823
+ if (opts.resolveTree) {
51824
+ const tree = await opts.resolveTree(specs);
51825
+ if (tree.ok && tree.packages.length > 0) {
51826
+ scanSet = tree.packages;
51827
+ } else if ((config.mode === "block" || config.strict) && !parsed.dgForce) {
51828
+ dispatch({
51829
+ type: "ERROR",
51830
+ message: `Could not enumerate the dependency tree (${tree.errorMessage ?? "dry-run produced no tree"}); transitive deps would install unscanned. Install aborted in ${config.strict ? "--strict" : "--mode block"}. Use --dg-force to bypass.`,
51831
+ proceed: false
51832
+ });
51833
+ dispatch({ type: "DONE", exitCode: 2 });
51834
+ return;
51835
+ }
51836
+ }
51837
+ dispatch({ type: "SCANNING", count: scanSet.length });
51838
+ const result = await opts.callAnalyze(scanSet, config);
51636
51839
  if (result.action === "pass") {
51637
51840
  if (exit) exit();
51638
51841
  const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
51639
51842
  const line = formatPassLine(result, chalk18);
51640
51843
  process.stderr.write(" " + line + "\n\n");
51641
- const code = await opts.runInstall(parsed.rawArgs);
51844
+ const code = await opts.runInstall(installArgs);
51642
51845
  process.exit(code);
51643
51846
  return;
51644
51847
  }
@@ -51654,7 +51857,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51654
51857
  });
51655
51858
  dispatch({ type: "WARN", result, dgForce: true });
51656
51859
  dispatch({ type: "INSTALLING" });
51657
- const code = await opts.runInstall(parsed.rawArgs);
51860
+ const code = await opts.runInstall(installArgs);
51658
51861
  dispatch({ type: "DONE", exitCode: code });
51659
51862
  return;
51660
51863
  }
@@ -51672,7 +51875,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51672
51875
  packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51673
51876
  });
51674
51877
  dispatch({ type: "INSTALLING" });
51675
- const code = await opts.runInstall(parsed.rawArgs);
51878
+ const code = await opts.runInstall(installArgs);
51676
51879
  dispatch({ type: "DONE", exitCode: code });
51677
51880
  } else {
51678
51881
  dispatch({ type: "DONE", exitCode: 1 });
@@ -51691,7 +51894,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51691
51894
  });
51692
51895
  dispatch({ type: "BLOCKED", result, dgForce: true });
51693
51896
  dispatch({ type: "INSTALLING" });
51694
- const code = await opts.runInstall(parsed.rawArgs);
51897
+ const code = await opts.runInstall(installArgs);
51695
51898
  dispatch({ type: "DONE", exitCode: code });
51696
51899
  return;
51697
51900
  }
@@ -51709,13 +51912,32 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51709
51912
  packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51710
51913
  });
51711
51914
  dispatch({ type: "INSTALLING" });
51712
- const code = await opts.runInstall(parsed.rawArgs);
51915
+ const code = await opts.runInstall(installArgs);
51713
51916
  dispatch({ type: "DONE", exitCode: code });
51714
51917
  } else {
51715
51918
  dispatch({ type: "DONE", exitCode: 2 });
51716
51919
  }
51717
51920
  return;
51718
51921
  }
51922
+ {
51923
+ const refuseHard = config.mode === "block" || config.strict;
51924
+ const baseMsg = "DG could not fully analyze the install set (analysis incomplete).";
51925
+ if (refuseHard && !parsed.dgForce) {
51926
+ dispatch({
51927
+ type: "INCOMPLETE",
51928
+ result,
51929
+ proceed: false,
51930
+ message: `${baseMsg} Refusing install in ${config.strict ? "--strict" : "--mode block"} \u2014 unverified is not safe. Use --mode warn or --dg-force to bypass.`
51931
+ });
51932
+ dispatch({ type: "DONE", exitCode: 4 });
51933
+ return;
51934
+ }
51935
+ dispatch({ type: "INCOMPLETE", result, proceed: true, message: baseMsg });
51936
+ dispatch({ type: "INSTALLING" });
51937
+ const code = await opts.runInstall(installArgs);
51938
+ dispatch({ type: "DONE", exitCode: code });
51939
+ return;
51940
+ }
51719
51941
  } catch (error) {
51720
51942
  if (error instanceof FreeCapReachedError) {
51721
51943
  dispatch({ type: "FREE_CAP_REACHED" });
@@ -51733,7 +51955,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51733
51955
  }
51734
51956
  dispatch({ type: "ERROR", message, proceed: true });
51735
51957
  dispatch({ type: "INSTALLING" });
51736
- const code = await opts.runInstall(parsedRef.current.rawArgs);
51958
+ const code = await opts.runInstall(installArgs);
51737
51959
  dispatch({ type: "DONE", exitCode: code });
51738
51960
  }
51739
51961
  })();
@@ -51756,11 +51978,13 @@ var init_useWrapperBase = __esm({
51756
51978
  "use strict";
51757
51979
  import_react37 = __toESM(require_react(), 1);
51758
51980
  init_client();
51981
+ init_wrapper_shared();
51759
51982
  init_npm_wrapper();
51760
51983
  init_pip_wrapper();
51761
51984
  NPM_OPTIONS = {
51762
51985
  parseArgs: parseNpmArgs,
51763
51986
  resolvePackages,
51987
+ resolveTree: resolveTreeNpm,
51764
51988
  callAnalyze: callAnalyzeAPI,
51765
51989
  runInstall: runNpm,
51766
51990
  inferSpecsFromContext: () => readBareInstallPackages(process.cwd()),
@@ -51769,6 +51993,7 @@ var init_useWrapperBase = __esm({
51769
51993
  PIP_OPTIONS = {
51770
51994
  parseArgs: parsePipArgs,
51771
51995
  resolvePackages: resolvePackages2,
51996
+ resolveTree: resolveTreePip,
51772
51997
  callAnalyze: callPyPIAnalyzeAPI,
51773
51998
  runInstall: runPip,
51774
51999
  inferSpecsFromContext: (parsed) => {
@@ -51832,8 +52057,8 @@ var init_ResultsView = __esm({
51832
52057
  config: _config,
51833
52058
  durationMs
51834
52059
  }) => {
51835
- const flagged = result.packages.filter((p) => p.score > 0 || p.action === "analysis_incomplete");
51836
- const clean = result.packages.filter((p) => p.score === 0 && p.action !== "analysis_incomplete");
52060
+ const flagged = result.packages.filter((p) => (p.action ?? "pass") !== "pass");
52061
+ const clean = result.packages.filter((p) => (p.action ?? "pass") === "pass");
51837
52062
  const total = result.packages.length;
51838
52063
  const groups = groupPackages(flagged);
51839
52064
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
@@ -51877,7 +52102,7 @@ var init_ResultsView = __esm({
51877
52102
  import_chalk16.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
51878
52103
  ] }),
51879
52104
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Newline, {}),
51880
- groups.filter((g) => g.packages[0].score > 0).map((group) => {
52105
+ groups.filter((g) => (g.packages[0].action ?? "pass") !== "pass").map((group) => {
51881
52106
  const rep = group.packages[0];
51882
52107
  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`;
51883
52108
  const visibleFindings = rep.findings.filter((f) => f.severity > 1).sort((a, b) => b.severity - a.severity);
@@ -52166,6 +52391,14 @@ var init_WrapperApp = __esm({
52166
52391
  showDetails && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Box_default, { marginTop: 1, children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ResultsView, { result: state.result, config, durationMs: state.result.durationMs }) }),
52167
52392
  !state.dgForce && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ConfirmPrompt, { message: "", onConfirm: handleConfirm, onReject: handleReject })
52168
52393
  ] });
52394
+ case "incomplete":
52395
+ if (state.proceed) {
52396
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Text, { color: "yellow", children: [
52397
+ state.message,
52398
+ " Proceeding with install."
52399
+ ] });
52400
+ }
52401
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorView, { error: new Error(state.message) });
52169
52402
  case "installing":
52170
52403
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner2, { label: labels.installing });
52171
52404
  case "done":
@@ -52245,26 +52478,33 @@ function parseCondaArgs(args) {
52245
52478
  async function resolveTopLevel(_parsed) {
52246
52479
  return { resolved: [], failed: [] };
52247
52480
  }
52248
- async function runStaticConda(args) {
52481
+ async function runStaticConda(args, ecosystem, config) {
52249
52482
  const parsed = parseCondaArgs(args);
52250
- if (process.stderr.isTTY && parsed.shouldScan) {
52483
+ if (parsed.shouldScan && (config.mode === "block" || config.strict) && !parsed.dgForce) {
52251
52484
  process.stderr.write(
52252
- import_chalk18.default.yellow(`\u2139\uFE0F DG: conda packages aren't yet scanned (conda-forge isn't supported in the scanner backend yet).
52253
- `) + import_chalk18.default.dim(` Passing through to real conda. Use \`dg verify\` for individual pypi-known packages.
52485
+ import_chalk18.default.red(import_chalk18.default.bold(" \u2717 BLOCKED: ")) + import_chalk18.default.red(`${ecosystem} packages cannot be scanned (the scanner backend does not support this ecosystem).
52486
+ `) + import_chalk18.default.dim(` --mode ${config.strict ? "strict" : "block"} \u21D2 refusing to install unscanned packages. Use --mode warn or --dg-force to bypass.
52254
52487
 
52255
52488
  `)
52256
52489
  );
52490
+ return 2;
52257
52491
  }
52258
- const real = resolveRealBinary("conda");
52492
+ if (parsed.shouldScan && process.stderr.isTTY) {
52493
+ process.stderr.write(
52494
+ import_chalk18.default.yellow(`\u2139\uFE0F DG: ${ecosystem} packages aren't yet scanned (the scanner backend doesn't support this ecosystem yet).
52495
+ `) + import_chalk18.default.dim(` Passing through to real ${ecosystem}. Use \`dg verify\` for individual pypi-known packages.
52496
+
52497
+ `)
52498
+ );
52499
+ }
52500
+ const real = resolveRealBinary(ecosystem);
52259
52501
  if (!real) {
52260
- process.stderr.write(`dg: real conda not found on PATH
52502
+ process.stderr.write(`dg: real ${ecosystem} not found on PATH
52261
52503
  `);
52262
52504
  return 127;
52263
52505
  }
52264
- const nonce = readNonce();
52265
- const env3 = nonce ? { ...process.env, DG_SHIM_ACTIVE: nonce } : { ...process.env };
52266
52506
  return await new Promise((resolve3) => {
52267
- const child = spawn5(real, parsed.rawArgs, { stdio: "inherit", env: env3 });
52507
+ const child = spawn5(real, parsed.rawArgs, { stdio: "inherit", env: childInstallEnv() });
52268
52508
  child.on("close", (code) => resolve3(code ?? 1));
52269
52509
  child.on("error", () => resolve3(1));
52270
52510
  });
@@ -52644,7 +52884,11 @@ function parseUvArgs(args) {
52644
52884
  for (let i = argStart; i < filtered.length; i++) {
52645
52885
  const arg = filtered[i];
52646
52886
  if (arg === "-r" || arg === "--requirement") {
52647
- if (i + 1 < filtered.length) i++;
52887
+ const file = filtered[i + 1];
52888
+ if (file !== void 0) {
52889
+ i++;
52890
+ packages.push(...parseRequirementsFile(file));
52891
+ }
52648
52892
  continue;
52649
52893
  }
52650
52894
  if (arg.startsWith("-")) {
@@ -52805,9 +53049,7 @@ function emitJson(config, result) {
52805
53049
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
52806
53050
  }
52807
53051
  function shimSentinelEnv3() {
52808
- const nonce = readNonce();
52809
- if (!nonce) return process.env;
52810
- return { ...process.env, DG_SHIM_ACTIVE: nonce };
53052
+ return childInstallEnv();
52811
53053
  }
52812
53054
  async function spawnRealBinary(adapter7, args) {
52813
53055
  const real = resolveRealBinary(adapter7.realBinaryName);
@@ -52852,8 +53094,46 @@ async function runEcosystemWrapper(adapter7, args, config) {
52852
53094
  `)
52853
53095
  );
52854
53096
  }
53097
+ const isRequirementsInstall = adapter7.apiKind === "pypi" && (parsed.rawArgs.includes("-r") || parsed.rawArgs.includes("--requirement"));
53098
+ let pinnedArgs = parsed.rawArgs;
53099
+ if (adapter7.apiKind === "npm") {
53100
+ pinnedArgs = pinTopLevelArgs(parsed.rawArgs, parsed.packages, resolved);
53101
+ } else if (!isRequirementsInstall) {
53102
+ pinnedArgs = pinPipArgs(parsed.rawArgs, parsed.packages, resolved);
53103
+ }
53104
+ if (isRequirementsInstall && (config.mode === "block" || config.strict) && !parsed.dgForce) {
53105
+ if (!config.json && !config.quiet) {
53106
+ process.stderr.write(
53107
+ import_chalk19.default.red(import_chalk19.default.bold(" \u2717 BLOCKED: ")) + import_chalk19.default.red(`a -r requirements install cannot be pinned to the exact scanned versions.
53108
+ `) + import_chalk19.default.dim(` --mode ${config.strict ? "strict" : "block"} \u21D2 refusing (would risk a resolve\u2192install mismatch). Use --mode warn or --dg-force to bypass.
53109
+
53110
+ `)
53111
+ );
53112
+ }
53113
+ emitJson(config, {
53114
+ ecosystem: adapter7.ecosystem,
53115
+ packages: [],
53116
+ scanVerdict: "scan_failed",
53117
+ installRan: false,
53118
+ installExitCode: null,
53119
+ error: { code: "unpinnable_requirements", message: "-r requirements install cannot be pinned to exact versions" }
53120
+ });
53121
+ return 2;
53122
+ }
53123
+ if (isRequirementsInstall && !config.json && !config.quiet) {
53124
+ process.stderr.write(
53125
+ import_chalk19.default.dim(` Note: -r requirements install cannot be pinned to exact versions; installing as specified.
53126
+ `)
53127
+ );
53128
+ }
53129
+ const installArgs = injectIgnoreScripts(pinnedArgs, {
53130
+ isNpmFamily: adapter7.apiKind === "npm",
53131
+ strict: config.strict,
53132
+ dgNoScripts: parsed.dgNoScripts
53133
+ });
52855
53134
  let scanSet = resolved;
52856
53135
  let treeOk = true;
53136
+ let treeError;
52857
53137
  if (adapter7.resolveTransitive) {
52858
53138
  const tree = await adapter7.resolveTransitive(parsed);
52859
53139
  if (tree.ok && tree.packages.length > 0) {
@@ -52873,15 +53153,36 @@ async function runEcosystemWrapper(adapter7, args, config) {
52873
53153
  `)
52874
53154
  );
52875
53155
  }
52876
- } else if (!tree.ok && !config.json && !config.quiet) {
53156
+ } else if (!tree.ok) {
52877
53157
  treeOk = false;
53158
+ treeError = tree.errorMessage ?? "unknown";
53159
+ }
53160
+ }
53161
+ if (!treeOk && (config.mode === "block" || config.strict) && !parsed.dgForce) {
53162
+ if (!config.json && !config.quiet) {
52878
53163
  process.stderr.write(
52879
- import_chalk19.default.dim(` Transitive resolution unavailable (${tree.errorMessage ?? "unknown"}); scanning top-level only.
53164
+ import_chalk19.default.red(import_chalk19.default.bold(" \u2717 BLOCKED: ")) + import_chalk19.default.red(`could not enumerate transitive dependencies (${treeError}); they would install unscanned.
53165
+ `) + import_chalk19.default.dim(` --mode block \u21D2 refusing install. Use --mode warn or --dg-force to bypass.
53166
+
52880
53167
  `)
52881
53168
  );
52882
53169
  }
53170
+ emitJson(config, {
53171
+ ecosystem: adapter7.ecosystem,
53172
+ packages: [],
53173
+ scanVerdict: "scan_failed",
53174
+ installRan: false,
53175
+ installExitCode: null,
53176
+ error: { code: "tree_resolution_failed", message: treeError ?? "transitive resolution failed" }
53177
+ });
53178
+ return 2;
53179
+ }
53180
+ if (!treeOk && !config.json && !config.quiet) {
53181
+ process.stderr.write(
53182
+ import_chalk19.default.dim(` Transitive resolution unavailable (${treeError}); scanning top-level only.
53183
+ `)
53184
+ );
52883
53185
  }
52884
- void treeOk;
52885
53186
  let result;
52886
53187
  try {
52887
53188
  if (adapter7.apiKind === "npm") {
@@ -52907,10 +53208,10 @@ async function runEcosystemWrapper(adapter7, args, config) {
52907
53208
  });
52908
53209
  return 1;
52909
53210
  }
52910
- if (config.mode === "block" && !parsed.dgForce) {
53211
+ if ((config.mode === "block" || config.strict) && !parsed.dgForce) {
52911
53212
  process.stderr.write(
52912
53213
  import_chalk19.default.red(` \u2717 DG scan failed: ${err.message}
52913
- `) + import_chalk19.default.dim(` --mode block + scan failure \u21D2 refusing install. Use --mode warn or --dg-force to bypass.
53214
+ `) + import_chalk19.default.dim(` --mode ${config.strict ? "strict" : "block"} + scan failure \u21D2 refusing install. Use --mode warn or --dg-force to bypass.
52914
53215
 
52915
53216
  `)
52916
53217
  );
@@ -52922,7 +53223,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
52922
53223
  installExitCode: null,
52923
53224
  error: { code: "scan_failed", message: err.message }
52924
53225
  });
52925
- return 3;
53226
+ return 2;
52926
53227
  }
52927
53228
  if (!config.json && !config.quiet) {
52928
53229
  process.stderr.write(
@@ -52930,7 +53231,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
52930
53231
  `)
52931
53232
  );
52932
53233
  }
52933
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53234
+ const code2 = await spawnRealBinary(adapter7, installArgs);
52934
53235
  emitJson(config, {
52935
53236
  ecosystem: adapter7.ecosystem,
52936
53237
  packages: [],
@@ -52959,7 +53260,7 @@ ${installLine}
52959
53260
  }
52960
53261
  process.stderr.write("\n");
52961
53262
  }
52962
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53263
+ const code2 = await spawnRealBinary(adapter7, installArgs);
52963
53264
  emitJson(config, {
52964
53265
  ecosystem: adapter7.ecosystem,
52965
53266
  packages: packagesFromResult(result, topLevelNames),
@@ -53006,7 +53307,7 @@ ${installLine}
53006
53307
  } else if (!config.json && !config.quiet) {
53007
53308
  process.stderr.write(import_chalk19.default.dim(" Proceeding (non-interactive).\n"));
53008
53309
  }
53009
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53310
+ const code2 = await spawnRealBinary(adapter7, installArgs);
53010
53311
  emitJson(config, {
53011
53312
  ecosystem: adapter7.ecosystem,
53012
53313
  packages: packagesFromResult(result, topLevelNames),
@@ -53034,7 +53335,7 @@ ${installLine}
53034
53335
 
53035
53336
  `));
53036
53337
  }
53037
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53338
+ const code2 = await spawnRealBinary(adapter7, installArgs);
53038
53339
  emitJson(config, {
53039
53340
  ecosystem: adapter7.ecosystem,
53040
53341
  packages: packagesFromResult(result, topLevelNames),
@@ -53072,11 +53373,38 @@ ${installLine}
53072
53373
  });
53073
53374
  return 2;
53074
53375
  }
53075
- const code = await spawnRealBinary(adapter7, parsed.rawArgs);
53376
+ const refuseHard = config.mode === "block" || config.strict;
53377
+ const unverifiedList = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
53378
+ if (refuseHard && !parsed.dgForce) {
53379
+ if (!config.json) {
53380
+ process.stderr.write(
53381
+ ` ${import_chalk19.default.red("\u2717")} ${import_chalk19.default.bold("DG could not verify")} ${unverifiedList} \u2014 analysis incomplete.
53382
+ ` + import_chalk19.default.dim(` --mode ${config.strict ? "strict" : "block"} \u21D2 refusing install (unverified is not safe). Use --mode warn or --dg-force to bypass.
53383
+
53384
+ `)
53385
+ );
53386
+ }
53387
+ emitJson(config, {
53388
+ ecosystem: adapter7.ecosystem,
53389
+ packages: packagesFromResult(result, topLevelNames),
53390
+ scanVerdict: "analysis_incomplete",
53391
+ installRan: false,
53392
+ installExitCode: null,
53393
+ error: { code: "analysis_incomplete", message: "scanner could not fully analyze the install set" }
53394
+ });
53395
+ return 4;
53396
+ }
53397
+ if (!config.json && !config.quiet) {
53398
+ process.stderr.write(
53399
+ import_chalk19.default.yellow(` \u26A0 DG could not fully verify ${unverifiedList} (analysis incomplete). Proceeding with install (mode=${config.mode}).
53400
+ `)
53401
+ );
53402
+ }
53403
+ const code = await spawnRealBinary(adapter7, installArgs);
53076
53404
  emitJson(config, {
53077
53405
  ecosystem: adapter7.ecosystem,
53078
53406
  packages: packagesFromResult(result, topLevelNames),
53079
- scanVerdict: "skipped",
53407
+ scanVerdict: "analysis_incomplete",
53080
53408
  installRan: true,
53081
53409
  installExitCode: code
53082
53410
  });
@@ -53092,6 +53420,9 @@ var init_wrapper_factory = __esm({
53092
53420
  init_install();
53093
53421
  init_audit_dispatcher();
53094
53422
  init_allowlist();
53423
+ init_wrapper_shared();
53424
+ init_npm_wrapper();
53425
+ init_pip_wrapper();
53095
53426
  }
53096
53427
  });
53097
53428
 
@@ -53312,7 +53643,7 @@ async function main() {
53312
53643
  const v = args[ecoArgIdx + 1];
53313
53644
  if (v === "npm" || v === "pypi") ecosystem = v;
53314
53645
  }
53315
- const { runNpmPublishCheck: runNpmPublishCheck2, runPypiPublishCheck: runPypiPublishCheck2, renderPublishCheckResult: renderPublishCheckResult2 } = await Promise.resolve().then(() => (init_publish_check(), publish_check_exports));
53646
+ const { runNpmPublishCheck: runNpmPublishCheck2, runPypiPublishCheck: runPypiPublishCheck2, renderPublishCheckResult: renderPublishCheckResult2, publishCheckExitCode: publishCheckExitCode2 } = await Promise.resolve().then(() => (init_publish_check(), publish_check_exports));
53316
53647
  const { existsSync: existsSync25 } = await import("node:fs");
53317
53648
  const { join: join15 } = await import("node:path");
53318
53649
  if (ecosystem === "auto") {
@@ -53342,7 +53673,7 @@ async function main() {
53342
53673
  } else {
53343
53674
  process.stderr.write(renderPublishCheckResult2(result));
53344
53675
  }
53345
- if (result.action === "block" || result.action === "block" && force) {
53676
+ if (result.action === "block") {
53346
53677
  try {
53347
53678
  const reasonIdx = args.indexOf("--dg-force-reason");
53348
53679
  const bypassReason = reasonIdx >= 0 ? args[reasonIdx + 1] : void 0;
@@ -53362,9 +53693,7 @@ async function main() {
53362
53693
  } catch {
53363
53694
  }
53364
53695
  }
53365
- if (result.action === "block" && !force) process.exit(2);
53366
- if (result.action === "analysis_incomplete") process.exit(4);
53367
- process.exit(0);
53696
+ process.exit(publishCheckExitCode2(result.action, force));
53368
53697
  }
53369
53698
  if (rawCommand === "hook") {
53370
53699
  const { handleHookCommand: handleHookCommand2 } = await Promise.resolve().then(() => (init_hook(), hook_exports));
@@ -53568,10 +53897,8 @@ async function handleWrapInternal(argv) {
53568
53897
  const ecoTyped = ecosystem;
53569
53898
  const spawnReal = async (real, args) => {
53570
53899
  const { spawn: spawn7 } = await import("node:child_process");
53571
- const { readNonce: readNonce3 } = await Promise.resolve().then(() => (init_install(), install_exports));
53572
- const nonce = readNonce3();
53573
- const env3 = nonce ? { ...process.env, DG_SHIM_ACTIVE: nonce } : { ...process.env };
53574
- const child = spawn7(real, args, { stdio: "inherit", env: env3 });
53900
+ const { childInstallEnv: childInstallEnv2 } = await Promise.resolve().then(() => (init_install(), install_exports));
53901
+ const child = spawn7(real, args, { stdio: "inherit", env: childInstallEnv2() });
53575
53902
  return await new Promise((resolve3) => {
53576
53903
  child.on("close", (code) => resolve3(code ?? 1));
53577
53904
  child.on("error", () => resolve3(1));
@@ -53621,7 +53948,7 @@ async function handleWrapInternal(argv) {
53621
53948
  }
53622
53949
  if (ecosystem === "conda" || ecosystem === "mamba") {
53623
53950
  const { runStaticConda: runStaticConda2 } = await Promise.resolve().then(() => (init_conda_wrapper(), conda_wrapper_exports));
53624
- return await runStaticConda2(wrapperArgs);
53951
+ return await runStaticConda2(wrapperArgs, ecosystem, config);
53625
53952
  }
53626
53953
  const adapterImports = {
53627
53954
  pnpm: () => Promise.resolve().then(() => (init_pnpm_wrapper(), pnpm_wrapper_exports)),