@westbayberry/dg 1.1.4 → 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
3213
+ )
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
3193
3221
  )
3194
- echo dg: real __ECOSYSTEM__ not found on PATH 1>&2
3195
- exit /b 127
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();
@@ -44516,8 +44571,31 @@ function findingFingerprint(pkg, f) {
44516
44571
  function buildSarif(response, opts = {}) {
44517
44572
  const ruleMap = /* @__PURE__ */ new Map();
44518
44573
  const results = [];
44574
+ const INCOMPLETE_RULE = "dg.analysis_incomplete";
44519
44575
  for (const pkg of response.packages) {
44576
+ if (pkg.action === "analysis_incomplete") {
44577
+ if (!ruleMap.has(INCOMPLETE_RULE)) {
44578
+ ruleMap.set(INCOMPLETE_RULE, {
44579
+ id: INCOMPLETE_RULE,
44580
+ name: INCOMPLETE_RULE,
44581
+ shortDescription: { text: "Package could not be fully analyzed \u2014 treat as unverified" },
44582
+ defaultConfiguration: { level: "warning" }
44583
+ });
44584
+ }
44585
+ results.push({
44586
+ ruleId: INCOMPLETE_RULE,
44587
+ level: "warning",
44588
+ message: { text: `${pkg.name} ${pkg.version}: analysis incomplete \u2014 the scanner could not fully evaluate this package. Treat as unverified, not safe.` },
44589
+ locations: [{
44590
+ physicalLocation: {
44591
+ artifactLocation: { uri: opts.lockfileUri ?? `dg:${pkg.name}@${pkg.version}` }
44592
+ }
44593
+ }],
44594
+ partialFingerprints: { dg_finding: `${pkg.name}@${pkg.version}#${INCOMPLETE_RULE}`.slice(0, 240) }
44595
+ });
44596
+ }
44520
44597
  const findings = pkg.findings ?? [];
44598
+ let pkgResultCount = 0;
44521
44599
  for (const f of findings) {
44522
44600
  const id = findingId(f);
44523
44601
  const level = severityToLevel(f.severity);
@@ -44541,6 +44619,32 @@ function buildSarif(response, opts = {}) {
44541
44619
  }],
44542
44620
  partialFingerprints: { dg_finding: findingFingerprint(pkg, f) }
44543
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
+ });
44544
44648
  }
44545
44649
  }
44546
44650
  return {
@@ -44677,7 +44781,7 @@ function shouldFireAudit(policy, decisionAction) {
44677
44781
  return false;
44678
44782
  }
44679
44783
  function flagPackages(packages) {
44680
- return packages.filter((p) => p.score >= 60);
44784
+ return packages.filter((p) => (p.action ?? "pass") !== "pass");
44681
44785
  }
44682
44786
  async function dispatchPublishCheckAudit(opts) {
44683
44787
  try {
@@ -44704,8 +44808,8 @@ function bypassLogPath2() {
44704
44808
  }
44705
44809
  function recordBypassLocally(record) {
44706
44810
  try {
44707
- const path2 = bypassLogPath2();
44708
- const dir = dirname10(path2);
44811
+ const path = bypassLogPath2();
44812
+ const dir = dirname10(path);
44709
44813
  if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true, mode: 448 });
44710
44814
  const full = {
44711
44815
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -44716,7 +44820,7 @@ function recordBypassLocally(record) {
44716
44820
  reason: record.reason,
44717
44821
  packages: record.packages
44718
44822
  };
44719
- appendFileSync3(path2, JSON.stringify(full) + "\n", { mode: 384 });
44823
+ appendFileSync3(path, JSON.stringify(full) + "\n", { mode: 384 });
44720
44824
  } catch {
44721
44825
  }
44722
44826
  }
@@ -44789,13 +44893,13 @@ function wrapperPackagesFromResult(result, topLevelNames) {
44789
44893
  }));
44790
44894
  }
44791
44895
  function loadPackageLockJson(cwd2 = process.cwd()) {
44792
- const path2 = resolvePath(cwd2, "package-lock.json");
44793
- if (!existsSync17(path2)) return null;
44896
+ const path = resolvePath(cwd2, "package-lock.json");
44897
+ if (!existsSync17(path)) return null;
44794
44898
  try {
44795
- const st = lstatSync5(path2);
44899
+ const st = lstatSync5(path);
44796
44900
  if (!st.isFile()) return null;
44797
44901
  if (st.size > MAX_PACKAGE_LOCK_BYTES) return null;
44798
- return JSON.parse(readFileSync11(path2, "utf8"));
44902
+ return JSON.parse(readFileSync11(path, "utf8"));
44799
44903
  } catch {
44800
44904
  return null;
44801
44905
  }
@@ -44875,7 +44979,7 @@ function maybePrintFirstScanNotice(config) {
44875
44979
  if (getScanNoticeShownAt2() !== null) return;
44876
44980
  process.stderr.write(
44877
44981
  import_chalk5.default.dim(
44878
- " 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"
44879
44983
  )
44880
44984
  );
44881
44985
  recordScanNoticeShown2();
@@ -44941,6 +45045,7 @@ function handleFreeCapReached2(error, jsonMode = false) {
44941
45045
  function actionColor(action) {
44942
45046
  if (action === "block") return import_chalk5.default.red;
44943
45047
  if (action === "warn") return import_chalk5.default.yellow;
45048
+ if (action === "analysis_incomplete") return import_chalk5.default.cyan;
44944
45049
  return import_chalk5.default.green;
44945
45050
  }
44946
45051
  function actionBadge(pkg) {
@@ -44957,6 +45062,9 @@ function isBlocked(p) {
44957
45062
  function isWarned(p) {
44958
45063
  return p.action === "warn";
44959
45064
  }
45065
+ function isIncomplete(p) {
45066
+ return p.action === "analysis_incomplete";
45067
+ }
44960
45068
  function renderResultClean(result, _config) {
44961
45069
  const lines = [];
44962
45070
  const total = result.packages.length;
@@ -44968,7 +45076,8 @@ function renderResultClean(result, _config) {
44968
45076
  }
44969
45077
  const blocked = result.packages.filter(isBlocked);
44970
45078
  const warned = result.packages.filter(isWarned);
44971
- if (result.action === "pass" && blocked.length === 0 && warned.length === 0) {
45079
+ const incomplete = result.packages.filter(isIncomplete);
45080
+ if (result.action === "pass" && blocked.length === 0 && warned.length === 0 && incomplete.length === 0) {
44972
45081
  lines.push("");
44973
45082
  lines.push(` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("Dependency Guardian")} checked ${total} package${total !== 1 ? "s" : ""}. ${import_chalk5.default.green("No risky behavior found.")}`);
44974
45083
  if (result.durationMs) {
@@ -44977,11 +45086,18 @@ function renderResultClean(result, _config) {
44977
45086
  lines.push("");
44978
45087
  return lines.join("\n");
44979
45088
  }
44980
- const headerColor = result.action === "block" ? import_chalk5.default.red : import_chalk5.default.yellow;
44981
- const headerLabel = result.action === "block" ? "BLOCK" : "WARN";
45089
+ const headerLabel = result.action === "block" ? "BLOCK" : result.action === "warn" ? "WARN" : result.action === "analysis_incomplete" ? "UNKNOWN" : "PASS";
45090
+ const headerColor = actionColor(result.action);
45091
+ const cleanCount = total - blocked.length - warned.length - incomplete.length;
45092
+ const countParts = [
45093
+ `${blocked.length} block`,
45094
+ `${warned.length} warn`,
45095
+ ...incomplete.length > 0 ? [`${incomplete.length} unknown`] : [],
45096
+ `${cleanCount} clean`
45097
+ ];
44982
45098
  lines.push("");
44983
45099
  lines.push(` ${headerColor(import_chalk5.default.bold(headerLabel))} ${import_chalk5.default.bold("Dependency Guardian")} ${import_chalk5.default.dim(`(score ${result.score})`)}`);
44984
- lines.push(` ${import_chalk5.default.dim(`${total} package${total !== 1 ? "s" : ""} scanned \xB7 ${blocked.length} block \xB7 ${warned.length} warn \xB7 ${total - blocked.length - warned.length} clean`)}`);
45100
+ lines.push(` ${import_chalk5.default.dim(`${total} package${total !== 1 ? "s" : ""} scanned \xB7 ${countParts.join(" \xB7 ")}`)}`);
44985
45101
  lines.push("");
44986
45102
  const showFirst = (pkgs, color, label) => {
44987
45103
  if (pkgs.length === 0) return;
@@ -44997,10 +45113,13 @@ function renderResultClean(result, _config) {
44997
45113
  };
44998
45114
  showFirst(blocked, import_chalk5.default.red, "Blocked");
44999
45115
  showFirst(warned, import_chalk5.default.yellow, "Warnings");
45116
+ showFirst(incomplete, import_chalk5.default.cyan, "Could not analyze");
45000
45117
  if (result.action === "block") {
45001
45118
  lines.push(` ${import_chalk5.default.dim("Next step:")} review the findings above, then either pin a safe version or use ${import_chalk5.default.bold("--dg-force")} to bypass.`);
45002
45119
  } else if (result.action === "warn") {
45003
45120
  lines.push(` ${import_chalk5.default.dim("Next step:")} review the warnings; install proceeds unless you set ${import_chalk5.default.bold("--mode block")}.`);
45121
+ } else if (result.action === "analysis_incomplete") {
45122
+ lines.push(` ${import_chalk5.default.dim("Next step:")} one or more packages could not be fully analyzed \u2014 treat as unverified, not safe. Re-run to retry.`);
45004
45123
  }
45005
45124
  lines.push("");
45006
45125
  return lines.join("\n");
@@ -45019,13 +45138,21 @@ function renderResultDetails(result, _config) {
45019
45138
  lines.push("");
45020
45139
  const blocked = result.packages.filter(isBlocked);
45021
45140
  const warned = result.packages.filter(isWarned);
45022
- const passWithScore = result.packages.filter((p) => p.score > 0 && p.score < 60);
45023
- const clean = result.packages.filter((p) => p.score === 0);
45141
+ const incomplete = result.packages.filter(isIncomplete);
45142
+ const rest = result.packages.filter((p) => !isBlocked(p) && !isWarned(p) && !isIncomplete(p));
45143
+ const passWithScore = rest.filter((p) => p.score > 0 && p.score < 60);
45144
+ const clean = rest.filter((p) => p.score === 0);
45024
45145
  const total = result.packages.length;
45025
45146
  const needsAttention = blocked.length + warned.length;
45026
- if (needsAttention > 0) {
45147
+ if (needsAttention > 0 || incomplete.length > 0) {
45148
+ const segs = [
45149
+ import_chalk5.default.red(`${blocked.length} block`),
45150
+ import_chalk5.default.yellow(`${warned.length} warn`),
45151
+ ...incomplete.length > 0 ? [import_chalk5.default.cyan(`${incomplete.length} unknown`)] : [],
45152
+ import_chalk5.default.green(`${clean.length + passWithScore.length} pass`)
45153
+ ];
45027
45154
  lines.push(
45028
- ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk5.default.dim("\u2502")} ${import_chalk5.default.red(`${blocked.length} block`)} ${import_chalk5.default.dim("\u2502")} ${import_chalk5.default.yellow(`${warned.length} warn`)} ${import_chalk5.default.dim("\u2502")} ${import_chalk5.default.green(`${clean.length + passWithScore.length} pass`)}`
45155
+ ` ${total} package${total !== 1 ? "s" : ""} scanned ${import_chalk5.default.dim("\u2502")} ${segs.join(` ${import_chalk5.default.dim("\u2502")} `)}`
45029
45156
  );
45030
45157
  } else {
45031
45158
  lines.push(
@@ -45038,8 +45165,8 @@ function renderResultDetails(result, _config) {
45038
45165
  lines.push("");
45039
45166
  return lines.join("\n");
45040
45167
  }
45041
- if (needsAttention > 0) {
45042
- const groups = groupPackages([...blocked, ...warned]);
45168
+ if (needsAttention > 0 || incomplete.length > 0) {
45169
+ const groups = groupPackages([...blocked, ...warned, ...incomplete]);
45043
45170
  lines.push(` ${import_chalk5.default.bold("Needs Attention")}`);
45044
45171
  lines.push(` ${import_chalk5.default.dim("\u2500".repeat(60))}`);
45045
45172
  for (const group of groups) {
@@ -45183,14 +45310,7 @@ async function runStatic(config) {
45183
45310
  }
45184
45311
  if (discovery.pythonPackages.length > 0) {
45185
45312
  const pyResult = await callPyPIAnalyzeAPI(discovery.pythonPackages, config);
45186
- result.packages.push(...pyResult.packages);
45187
- result.score = Math.max(result.score, pyResult.score);
45188
- if (pyResult.action === "block" || pyResult.action === "warn" && result.action === "pass") {
45189
- result.action = pyResult.action;
45190
- }
45191
- if (pyResult.freeScansRemaining !== void 0) {
45192
- result.freeScansRemaining = pyResult.freeScansRemaining;
45193
- }
45313
+ result = mergeResponses([result, pyResult]);
45194
45314
  }
45195
45315
  clearSpinner();
45196
45316
  dbg(
@@ -45354,11 +45474,11 @@ function buildInstallArgs(parsed, topLevelSpecs, tree, config) {
45354
45474
  if (tree.length > 0 && topLevelSpecs.length > 0) {
45355
45475
  args = pinTopLevelArgs(args, topLevelSpecs, tree);
45356
45476
  }
45357
- const wantsNoScripts = parsed.dgNoScripts || config.strict;
45358
- if (wantsNoScripts && !args.includes("--ignore-scripts")) {
45359
- args = [...args, "--ignore-scripts"];
45360
- }
45361
- return args;
45477
+ return injectIgnoreScripts(args, {
45478
+ isNpmFamily: true,
45479
+ strict: config.strict,
45480
+ dgNoScripts: parsed.dgNoScripts
45481
+ });
45362
45482
  }
45363
45483
  async function scanAndInstallStatic(resolved, parsed, config) {
45364
45484
  const topLevelSpecs = resolved.map((p) => `${p.name}@${p.version}`);
@@ -45387,6 +45507,14 @@ async function scanAndInstallStatic(resolved, parsed, config) {
45387
45507
  process.stderr.write(
45388
45508
  import_chalk5.default.dim(" Only top-level packages would be scanned; transitive deps would slip through. Use --dg-force to bypass.\n\n")
45389
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
+ });
45390
45518
  process.exit(2);
45391
45519
  }
45392
45520
  process.stderr.write(
@@ -45606,6 +45734,42 @@ ${installLine}
45606
45734
  });
45607
45735
  process.exit(2);
45608
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
+ }
45609
45773
  }
45610
45774
  async function runStaticPip(pipArgs, config) {
45611
45775
  config = mergeProjectConfig(config, process.argv.slice(2));
@@ -45695,6 +45859,17 @@ async function runStaticPip(pipArgs, config) {
45695
45859
  )
45696
45860
  );
45697
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);
45698
45873
  note(
45699
45874
  config,
45700
45875
  import_chalk5.default.dim(
@@ -45723,14 +45898,14 @@ async function runStaticPip(pipArgs, config) {
45723
45898
  process.stderr.write(
45724
45899
  import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
45725
45900
  );
45726
- const code2 = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45901
+ const code2 = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45727
45902
  process.exit(code2);
45728
45903
  }
45729
45904
  process.stderr.write(
45730
45905
  import_chalk5.default.yellow(` Warning: Scan failed (${msg}). Proceeding with install (mode=${config.mode}).
45731
45906
  `)
45732
45907
  );
45733
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45908
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45734
45909
  process.exit(code);
45735
45910
  return;
45736
45911
  }
@@ -45767,7 +45942,7 @@ ${installLine}
45767
45942
  `);
45768
45943
  printTrialBanner(result, config);
45769
45944
  process.stderr.write("\n");
45770
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45945
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45771
45946
  emitWrapperJson(config, {
45772
45947
  ecosystem: "pypi",
45773
45948
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
@@ -45799,7 +45974,7 @@ ${installLine}
45799
45974
  });
45800
45975
  process.exit(1);
45801
45976
  }
45802
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
45977
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45803
45978
  emitWrapperJson(config, {
45804
45979
  ecosystem: "pypi",
45805
45980
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
@@ -45822,7 +45997,7 @@ ${installLine}
45822
45997
  process.stderr.write(
45823
45998
  import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
45824
45999
  );
45825
- const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
46000
+ const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45826
46001
  emitWrapperJson(config, {
45827
46002
  ecosystem: "pypi",
45828
46003
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
@@ -45857,6 +46032,42 @@ ${installLine}
45857
46032
  });
45858
46033
  process.exit(2);
45859
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
+ }
45860
46071
  }
45861
46072
  async function runStaticLogin() {
45862
46073
  const {
@@ -45969,6 +46180,7 @@ var init_static_output = __esm({
45969
46180
  init_lockfile();
45970
46181
  init_npm_wrapper();
45971
46182
  init_pip_wrapper();
46183
+ init_wrapper_shared();
45972
46184
  init_artifact_integrity();
45973
46185
  init_sanitize();
45974
46186
  init_format_helpers();
@@ -46763,11 +46975,11 @@ var init_InteractiveResultsView = __esm({
46763
46975
  const scanUsage = usageDisplay ? usageDisplay.text : result.freeScansRemaining !== void 0 ? `${result.freeScansRemaining.toLocaleString()} packages left` : scanUsageProp;
46764
46976
  const usageNearLimit = usageDisplay?.nearLimit ?? false;
46765
46977
  const flagged = (0, import_react30.useMemo)(
46766
- () => result.packages.filter((p) => p.score > 0),
46978
+ () => result.packages.filter((p) => (p.action ?? "pass") !== "pass"),
46767
46979
  [result.packages]
46768
46980
  );
46769
46981
  const clean = (0, import_react30.useMemo)(
46770
- () => result.packages.filter((p) => p.score === 0),
46982
+ () => result.packages.filter((p) => (p.action ?? "pass") === "pass"),
46771
46983
  [result.packages]
46772
46984
  );
46773
46985
  const total = result.packages.length;
@@ -47063,8 +47275,8 @@ var init_InteractiveResultsView = __esm({
47063
47275
  const { body, ext } = formatExport(payload, scope, format);
47064
47276
  const scopeTag = scope === "current-license" && currentLicenseIdx !== null ? `${(licenseGroups[currentLicenseIdx]?.spdx ?? "license").replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 32)}` : scope;
47065
47277
  const filename = `dg-scan-${ts}-${scopeTag}.${ext}`;
47066
- const path2 = resolvePath2(process.cwd(), filename);
47067
- writeFileSync11(path2, body, "utf-8");
47278
+ const path = resolvePath2(process.cwd(), filename);
47279
+ writeFileSync11(path, body, "utf-8");
47068
47280
  showExportMsg(`\u2713 Exported to ${filename}`);
47069
47281
  } catch (e) {
47070
47282
  showExportMsg(`Export failed: ${e.message}`);
@@ -48461,6 +48673,7 @@ var publish_check_exports = {};
48461
48673
  __export(publish_check_exports, {
48462
48674
  findPypiArtifacts: () => findPypiArtifacts,
48463
48675
  npmPackDryRun: () => npmPackDryRun,
48676
+ publishCheckExitCode: () => publishCheckExitCode,
48464
48677
  renderPublishCheckResult: () => renderPublishCheckResult,
48465
48678
  runNpmPublishCheck: () => runNpmPublishCheck,
48466
48679
  runPypiPublishCheck: () => runPypiPublishCheck,
@@ -48597,6 +48810,12 @@ function summarize(ecosystem, artifact, files, findings) {
48597
48810
  action
48598
48811
  };
48599
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
+ }
48600
48819
  async function runNpmPublishCheck(cwd2 = process.cwd()) {
48601
48820
  const pack = await npmPackDryRun(cwd2);
48602
48821
  if (!pack.ok) return { ok: false, errorMessage: pack.errorMessage };
@@ -48658,10 +48877,10 @@ function parseTar(buf) {
48658
48877
  }
48659
48878
  return out;
48660
48879
  }
48661
- async function readGzipped(path2) {
48880
+ async function readGzipped(path) {
48662
48881
  return new Promise((resolve3, reject) => {
48663
48882
  const chunks = [];
48664
- const stream = createReadStream(path2).pipe(createGunzip());
48883
+ const stream = createReadStream(path).pipe(createGunzip());
48665
48884
  stream.on("data", (c) => chunks.push(c));
48666
48885
  stream.on("end", () => resolve3(Buffer.concat(chunks)));
48667
48886
  stream.on("error", reject);
@@ -48894,11 +49113,11 @@ function validateEntry(raw) {
48894
49113
  };
48895
49114
  }
48896
49115
  function readRegistry() {
48897
- const path2 = registryPath();
48898
- if (!existsSync20(path2)) return [];
49116
+ const path = registryPath();
49117
+ if (!existsSync20(path)) return [];
48899
49118
  let raw;
48900
49119
  try {
48901
- raw = readFileSync14(path2, "utf-8");
49120
+ raw = readFileSync14(path, "utf-8");
48902
49121
  } catch {
48903
49122
  return [];
48904
49123
  }
@@ -48919,13 +49138,13 @@ function readRegistry() {
48919
49138
  return out;
48920
49139
  }
48921
49140
  function writeRegistry(entries) {
48922
- const path2 = registryPath();
48923
- const parent = dirname12(path2);
49141
+ const path = registryPath();
49142
+ const parent = dirname12(path);
48924
49143
  if (!existsSync20(parent)) mkdirSync8(parent, { recursive: true, mode: 448 });
48925
49144
  const payload = { version: 1, entries };
48926
- 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 });
48927
49146
  try {
48928
- chmodSync4(path2, 384);
49147
+ chmodSync4(path, 384);
48929
49148
  } catch {
48930
49149
  }
48931
49150
  }
@@ -49524,9 +49743,9 @@ function installPrefix(resolvedBinPath) {
49524
49743
  if (idx < 0) return null;
49525
49744
  return resolvedBinPath.slice(0, idx);
49526
49745
  }
49527
- function canWrite(path2) {
49746
+ function canWrite(path) {
49528
49747
  try {
49529
- accessSync(path2, constants2.W_OK);
49748
+ accessSync(path, constants2.W_OK);
49530
49749
  return true;
49531
49750
  } catch {
49532
49751
  return false;
@@ -49949,9 +50168,9 @@ async function revokeApiKey(apiKey) {
49949
50168
  return { ok: false, reason: e.message };
49950
50169
  }
49951
50170
  }
49952
- function rmFile(path2) {
50171
+ function rmFile(path) {
49953
50172
  try {
49954
- unlinkSync7(path2);
50173
+ unlinkSync7(path);
49955
50174
  return { ok: true };
49956
50175
  } catch (e) {
49957
50176
  const code = e.code;
@@ -49959,9 +50178,9 @@ function rmFile(path2) {
49959
50178
  return { ok: false, reason: e.message };
49960
50179
  }
49961
50180
  }
49962
- function rmTree(path2) {
50181
+ function rmTree(path) {
49963
50182
  try {
49964
- rmSync2(path2, { recursive: true, force: true });
50183
+ rmSync2(path, { recursive: true, force: true });
49965
50184
  return { ok: true };
49966
50185
  } catch (e) {
49967
50186
  return { ok: false, reason: e.message };
@@ -50950,8 +51169,8 @@ var init_ProjectSelector = __esm({
50950
51169
  const ecoCountPlainLen = `${proj.ecosystem} ${proj.packageCount} packages`.length;
50951
51170
  const fixedPrefixLen = 4;
50952
51171
  const pathColWidth = Math.max(20, termCols - fixedPrefixLen - ecoCountPlainLen - 3);
50953
- const path2 = sanitize(proj.relativePath);
50954
- 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);
50955
51174
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Text, { backgroundColor: isCursor ? "#1a1a2e" : void 0, wrap: "truncate-end", children: [
50956
51175
  prefix,
50957
51176
  check,
@@ -51046,6 +51265,7 @@ var init_App2 = __esm({
51046
51265
  await init_ProjectSelector();
51047
51266
  await init_SetupBanner();
51048
51267
  await init_useTerminalSize();
51268
+ init_static_output();
51049
51269
  init_terminal_state();
51050
51270
  import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
51051
51271
  App2 = ({ config, userStatus, scanUsage, setupIssues = [] }) => {
@@ -51084,16 +51304,7 @@ var init_App2 = __esm({
51084
51304
  }, []);
51085
51305
  const handleResultsExit = (0, import_react36.useCallback)(() => {
51086
51306
  if (state.phase === "results") {
51087
- const { result } = state;
51088
- if (result.action === "block" && config.mode === "block") {
51089
- process.exitCode = 2;
51090
- } else if (result.action === "block" || result.action === "warn") {
51091
- process.exitCode = 1;
51092
- } else if (result.action === "analysis_incomplete") {
51093
- process.exitCode = 4;
51094
- } else {
51095
- process.exitCode = 0;
51096
- }
51307
+ process.exitCode = scanExitCode(state.result.action, config.mode);
51097
51308
  }
51098
51309
  leaveAltScreen();
51099
51310
  exit();
@@ -51122,7 +51333,10 @@ var init_App2 = __esm({
51122
51333
  `, 3);
51123
51334
  return () => clearTimeout(timer);
51124
51335
  }
51125
- }, [state, exitWithMessage]);
51336
+ if (state.phase === "results") {
51337
+ process.exitCode = scanExitCode(state.result.action, config.mode);
51338
+ }
51339
+ }, [state, config, exitWithMessage]);
51126
51340
  use_input_default((input, key) => {
51127
51341
  if (state.phase === "discovering" || state.phase === "scanning") {
51128
51342
  if (input === "q" || key.escape) {
@@ -51272,9 +51486,9 @@ function locateInkInstancesPath() {
51272
51486
  async function initInkInstances() {
51273
51487
  if (realInstances) return;
51274
51488
  try {
51275
- const path2 = locateInkInstancesPath();
51276
- if (!path2) return;
51277
- const mod = await import(path2);
51489
+ const path = locateInkInstancesPath();
51490
+ if (!path) return;
51491
+ const mod = await import(path);
51278
51492
  realInstances = mod.default ?? null;
51279
51493
  } catch {
51280
51494
  realInstances = null;
@@ -51524,6 +51738,8 @@ function reducer4(_state, action) {
51524
51738
  return { phase: "warn", result: action.result, dgForce: action.dgForce };
51525
51739
  case "BLOCKED":
51526
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 };
51527
51743
  case "INSTALLING":
51528
51744
  return { phase: "installing" };
51529
51745
  case "DONE":
@@ -51558,6 +51774,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51558
51774
  if (started.current) return;
51559
51775
  started.current = true;
51560
51776
  const parsed = parsedRef.current;
51777
+ let installArgs = parsed.rawArgs;
51561
51778
  (async () => {
51562
51779
  try {
51563
51780
  if (!parsed.shouldScan) {
@@ -51586,14 +51803,45 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51586
51803
  dispatch({ type: "DONE", exitCode: code });
51587
51804
  return;
51588
51805
  }
51589
- dispatch({ type: "SCANNING", count: resolved.length });
51590
- 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);
51591
51839
  if (result.action === "pass") {
51592
51840
  if (exit) exit();
51593
51841
  const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
51594
51842
  const line = formatPassLine(result, chalk18);
51595
51843
  process.stderr.write(" " + line + "\n\n");
51596
- const code = await opts.runInstall(parsed.rawArgs);
51844
+ const code = await opts.runInstall(installArgs);
51597
51845
  process.exit(code);
51598
51846
  return;
51599
51847
  }
@@ -51609,7 +51857,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51609
51857
  });
51610
51858
  dispatch({ type: "WARN", result, dgForce: true });
51611
51859
  dispatch({ type: "INSTALLING" });
51612
- const code = await opts.runInstall(parsed.rawArgs);
51860
+ const code = await opts.runInstall(installArgs);
51613
51861
  dispatch({ type: "DONE", exitCode: code });
51614
51862
  return;
51615
51863
  }
@@ -51627,7 +51875,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51627
51875
  packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51628
51876
  });
51629
51877
  dispatch({ type: "INSTALLING" });
51630
- const code = await opts.runInstall(parsed.rawArgs);
51878
+ const code = await opts.runInstall(installArgs);
51631
51879
  dispatch({ type: "DONE", exitCode: code });
51632
51880
  } else {
51633
51881
  dispatch({ type: "DONE", exitCode: 1 });
@@ -51646,7 +51894,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51646
51894
  });
51647
51895
  dispatch({ type: "BLOCKED", result, dgForce: true });
51648
51896
  dispatch({ type: "INSTALLING" });
51649
- const code = await opts.runInstall(parsed.rawArgs);
51897
+ const code = await opts.runInstall(installArgs);
51650
51898
  dispatch({ type: "DONE", exitCode: code });
51651
51899
  return;
51652
51900
  }
@@ -51664,13 +51912,32 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51664
51912
  packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51665
51913
  });
51666
51914
  dispatch({ type: "INSTALLING" });
51667
- const code = await opts.runInstall(parsed.rawArgs);
51915
+ const code = await opts.runInstall(installArgs);
51668
51916
  dispatch({ type: "DONE", exitCode: code });
51669
51917
  } else {
51670
51918
  dispatch({ type: "DONE", exitCode: 2 });
51671
51919
  }
51672
51920
  return;
51673
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
+ }
51674
51941
  } catch (error) {
51675
51942
  if (error instanceof FreeCapReachedError) {
51676
51943
  dispatch({ type: "FREE_CAP_REACHED" });
@@ -51688,7 +51955,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51688
51955
  }
51689
51956
  dispatch({ type: "ERROR", message, proceed: true });
51690
51957
  dispatch({ type: "INSTALLING" });
51691
- const code = await opts.runInstall(parsedRef.current.rawArgs);
51958
+ const code = await opts.runInstall(installArgs);
51692
51959
  dispatch({ type: "DONE", exitCode: code });
51693
51960
  }
51694
51961
  })();
@@ -51711,11 +51978,13 @@ var init_useWrapperBase = __esm({
51711
51978
  "use strict";
51712
51979
  import_react37 = __toESM(require_react(), 1);
51713
51980
  init_client();
51981
+ init_wrapper_shared();
51714
51982
  init_npm_wrapper();
51715
51983
  init_pip_wrapper();
51716
51984
  NPM_OPTIONS = {
51717
51985
  parseArgs: parseNpmArgs,
51718
51986
  resolvePackages,
51987
+ resolveTree: resolveTreeNpm,
51719
51988
  callAnalyze: callAnalyzeAPI,
51720
51989
  runInstall: runNpm,
51721
51990
  inferSpecsFromContext: () => readBareInstallPackages(process.cwd()),
@@ -51724,6 +51993,7 @@ var init_useWrapperBase = __esm({
51724
51993
  PIP_OPTIONS = {
51725
51994
  parseArgs: parsePipArgs,
51726
51995
  resolvePackages: resolvePackages2,
51996
+ resolveTree: resolveTreePip,
51727
51997
  callAnalyze: callPyPIAnalyzeAPI,
51728
51998
  runInstall: runPip,
51729
51999
  inferSpecsFromContext: (parsed) => {
@@ -51787,8 +52057,8 @@ var init_ResultsView = __esm({
51787
52057
  config: _config,
51788
52058
  durationMs
51789
52059
  }) => {
51790
- const flagged = result.packages.filter((p) => p.score > 0);
51791
- const clean = result.packages.filter((p) => p.score === 0);
52060
+ const flagged = result.packages.filter((p) => (p.action ?? "pass") !== "pass");
52061
+ const clean = result.packages.filter((p) => (p.action ?? "pass") === "pass");
51792
52062
  const total = result.packages.length;
51793
52063
  const groups = groupPackages(flagged);
51794
52064
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", paddingLeft: 2, children: [
@@ -51832,7 +52102,7 @@ var init_ResultsView = __esm({
51832
52102
  import_chalk16.default.dim(`package${clean.length !== 1 ? "s" : ""} passed with score 0`)
51833
52103
  ] }),
51834
52104
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Newline, {}),
51835
- groups.filter((g) => g.packages[0].score > 0).map((group) => {
52105
+ groups.filter((g) => (g.packages[0].action ?? "pass") !== "pass").map((group) => {
51836
52106
  const rep = group.packages[0];
51837
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`;
51838
52108
  const visibleFindings = rep.findings.filter((f) => f.severity > 1).sort((a, b) => b.severity - a.severity);
@@ -51943,13 +52213,15 @@ function reasonTag(pkg) {
51943
52213
  function countSummary(result) {
51944
52214
  let block = 0;
51945
52215
  let warn = 0;
52216
+ let unknown = 0;
51946
52217
  let clean = 0;
51947
52218
  for (const p of result.packages) {
51948
52219
  if (p.action === "block") block++;
51949
52220
  else if (p.action === "warn") warn++;
52221
+ else if (p.action === "analysis_incomplete") unknown++;
51950
52222
  else clean++;
51951
52223
  }
51952
- return { block, warn, clean };
52224
+ return { block, warn, unknown, clean };
51953
52225
  }
51954
52226
  var import_jsx_runtime17, WrapperVerdictLine;
51955
52227
  var init_WrapperVerdictLine = __esm({
@@ -52020,6 +52292,7 @@ var init_WrapperVerdictLine = __esm({
52020
52292
  const parts = [];
52021
52293
  if (counts.block > 0) parts.push(`${counts.block} block`);
52022
52294
  if (counts.warn > 0) parts.push(`${counts.warn} warn`);
52295
+ if (counts.unknown > 0) parts.push(`${counts.unknown} unknown`);
52023
52296
  if (counts.clean > 0) parts.push(`${counts.clean} clean`);
52024
52297
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Box_default, { flexDirection: "row", children: [
52025
52298
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { color, children: [
@@ -52118,6 +52391,14 @@ var init_WrapperApp = __esm({
52118
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 }) }),
52119
52392
  !state.dgForce && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ConfirmPrompt, { message: "", onConfirm: handleConfirm, onReject: handleReject })
52120
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) });
52121
52402
  case "installing":
52122
52403
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner2, { label: labels.installing });
52123
52404
  case "done":
@@ -52197,26 +52478,33 @@ function parseCondaArgs(args) {
52197
52478
  async function resolveTopLevel(_parsed) {
52198
52479
  return { resolved: [], failed: [] };
52199
52480
  }
52200
- async function runStaticConda(args) {
52481
+ async function runStaticConda(args, ecosystem, config) {
52201
52482
  const parsed = parseCondaArgs(args);
52202
- if (process.stderr.isTTY && parsed.shouldScan) {
52483
+ if (parsed.shouldScan && (config.mode === "block" || config.strict) && !parsed.dgForce) {
52484
+ process.stderr.write(
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.
52487
+
52488
+ `)
52489
+ );
52490
+ return 2;
52491
+ }
52492
+ if (parsed.shouldScan && process.stderr.isTTY) {
52203
52493
  process.stderr.write(
52204
- import_chalk18.default.yellow(`\u2139\uFE0F DG: conda packages aren't yet scanned (conda-forge isn't supported in the scanner backend yet).
52205
- `) + import_chalk18.default.dim(` Passing through to real conda. Use \`dg verify\` for individual pypi-known packages.
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.
52206
52496
 
52207
52497
  `)
52208
52498
  );
52209
52499
  }
52210
- const real = resolveRealBinary("conda");
52500
+ const real = resolveRealBinary(ecosystem);
52211
52501
  if (!real) {
52212
- process.stderr.write(`dg: real conda not found on PATH
52502
+ process.stderr.write(`dg: real ${ecosystem} not found on PATH
52213
52503
  `);
52214
52504
  return 127;
52215
52505
  }
52216
- const nonce = readNonce();
52217
- const env3 = nonce ? { ...process.env, DG_SHIM_ACTIVE: nonce } : { ...process.env };
52218
52506
  return await new Promise((resolve3) => {
52219
- const child = spawn5(real, parsed.rawArgs, { stdio: "inherit", env: env3 });
52507
+ const child = spawn5(real, parsed.rawArgs, { stdio: "inherit", env: childInstallEnv() });
52220
52508
  child.on("close", (code) => resolve3(code ?? 1));
52221
52509
  child.on("error", () => resolve3(1));
52222
52510
  });
@@ -52596,7 +52884,11 @@ function parseUvArgs(args) {
52596
52884
  for (let i = argStart; i < filtered.length; i++) {
52597
52885
  const arg = filtered[i];
52598
52886
  if (arg === "-r" || arg === "--requirement") {
52599
- 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
+ }
52600
52892
  continue;
52601
52893
  }
52602
52894
  if (arg.startsWith("-")) {
@@ -52757,9 +53049,7 @@ function emitJson(config, result) {
52757
53049
  process.stdout.write(JSON.stringify(result, null, 2) + "\n");
52758
53050
  }
52759
53051
  function shimSentinelEnv3() {
52760
- const nonce = readNonce();
52761
- if (!nonce) return process.env;
52762
- return { ...process.env, DG_SHIM_ACTIVE: nonce };
53052
+ return childInstallEnv();
52763
53053
  }
52764
53054
  async function spawnRealBinary(adapter7, args) {
52765
53055
  const real = resolveRealBinary(adapter7.realBinaryName);
@@ -52804,8 +53094,46 @@ async function runEcosystemWrapper(adapter7, args, config) {
52804
53094
  `)
52805
53095
  );
52806
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
+ });
52807
53134
  let scanSet = resolved;
52808
53135
  let treeOk = true;
53136
+ let treeError;
52809
53137
  if (adapter7.resolveTransitive) {
52810
53138
  const tree = await adapter7.resolveTransitive(parsed);
52811
53139
  if (tree.ok && tree.packages.length > 0) {
@@ -52825,15 +53153,36 @@ async function runEcosystemWrapper(adapter7, args, config) {
52825
53153
  `)
52826
53154
  );
52827
53155
  }
52828
- } else if (!tree.ok && !config.json && !config.quiet) {
53156
+ } else if (!tree.ok) {
52829
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) {
52830
53163
  process.stderr.write(
52831
- 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
+
52832
53167
  `)
52833
53168
  );
52834
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
+ );
52835
53185
  }
52836
- void treeOk;
52837
53186
  let result;
52838
53187
  try {
52839
53188
  if (adapter7.apiKind === "npm") {
@@ -52859,10 +53208,10 @@ async function runEcosystemWrapper(adapter7, args, config) {
52859
53208
  });
52860
53209
  return 1;
52861
53210
  }
52862
- if (config.mode === "block" && !parsed.dgForce) {
53211
+ if ((config.mode === "block" || config.strict) && !parsed.dgForce) {
52863
53212
  process.stderr.write(
52864
53213
  import_chalk19.default.red(` \u2717 DG scan failed: ${err.message}
52865
- `) + 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.
52866
53215
 
52867
53216
  `)
52868
53217
  );
@@ -52874,7 +53223,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
52874
53223
  installExitCode: null,
52875
53224
  error: { code: "scan_failed", message: err.message }
52876
53225
  });
52877
- return 3;
53226
+ return 2;
52878
53227
  }
52879
53228
  if (!config.json && !config.quiet) {
52880
53229
  process.stderr.write(
@@ -52882,7 +53231,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
52882
53231
  `)
52883
53232
  );
52884
53233
  }
52885
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53234
+ const code2 = await spawnRealBinary(adapter7, installArgs);
52886
53235
  emitJson(config, {
52887
53236
  ecosystem: adapter7.ecosystem,
52888
53237
  packages: [],
@@ -52911,7 +53260,7 @@ ${installLine}
52911
53260
  }
52912
53261
  process.stderr.write("\n");
52913
53262
  }
52914
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53263
+ const code2 = await spawnRealBinary(adapter7, installArgs);
52915
53264
  emitJson(config, {
52916
53265
  ecosystem: adapter7.ecosystem,
52917
53266
  packages: packagesFromResult(result, topLevelNames),
@@ -52958,7 +53307,7 @@ ${installLine}
52958
53307
  } else if (!config.json && !config.quiet) {
52959
53308
  process.stderr.write(import_chalk19.default.dim(" Proceeding (non-interactive).\n"));
52960
53309
  }
52961
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53310
+ const code2 = await spawnRealBinary(adapter7, installArgs);
52962
53311
  emitJson(config, {
52963
53312
  ecosystem: adapter7.ecosystem,
52964
53313
  packages: packagesFromResult(result, topLevelNames),
@@ -52986,7 +53335,7 @@ ${installLine}
52986
53335
 
52987
53336
  `));
52988
53337
  }
52989
- const code2 = await spawnRealBinary(adapter7, parsed.rawArgs);
53338
+ const code2 = await spawnRealBinary(adapter7, installArgs);
52990
53339
  emitJson(config, {
52991
53340
  ecosystem: adapter7.ecosystem,
52992
53341
  packages: packagesFromResult(result, topLevelNames),
@@ -53024,11 +53373,38 @@ ${installLine}
53024
53373
  });
53025
53374
  return 2;
53026
53375
  }
53027
- 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);
53028
53404
  emitJson(config, {
53029
53405
  ecosystem: adapter7.ecosystem,
53030
53406
  packages: packagesFromResult(result, topLevelNames),
53031
- scanVerdict: "skipped",
53407
+ scanVerdict: "analysis_incomplete",
53032
53408
  installRan: true,
53033
53409
  installExitCode: code
53034
53410
  });
@@ -53044,6 +53420,9 @@ var init_wrapper_factory = __esm({
53044
53420
  init_install();
53045
53421
  init_audit_dispatcher();
53046
53422
  init_allowlist();
53423
+ init_wrapper_shared();
53424
+ init_npm_wrapper();
53425
+ init_pip_wrapper();
53047
53426
  }
53048
53427
  });
53049
53428
 
@@ -53264,7 +53643,7 @@ async function main() {
53264
53643
  const v = args[ecoArgIdx + 1];
53265
53644
  if (v === "npm" || v === "pypi") ecosystem = v;
53266
53645
  }
53267
- 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));
53268
53647
  const { existsSync: existsSync25 } = await import("node:fs");
53269
53648
  const { join: join15 } = await import("node:path");
53270
53649
  if (ecosystem === "auto") {
@@ -53294,7 +53673,7 @@ async function main() {
53294
53673
  } else {
53295
53674
  process.stderr.write(renderPublishCheckResult2(result));
53296
53675
  }
53297
- if (result.action === "block" || result.action === "block" && force) {
53676
+ if (result.action === "block") {
53298
53677
  try {
53299
53678
  const reasonIdx = args.indexOf("--dg-force-reason");
53300
53679
  const bypassReason = reasonIdx >= 0 ? args[reasonIdx + 1] : void 0;
@@ -53314,9 +53693,7 @@ async function main() {
53314
53693
  } catch {
53315
53694
  }
53316
53695
  }
53317
- if (result.action === "block" && !force) process.exit(2);
53318
- if (result.action === "analysis_incomplete") process.exit(4);
53319
- process.exit(0);
53696
+ process.exit(publishCheckExitCode2(result.action, force));
53320
53697
  }
53321
53698
  if (rawCommand === "hook") {
53322
53699
  const { handleHookCommand: handleHookCommand2 } = await Promise.resolve().then(() => (init_hook(), hook_exports));
@@ -53520,10 +53897,8 @@ async function handleWrapInternal(argv) {
53520
53897
  const ecoTyped = ecosystem;
53521
53898
  const spawnReal = async (real, args) => {
53522
53899
  const { spawn: spawn7 } = await import("node:child_process");
53523
- const { readNonce: readNonce3 } = await Promise.resolve().then(() => (init_install(), install_exports));
53524
- const nonce = readNonce3();
53525
- const env3 = nonce ? { ...process.env, DG_SHIM_ACTIVE: nonce } : { ...process.env };
53526
- 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() });
53527
53902
  return await new Promise((resolve3) => {
53528
53903
  child.on("close", (code) => resolve3(code ?? 1));
53529
53904
  child.on("error", () => resolve3(1));
@@ -53573,7 +53948,7 @@ async function handleWrapInternal(argv) {
53573
53948
  }
53574
53949
  if (ecosystem === "conda" || ecosystem === "mamba") {
53575
53950
  const { runStaticConda: runStaticConda2 } = await Promise.resolve().then(() => (init_conda_wrapper(), conda_wrapper_exports));
53576
- return await runStaticConda2(wrapperArgs);
53951
+ return await runStaticConda2(wrapperArgs, ecosystem, config);
53577
53952
  }
53578
53953
  const adapterImports = {
53579
53954
  pnpm: () => Promise.resolve().then(() => (init_pnpm_wrapper(), pnpm_wrapper_exports)),