@westbayberry/dg 1.2.0 → 1.3.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.
Files changed (2) hide show
  1. package/dist/index.mjs +679 -694
  2. package/package.json +1 -1
package/dist/index.mjs CHANGED
@@ -1894,6 +1894,7 @@ __export(auth_exports, {
1894
1894
  pollAuthSession: () => pollAuthSession,
1895
1895
  preflightAuthCheck: () => preflightAuthCheck,
1896
1896
  readTermsAcceptedAt: () => readTermsAcceptedAt,
1897
+ recordScanCapReached: () => recordScanCapReached,
1897
1898
  recordScanNoticeShown: () => recordScanNoticeShown,
1898
1899
  saveCredentials: () => saveCredentials,
1899
1900
  saveCredentialsFromToken: () => saveCredentialsFromToken,
@@ -2283,18 +2284,28 @@ function writeCachedAuthStatus(status) {
2283
2284
  } catch {
2284
2285
  }
2285
2286
  }
2287
+ function recordScanCapReached(scansUsed, maxScans, reason) {
2288
+ writeCachedAuthStatus({
2289
+ authenticated: !!getStoredApiKey(),
2290
+ freeTierCapReached: true,
2291
+ scansUsed,
2292
+ scansLimit: maxScans,
2293
+ capReason: reason,
2294
+ fetchedAt: Date.now()
2295
+ });
2296
+ }
2286
2297
  async function preflightAuthCheck(apiUrl) {
2287
2298
  if (process.env.DG_SIMULATE_FREE_CAP_REACHED === "1") {
2288
2299
  throw new PreflightFreeCapReachedError(5, 5);
2289
2300
  }
2301
+ const apiKey = getStoredApiKey();
2290
2302
  const cached = readCachedAuthStatus();
2291
- if (cached) {
2303
+ if (cached && cached.authenticated === !!apiKey) {
2292
2304
  if (cached.freeTierCapReached) {
2293
2305
  throw new PreflightFreeCapReachedError(cached.scansUsed, cached.scansLimit ?? cached.scansUsed, cached.capReason ?? "monthly_limit");
2294
2306
  }
2295
2307
  return cached;
2296
2308
  }
2297
- const apiKey = getStoredApiKey();
2298
2309
  const headers = {};
2299
2310
  if (apiKey) {
2300
2311
  headers["Authorization"] = `Bearer ${apiKey}`;
@@ -2324,17 +2335,17 @@ async function preflightAuthCheck(apiUrl) {
2324
2335
  } catch {
2325
2336
  }
2326
2337
  if (body.freeTierCapReached) {
2327
- const capReason = body.capReason === "prefix_cap" ? "prefix_cap" : "monthly_limit";
2338
+ const capReason2 = body.capReason === "prefix_cap" ? "prefix_cap" : "monthly_limit";
2328
2339
  const status2 = {
2329
2340
  authenticated: !!apiKey,
2330
2341
  freeTierCapReached: true,
2331
2342
  scansUsed: body.scansUsed ?? 0,
2332
2343
  scansLimit: body.maxScans ?? 0,
2333
- capReason,
2344
+ capReason: capReason2,
2334
2345
  fetchedAt: Date.now()
2335
2346
  };
2336
2347
  writeCachedAuthStatus(status2);
2337
- throw new PreflightFreeCapReachedError(status2.scansUsed, status2.scansLimit ?? 0, capReason);
2348
+ throw new PreflightFreeCapReachedError(status2.scansUsed, status2.scansLimit ?? 0, capReason2);
2338
2349
  }
2339
2350
  }
2340
2351
  if (!resp.ok) {
@@ -2352,18 +2363,20 @@ async function preflightAuthCheck(apiUrl) {
2352
2363
  data = await resp.json();
2353
2364
  } catch {
2354
2365
  }
2366
+ const capReason = data.capReason === "prefix_cap" ? "prefix_cap" : "monthly_limit";
2355
2367
  const status = {
2356
2368
  authenticated: !!apiKey,
2357
2369
  freeTierCapReached: !!data.freeTierCapReached,
2358
2370
  scansUsed: data.scansUsed ?? 0,
2359
2371
  scansLimit: data.scansLimit ?? null,
2372
+ capReason,
2360
2373
  tier: data.tier,
2361
2374
  name: data.name,
2362
2375
  fetchedAt: Date.now()
2363
2376
  };
2364
2377
  writeCachedAuthStatus(status);
2365
2378
  if (status.freeTierCapReached) {
2366
- throw new PreflightFreeCapReachedError(status.scansUsed, status.scansLimit ?? 0);
2379
+ throw new PreflightFreeCapReachedError(status.scansUsed, status.scansLimit ?? 0, capReason);
2367
2380
  }
2368
2381
  return status;
2369
2382
  }
@@ -2555,9 +2568,9 @@ function loadDgrc() {
2555
2568
  `);
2556
2569
  }
2557
2570
  }
2558
- if (cwdPath !== homePath && existsSync2(cwdPath) && process.env.DG_QUIET !== "1") {
2571
+ if (cwdPath !== homePath && existsSync2(cwdPath)) {
2559
2572
  process.stderr.write(
2560
- `dg: note: ./.dgrc.json is ignored (repo-controlled config is no longer honored). Use ~/.dg/.dgrc.json, env vars (DG_MODE, DG_API_URL), or CLI flags.
2573
+ `dg: note: ./.dgrc.json is ignored (repo-controlled config is no longer honored). Use ~/.dg/.dgrc.json or CLI flags.
2561
2574
  `
2562
2575
  );
2563
2576
  }
@@ -2655,7 +2668,7 @@ function parseConfig(argv, strictFlags = true) {
2655
2668
  const apiKey = dgrc.apiKey && typeof dgrc.apiKey === "string" && (dgrc.apiKey.startsWith("dg_live_") || dgrc.apiKey.startsWith("dg_test_")) ? dgrc.apiKey : null;
2656
2669
  const isProtectiveWrapper = command === "npm" || command === "pip";
2657
2670
  const defaultMode = isProtectiveWrapper ? "block" : "warn";
2658
- const modeRaw = values.mode ?? process.env.DG_MODE ?? dgrc.mode ?? defaultMode;
2671
+ const modeRaw = values.mode ?? dgrc.mode ?? defaultMode;
2659
2672
  if (!["block", "warn", "off"].includes(modeRaw)) {
2660
2673
  process.stderr.write(
2661
2674
  `Error: Invalid mode "${modeRaw}". Must be block, warn, or off.
@@ -2683,7 +2696,7 @@ function parseConfig(argv, strictFlags = true) {
2683
2696
  sarif: values.sarif || false,
2684
2697
  scanAll: !values["changed-only"],
2685
2698
  baseLockfile: values["base-lockfile"] ?? null,
2686
- workspace: values.workspace ?? process.env.DG_WORKSPACE ?? null,
2699
+ workspace: values.workspace ?? null,
2687
2700
  outputFile: values.output ?? null,
2688
2701
  command,
2689
2702
  debug,
@@ -2692,7 +2705,6 @@ function parseConfig(argv, strictFlags = true) {
2692
2705
  quiet: (() => {
2693
2706
  if (values["no-quiet"]) return false;
2694
2707
  if (values.quiet) return true;
2695
- if (process.env.DG_QUIET === "1") return true;
2696
2708
  if (process.env.CI === "1" || process.env.CI === "true") return true;
2697
2709
  return false;
2698
2710
  })(),
@@ -2801,8 +2813,7 @@ var init_config = __esm({
2801
2813
  --api-url <url> API base URL (default: https://api.westbayberry.com)
2802
2814
 
2803
2815
  Install-wrapper flags (work on \`npm install\`, \`pip install\`, etc.):
2804
- --dg-force Bypass a block (audit-visible \u2014 record it)
2805
- --dg-force-reason "..." Reason recorded with the override
2816
+ --dg-force Bypass a block (audit-visible)
2806
2817
  --dg-no-scripts Add \`--ignore-scripts\` to the real install
2807
2818
  --strict Strongest protection: implies --dg-no-scripts and
2808
2819
  refuses any partial-coverage scan
@@ -2811,16 +2822,11 @@ var init_config = __esm({
2811
2822
  DG_API_KEY CI auth token (dg_live_* or dg_test_*).
2812
2823
  Used when ~/.dg/config.json is absent.
2813
2824
  File beats env if both are present.
2814
- DG_API_URL API base URL
2815
- DG_MODE Mode (block | warn | off)
2816
- DG_DEBUG=1 Enable debug output
2817
- DG_QUIET=1 Same as passing --quiet
2818
- DG_WORKSPACE Workspace subdirectory to scan
2819
- DG_TELEMETRY=0 Opt out of anonymous crash reports (on by default; DO_NOT_TRACK=1 also opts out)
2820
- DG_FORCE_POSTINSTALL=1 Force postinstall to run even outside a TTY
2821
- (useful for re-running setup manually)
2825
+ DG_TELEMETRY=0 Opt out of anonymous crash reports (on by default;
2826
+ DO_NOT_TRACK=1 also opts out)
2822
2827
  DG_NO_RC_EDIT=1 Postinstall installs shims but does not edit
2823
2828
  shell rc files; you set PATH yourself
2829
+ NO_COLOR=1 Disable colored output
2824
2830
  CI=1 Auto-enables --ci output mode + --quiet
2825
2831
 
2826
2832
  Exit Codes:
@@ -2837,8 +2843,8 @@ var init_config = __esm({
2837
2843
  if the verdict permits. Top-level versions are pinned to the
2838
2844
  exact version we scanned (TOCTOU defense).
2839
2845
  - Warn verdict in a TTY: shows findings and prompts \`Proceed? (Y/n)\`.
2840
- - Block verdict: refuses install, prints the override command.
2841
- Override always requires \`--dg-force-reason\`.
2846
+ - Block verdict: refuses install, prints the override command
2847
+ (re-run with \`--dg-force\` to install anyway).
2842
2848
  - Read-only subcommands (npm view, pip show, pnpm list, etc.) skip
2843
2849
  the wrapper entirely \u2014 fast pass-through to the real binary.
2844
2850
  - \`dg scan\` is read-only and never blocks. It does not consume
@@ -2851,7 +2857,7 @@ var init_config = __esm({
2851
2857
  bun add some-pkg
2852
2858
  uv pip install numpy
2853
2859
  pipx install black
2854
- npm install risky-pkg --dg-force --dg-force-reason="emergency hotfix"
2860
+ npm install risky-pkg --dg-force
2855
2861
  dg scan --json | jq # CI-friendly
2856
2862
  dg status # see what's protected
2857
2863
  `.trimStart();
@@ -3993,7 +3999,6 @@ dg publish-check \u2014 scan a package about to be published
3993
3999
 
3994
4000
  Usage:
3995
4001
  dg publish-check [--ecosystem npm|pypi] [--json] [--dg-force]
3996
- [--dg-force-reason <text>]
3997
4002
 
3998
4003
  What it does:
3999
4004
  Scans the package artifact you're about to publish for bundled secrets,
@@ -4005,7 +4010,6 @@ Flags:
4005
4010
  --ecosystem <npm|pypi> Force ecosystem detection
4006
4011
  --json JSON output to stdout
4007
4012
  --dg-force Bypass block verdict (audited)
4008
- --dg-force-reason <text> Reason string stored with override
4009
4013
 
4010
4014
  Exit codes:
4011
4015
  0 pass No risks detected
@@ -14026,7 +14030,7 @@ var require_react_reconciler_development = __commonJS({
14026
14030
  var HostPortal = 4;
14027
14031
  var HostComponent = 5;
14028
14032
  var HostText = 6;
14029
- var Fragment6 = 7;
14033
+ var Fragment7 = 7;
14030
14034
  var Mode = 8;
14031
14035
  var ContextConsumer = 9;
14032
14036
  var ContextProvider = 10;
@@ -14166,7 +14170,7 @@ var require_react_reconciler_development = __commonJS({
14166
14170
  return "DehydratedFragment";
14167
14171
  case ForwardRef:
14168
14172
  return getWrappedName$1(type, type.render, "ForwardRef");
14169
- case Fragment6:
14173
+ case Fragment7:
14170
14174
  return "Fragment";
14171
14175
  case HostComponent:
14172
14176
  return type;
@@ -17300,7 +17304,7 @@ var require_react_reconciler_development = __commonJS({
17300
17304
  }
17301
17305
  }
17302
17306
  function updateFragment2(returnFiber, current2, fragment, lanes, key) {
17303
- if (current2 === null || current2.tag !== Fragment6) {
17307
+ if (current2 === null || current2.tag !== Fragment7) {
17304
17308
  var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);
17305
17309
  created.return = returnFiber;
17306
17310
  return created;
@@ -17703,7 +17707,7 @@ var require_react_reconciler_development = __commonJS({
17703
17707
  if (child.key === key) {
17704
17708
  var elementType = element.type;
17705
17709
  if (elementType === REACT_FRAGMENT_TYPE) {
17706
- if (child.tag === Fragment6) {
17710
+ if (child.tag === Fragment7) {
17707
17711
  deleteRemainingChildren(returnFiber, child.sibling);
17708
17712
  var existing = useFiber(child, element.props.children);
17709
17713
  existing.return = returnFiber;
@@ -23194,7 +23198,7 @@ var require_react_reconciler_development = __commonJS({
23194
23198
  var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
23195
23199
  return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2);
23196
23200
  }
23197
- case Fragment6:
23201
+ case Fragment7:
23198
23202
  return updateFragment(current2, workInProgress2, renderLanes2);
23199
23203
  case Mode:
23200
23204
  return updateMode(current2, workInProgress2, renderLanes2);
@@ -23631,7 +23635,7 @@ var require_react_reconciler_development = __commonJS({
23631
23635
  case SimpleMemoComponent:
23632
23636
  case FunctionComponent:
23633
23637
  case ForwardRef:
23634
- case Fragment6:
23638
+ case Fragment7:
23635
23639
  case Mode:
23636
23640
  case Profiler:
23637
23641
  case ContextConsumer:
@@ -28399,7 +28403,7 @@ var require_react_reconciler_development = __commonJS({
28399
28403
  return fiber;
28400
28404
  }
28401
28405
  function createFiberFromFragment(elements, mode, lanes, key) {
28402
- var fiber = createFiber(Fragment6, elements, key, mode);
28406
+ var fiber = createFiber(Fragment7, elements, key, mode);
28403
28407
  fiber.lanes = lanes;
28404
28408
  return fiber;
28405
28409
  }
@@ -42574,6 +42578,24 @@ var init_lockfile = __esm({
42574
42578
  });
42575
42579
 
42576
42580
  // src/commands/wrapper-shared.ts
42581
+ import { spawn as spawn2 } from "node:child_process";
42582
+ function spawnTrimmed(bin, args, env3) {
42583
+ return new Promise((resolve3) => {
42584
+ const child = spawn2(bin, args, { stdio: ["inherit", "pipe", "pipe"], shell: false, env: { ...env3, FORCE_COLOR: "1" } });
42585
+ let buf = "";
42586
+ const onData = (c) => {
42587
+ buf += c.toString();
42588
+ };
42589
+ child.stdout?.on("data", onData);
42590
+ child.stderr?.on("data", onData);
42591
+ child.on("error", () => resolve3(1));
42592
+ child.on("close", (code) => {
42593
+ const lines = buf.split("\n").filter((l) => l.replace(ANSI_RE, "").trim() !== "");
42594
+ if (lines.length) process.stdout.write(lines.join("\n") + "\n");
42595
+ resolve3(code ?? 1);
42596
+ });
42597
+ });
42598
+ }
42577
42599
  function injectIgnoreScripts(args, opts) {
42578
42600
  if (!opts.isNpmFamily) return args;
42579
42601
  if (!(opts.strict || opts.dgNoScripts)) return args;
@@ -42582,7 +42604,6 @@ function injectIgnoreScripts(args, opts) {
42582
42604
  }
42583
42605
  function stripDgFlags(args) {
42584
42606
  let dgForce = false;
42585
- let dgForceReason;
42586
42607
  let dgNoScripts = false;
42587
42608
  const filtered = [];
42588
42609
  for (let i = 0; i < args.length; i++) {
@@ -42591,15 +42612,6 @@ function stripDgFlags(args) {
42591
42612
  dgForce = true;
42592
42613
  continue;
42593
42614
  }
42594
- if (arg === "--dg-force-reason") {
42595
- dgForceReason = (args[i + 1] ?? "").slice(0, 500);
42596
- i++;
42597
- continue;
42598
- }
42599
- if (arg.startsWith("--dg-force-reason=")) {
42600
- dgForceReason = arg.slice("--dg-force-reason=".length).slice(0, 500);
42601
- continue;
42602
- }
42603
42615
  if (arg === "--dg-no-scripts") {
42604
42616
  dgNoScripts = true;
42605
42617
  continue;
@@ -42619,12 +42631,13 @@ function stripDgFlags(args) {
42619
42631
  if (consumed) continue;
42620
42632
  filtered.push(arg);
42621
42633
  }
42622
- return { filtered, dgForce, dgForceReason, dgNoScripts };
42634
+ return { filtered, dgForce, dgNoScripts };
42623
42635
  }
42624
- var DG_VALUE_FLAGS, DG_BOOLEAN_FLAGS;
42636
+ var ANSI_RE, DG_VALUE_FLAGS, DG_BOOLEAN_FLAGS;
42625
42637
  var init_wrapper_shared = __esm({
42626
42638
  "src/commands/wrapper-shared.ts"() {
42627
42639
  "use strict";
42640
+ ANSI_RE = /\x1b\[[0-9;]*m/g;
42628
42641
  DG_VALUE_FLAGS = /* @__PURE__ */ new Set([
42629
42642
  "--mode",
42630
42643
  "--api-url",
@@ -42633,6 +42646,8 @@ var init_wrapper_shared = __esm({
42633
42646
  "--workspace",
42634
42647
  "--output",
42635
42648
  "-o",
42649
+ // Removed flag: still consumed (with its value) so a legacy invocation is
42650
+ // silently stripped rather than leaking to the real installer as a package.
42636
42651
  "--dg-force-reason"
42637
42652
  ]);
42638
42653
  DG_BOOLEAN_FLAGS = /* @__PURE__ */ new Set([
@@ -42650,7 +42665,7 @@ var init_wrapper_shared = __esm({
42650
42665
  });
42651
42666
 
42652
42667
  // src/commands/npm-wrapper.ts
42653
- import { spawn as spawn2 } from "node:child_process";
42668
+ import { spawn as spawn3 } from "node:child_process";
42654
42669
  import { readFileSync as readFileSync9, existsSync as existsSync12, mkdtempSync, writeFileSync as writeFileSync8, rmSync } from "node:fs";
42655
42670
  import { join as join7 } from "node:path";
42656
42671
  import { tmpdir } from "node:os";
@@ -42665,7 +42680,7 @@ function shimSentinelEnv() {
42665
42680
  return childInstallEnv();
42666
42681
  }
42667
42682
  function parseNpmArgs(args) {
42668
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
42683
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
42669
42684
  const command = filtered[0] ?? "";
42670
42685
  const shouldScan = INSTALL_COMMANDS.has(command);
42671
42686
  const packages = [];
@@ -42686,7 +42701,6 @@ function parseNpmArgs(args) {
42686
42701
  packages,
42687
42702
  rawArgs: filtered,
42688
42703
  dgForce,
42689
- dgForceReason,
42690
42704
  dgNoScripts,
42691
42705
  shouldScan
42692
42706
  };
@@ -42742,7 +42756,7 @@ async function resolveVersion(spec) {
42742
42756
  return null;
42743
42757
  }
42744
42758
  return new Promise((resolve3) => {
42745
- const child = spawn2(realNpmBinary(), ["view", spec, "version", "--json"], {
42759
+ const child = spawn3(realNpmBinary(), ["view", spec, "version", "--json"], {
42746
42760
  stdio: ["pipe", "pipe", "pipe"],
42747
42761
  env: shimSentinelEnv()
42748
42762
  });
@@ -42818,9 +42832,12 @@ async function resolvePackages(specs) {
42818
42832
  return { resolved, failed };
42819
42833
  }
42820
42834
  function runNpm(args, opts) {
42835
+ if (opts?.trim) {
42836
+ return spawnTrimmed(realNpmBinary(), args, shimSentinelEnv());
42837
+ }
42821
42838
  return new Promise((resolve3) => {
42822
42839
  const stdio = opts?.stdoutToStderr ? ["inherit", "pipe", "inherit"] : ["inherit", "inherit", "inherit"];
42823
- const child = spawn2(realNpmBinary(), args, { stdio, shell: false, env: shimSentinelEnv() });
42840
+ const child = spawn3(realNpmBinary(), args, { stdio, shell: false, env: shimSentinelEnv() });
42824
42841
  if (opts?.stdoutToStderr && child.stdout) {
42825
42842
  child.stdout.on("data", (chunk) => {
42826
42843
  process.stderr.write(chunk);
@@ -42840,7 +42857,7 @@ async function resolveTreeNpm(specs) {
42840
42857
  try {
42841
42858
  writeFileSync8(join7(dir, "package.json"), '{"name":"_dg_resolve","version":"1.0.0","private":true}');
42842
42859
  const stdout = await new Promise((resolve3) => {
42843
- const child = spawn2(
42860
+ const child = spawn3(
42844
42861
  realNpmBinary(),
42845
42862
  [
42846
42863
  "install",
@@ -43000,10 +43017,10 @@ var init_npm_wrapper = __esm({
43000
43017
  });
43001
43018
 
43002
43019
  // src/commands/pip-wrapper.ts
43003
- import { spawn as spawn3 } from "node:child_process";
43020
+ import { spawn as spawn4 } from "node:child_process";
43004
43021
  import { existsSync as existsSync13 } from "node:fs";
43005
43022
  function parsePipArgs(args) {
43006
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
43023
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
43007
43024
  const command = filtered[0] ?? "";
43008
43025
  const shouldScan = INSTALL_COMMANDS2.has(command);
43009
43026
  const packages = [];
@@ -43030,7 +43047,6 @@ function parsePipArgs(args) {
43030
43047
  packages,
43031
43048
  rawArgs: filtered,
43032
43049
  dgForce,
43033
- dgForceReason,
43034
43050
  dgNoScripts,
43035
43051
  shouldScan,
43036
43052
  requirementsFile
@@ -43202,7 +43218,7 @@ async function detectPipBinary() {
43202
43218
  try {
43203
43219
  const parts = cmd.split(" ");
43204
43220
  const code = await new Promise((resolve3) => {
43205
- const child = spawn3(parts[0], [...parts.slice(1), "--version"], {
43221
+ const child = spawn4(parts[0], [...parts.slice(1), "--version"], {
43206
43222
  stdio: ["pipe", "pipe", "pipe"],
43207
43223
  timeout: 5e3,
43208
43224
  env: shimSentinelEnv2()
@@ -43221,9 +43237,12 @@ async function detectPipBinary() {
43221
43237
  async function runPip(args, opts) {
43222
43238
  const pipCmd = await detectPipBinary();
43223
43239
  const parts = pipCmd.split(" ");
43240
+ if (opts?.trim) {
43241
+ return spawnTrimmed(parts[0], [...parts.slice(1), ...args], shimSentinelEnv2());
43242
+ }
43224
43243
  return new Promise((resolve3) => {
43225
43244
  const stdio = opts?.stdoutToStderr ? ["inherit", "pipe", "inherit"] : ["inherit", "inherit", "inherit"];
43226
- const child = spawn3(parts[0], [...parts.slice(1), ...args], { stdio, shell: false, env: shimSentinelEnv2() });
43245
+ const child = spawn4(parts[0], [...parts.slice(1), ...args], { stdio, shell: false, env: shimSentinelEnv2() });
43227
43246
  if (opts?.stdoutToStderr && child.stdout) {
43228
43247
  child.stdout.on("data", (chunk) => {
43229
43248
  process.stderr.write(chunk);
@@ -43238,7 +43257,7 @@ async function pipVersion() {
43238
43257
  const pipCmd = await detectPipBinary();
43239
43258
  const parts = pipCmd.split(" ");
43240
43259
  return await new Promise((resolve3) => {
43241
- const child = spawn3(parts[0], [...parts.slice(1), "--version"], {
43260
+ const child = spawn4(parts[0], [...parts.slice(1), "--version"], {
43242
43261
  stdio: ["pipe", "pipe", "pipe"],
43243
43262
  timeout: 5e3,
43244
43263
  env: shimSentinelEnv2()
@@ -43296,7 +43315,7 @@ async function resolveTreePip(specs) {
43296
43315
  const pipCmd = await detectPipBinary();
43297
43316
  const parts = pipCmd.split(" ");
43298
43317
  const runDryRun = (extraFlags) => new Promise((resolve3) => {
43299
- const child = spawn3(
43318
+ const child = spawn4(
43300
43319
  parts[0],
43301
43320
  [
43302
43321
  ...parts.slice(1),
@@ -43388,6 +43407,153 @@ var init_pip_wrapper = __esm({
43388
43407
  }
43389
43408
  });
43390
43409
 
43410
+ // src/wrapper/route.ts
43411
+ function routeVerdict(input) {
43412
+ const { verdict, mode, strict, dgForce } = input;
43413
+ const refuseHard = mode === "block" || strict;
43414
+ const refuseWarn = strict;
43415
+ const D = (outcome, refuseExitCode, extra) => ({
43416
+ verdict,
43417
+ outcome,
43418
+ refuseExitCode,
43419
+ bypassed: false,
43420
+ ...extra
43421
+ });
43422
+ if (verdict === "free_cap") return D("refuse", 1);
43423
+ if (verdict === "pass") return D("install", 0);
43424
+ if (dgForce && (verdict === "warn" || verdict === "block")) {
43425
+ return D("install", 0, { audit: "override", bypassed: true });
43426
+ }
43427
+ switch (verdict) {
43428
+ case "warn":
43429
+ if (mode === "off") return D("install", 0);
43430
+ if (refuseWarn) return D("refuse", 1);
43431
+ return D("prompt", 1);
43432
+ // warn/block mode → prompt; decline → 1
43433
+ case "block":
43434
+ if (mode === "off") return D("install", 0);
43435
+ return D("refuse", 2, { audit: "block" });
43436
+ case "analysis_incomplete":
43437
+ if (dgForce) return D("install", 0, { bypassed: true });
43438
+ if (refuseHard) return D("refuse", 4);
43439
+ return D("install", 0);
43440
+ // off/warn → install with a "could not verify" notice
43441
+ case "scan_failed":
43442
+ case "tree_failed":
43443
+ if (dgForce) return D("install", 0, { bypassed: true });
43444
+ if (refuseHard) return D("refuse", 2);
43445
+ return D("install", 0);
43446
+ // best-effort under off/warn
43447
+ case "resolve_failed":
43448
+ if (dgForce) return D("passthrough", 0, { bypassed: true });
43449
+ if (refuseHard) return D("refuse", 2);
43450
+ return D("passthrough", 0);
43451
+ // nothing resolved to scan → hand off to the installer
43452
+ default: {
43453
+ const _never = verdict;
43454
+ void _never;
43455
+ return D(refuseHard ? "refuse" : "install", refuseHard ? 4 : 0);
43456
+ }
43457
+ }
43458
+ }
43459
+ var init_route = __esm({
43460
+ "src/wrapper/route.ts"() {
43461
+ "use strict";
43462
+ }
43463
+ });
43464
+
43465
+ // src/wrapper/run.ts
43466
+ function verdictFromResult(result, gates = {}) {
43467
+ if (gates.scanFailed) return "scan_failed";
43468
+ if (gates.treeFailed) return "tree_failed";
43469
+ if (gates.resolveFailed) return "resolve_failed";
43470
+ const action = result?.action;
43471
+ if (action === "pass" || action === "warn" || action === "block") return action;
43472
+ return "analysis_incomplete";
43473
+ }
43474
+ function scanVerdictOf(decision) {
43475
+ if (decision.bypassed && (decision.verdict === "warn" || decision.verdict === "block")) {
43476
+ return "override";
43477
+ }
43478
+ switch (decision.verdict) {
43479
+ case "pass":
43480
+ return "pass";
43481
+ case "warn":
43482
+ return "warn";
43483
+ case "block":
43484
+ return "block";
43485
+ case "analysis_incomplete":
43486
+ return "analysis_incomplete";
43487
+ case "scan_failed":
43488
+ case "tree_failed":
43489
+ case "resolve_failed":
43490
+ return "scan_failed";
43491
+ default:
43492
+ return "skipped";
43493
+ }
43494
+ }
43495
+ async function executeDecision(decision, ctx, presenter) {
43496
+ await presenter.announce(decision, ctx);
43497
+ if (decision.audit) {
43498
+ await presenter.audit(decision.audit, ctx);
43499
+ }
43500
+ const scanVerdict = scanVerdictOf(decision);
43501
+ const base = (installRan, installExitCode) => ({
43502
+ scanVerdict,
43503
+ installRan,
43504
+ installExitCode,
43505
+ error: ctx.error,
43506
+ suppressedByAllowlist: ctx.suppressedCount > 0 ? ctx.suppressedCount : void 0
43507
+ });
43508
+ switch (decision.outcome) {
43509
+ case "refuse":
43510
+ presenter.emit(base(false, null));
43511
+ return decision.refuseExitCode;
43512
+ case "install": {
43513
+ const code = await presenter.runInstall(ctx.installArgs);
43514
+ presenter.emit(base(true, code));
43515
+ return code;
43516
+ }
43517
+ case "passthrough": {
43518
+ const code = await presenter.runInstall(ctx.passthroughArgs);
43519
+ presenter.emit(base(true, code));
43520
+ return code;
43521
+ }
43522
+ case "prompt": {
43523
+ const proceed = await presenter.confirmProceed(ctx);
43524
+ if (!proceed) {
43525
+ presenter.emit(base(false, null));
43526
+ return decision.refuseExitCode;
43527
+ }
43528
+ if (presenter.onPromptAccepted) await presenter.onPromptAccepted(ctx);
43529
+ const code = await presenter.runInstall(ctx.installArgs);
43530
+ presenter.emit(base(true, code));
43531
+ return code;
43532
+ }
43533
+ default: {
43534
+ const _never = decision.outcome;
43535
+ void _never;
43536
+ return 1;
43537
+ }
43538
+ }
43539
+ }
43540
+ var init_run = __esm({
43541
+ "src/wrapper/run.ts"() {
43542
+ "use strict";
43543
+ }
43544
+ });
43545
+
43546
+ // src/wrapper/json.ts
43547
+ function emitWrapperJson(config, result) {
43548
+ if (!config.json) return;
43549
+ process.stdout.write(JSON.stringify(result, null, 2) + "\n");
43550
+ }
43551
+ var init_json = __esm({
43552
+ "src/wrapper/json.ts"() {
43553
+ "use strict";
43554
+ }
43555
+ });
43556
+
43391
43557
  // src/security/artifact_integrity.ts
43392
43558
  function normalize(h, algo) {
43393
43559
  if (!h) return void 0;
@@ -44795,7 +44961,6 @@ async function dispatchPublishCheckAudit(opts) {
44795
44961
  score: opts.score,
44796
44962
  action: opts.decisionAction,
44797
44963
  bypassed: opts.bypassed,
44798
- bypass_reason: opts.bypassReason,
44799
44964
  event_kind: "publish_check"
44800
44965
  },
44801
44966
  { apiUrl: opts.apiUrl }
@@ -44817,7 +44982,6 @@ function recordBypassLocally(record) {
44817
44982
  ecosystem: record.ecosystem,
44818
44983
  verdict: record.verdict,
44819
44984
  trigger: record.trigger,
44820
- reason: record.reason,
44821
44985
  packages: record.packages
44822
44986
  };
44823
44987
  appendFileSync3(path, JSON.stringify(full) + "\n", { mode: 384 });
@@ -44840,7 +45004,6 @@ async function dispatchInstallAudit(opts) {
44840
45004
  score: p.score,
44841
45005
  action: opts.decisionAction,
44842
45006
  bypassed: opts.bypassed,
44843
- bypass_reason: opts.bypassReason,
44844
45007
  project_hash: opts.projectHash
44845
45008
  },
44846
45009
  { apiUrl: opts.apiUrl }
@@ -44879,10 +45042,6 @@ function note(config, text) {
44879
45042
  if (config.quiet) return;
44880
45043
  process.stderr.write(text);
44881
45044
  }
44882
- function emitWrapperJson(config, result) {
44883
- if (!config.json) return;
44884
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
44885
- }
44886
45045
  function wrapperPackagesFromResult(result, topLevelNames) {
44887
45046
  return result.packages.map((p) => ({
44888
45047
  name: p.name,
@@ -45367,11 +45526,7 @@ async function runStatic(config) {
45367
45526
  printTrialBanner(result, config);
45368
45527
  process.exit(scanExitCode(result.action, config.mode));
45369
45528
  }
45370
- function mergeProjectConfig(config, _argv) {
45371
- return config;
45372
- }
45373
45529
  async function runStaticNpm(npmArgs, config) {
45374
- config = mergeProjectConfig(config, process.argv.slice(2));
45375
45530
  const parsed = parseNpmArgs(npmArgs);
45376
45531
  if (!parsed.shouldScan) {
45377
45532
  const code = await runNpm(parsed.rawArgs);
@@ -45623,156 +45778,106 @@ async function scanAndInstallStatic(resolved, parsed, config) {
45623
45778
  );
45624
45779
  }
45625
45780
  }
45626
- if (result.action === "pass") {
45627
- const topLevel = resolved.map((p) => `${p.name} ${p.version}`);
45628
- const passLine = topLevel.length === 1 ? ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel[0]} is safe` : ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel.length} packages safe`;
45629
- const installLine = topLevel.length === 1 ? ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel[0]}` : ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel.join(", ")}`;
45630
- process.stderr.write(`${passLine}
45781
+ const npmInstallArgs = buildInstallArgs(parsed, topLevelSpecs, tree.packages, config);
45782
+ const npmTopLevelNames = new Set(resolved.map((p) => p.name));
45783
+ const npmDecision = routeVerdict({
45784
+ verdict: verdictFromResult(result),
45785
+ mode: config.mode,
45786
+ strict: config.strict,
45787
+ dgForce: parsed.dgForce
45788
+ });
45789
+ const npmPresenter = {
45790
+ async announce(d) {
45791
+ if (d.verdict === "pass") {
45792
+ const topLevel2 = resolved.map((p) => `${p.name} ${p.version}`);
45793
+ const passLine = topLevel2.length === 1 ? ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel2[0]} is safe` : ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel2.length} packages safe`;
45794
+ const installLine = topLevel2.length === 1 ? ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel2[0]}` : ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel2.join(", ")}`;
45795
+ process.stderr.write(`${passLine}
45631
45796
  ${installLine}
45632
45797
  `);
45633
- if (parsed.dgNoScripts || config.strict) {
45634
- const why = config.strict ? "--strict" : "--dg-no-scripts";
45635
- process.stderr.write(import_chalk5.default.dim(` ${why}: lifecycle scripts will be suppressed during install.
45798
+ if (parsed.dgNoScripts || config.strict) {
45799
+ const why = config.strict ? "--strict" : "--dg-no-scripts";
45800
+ process.stderr.write(import_chalk5.default.dim(` ${why}: lifecycle scripts will be suppressed during install.
45636
45801
  `));
45637
- }
45638
- printTrialBanner(result, config);
45639
- process.stderr.write("\n");
45640
- const code = await runNpm(buildInstallArgs(parsed, topLevelSpecs, tree.packages, config), { stdoutToStderr: !!config.json });
45641
- emitWrapperJson(config, {
45642
- ecosystem: "npm",
45643
- packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45644
- scanVerdict: "pass",
45645
- installRan: true,
45646
- installExitCode: code
45647
- });
45648
- process.exit(code);
45649
- }
45650
- const output = renderResultStatic(result, config);
45651
- (config.json ? process.stderr : process.stdout).write(output + "\n");
45652
- printTrialBanner(result, config);
45653
- if (result.action === "warn") {
45654
- const { promptYesNo: promptYesNo2 } = await Promise.resolve().then(() => (init_prompt(), prompt_exports));
45655
- const topLevel = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
45656
- process.stderr.write(
45657
- ` ${import_chalk5.default.yellow("\u26A0")} ${import_chalk5.default.bold("DG flagged")} ${topLevel}.
45802
+ }
45803
+ printTrialBanner(result, config);
45804
+ process.stderr.write("\n");
45805
+ return;
45806
+ }
45807
+ const output = renderResultStatic(result, config);
45808
+ (config.json ? process.stderr : process.stdout).write(output + "\n");
45809
+ printTrialBanner(result, config);
45810
+ const topLevel = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
45811
+ if (d.verdict === "warn") {
45812
+ process.stderr.write(` ${import_chalk5.default.yellow("\u26A0")} ${import_chalk5.default.bold("DG flagged")} ${topLevel}.
45813
+ `);
45814
+ } else if (d.verdict === "block") {
45815
+ if (d.outcome === "install") {
45816
+ process.stderr.write(import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n")));
45817
+ } else {
45818
+ const blockedSpecArg = topLevelSpecs.length > 0 ? topLevelSpecs.join(" ") : topLevel.split(", ").map((s) => s.replace(/ /g, "@")).join(" ");
45819
+ process.stderr.write(
45820
+ ` ${import_chalk5.default.red("\u2717")} ${import_chalk5.default.bold("DG blocked")} ${topLevel}.
45821
+ ${import_chalk5.default.dim(`install anyway: npm install ${blockedSpecArg} --dg-force`)}
45822
+
45658
45823
  `
45659
- );
45660
- const proceed = await promptYesNo2({
45661
- defaultAnswer: "y",
45662
- message: ` Proceed?`
45663
- });
45664
- if (!proceed) {
45665
- process.stderr.write(import_chalk5.default.dim(" Install cancelled by user.\n\n"));
45666
- emitWrapperJson(config, {
45667
- ecosystem: "npm",
45668
- packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45669
- scanVerdict: "warn",
45670
- installRan: false,
45671
- installExitCode: null
45672
- });
45673
- process.exit(1);
45674
- }
45675
- const code = await runNpm(buildInstallArgs(parsed, topLevelSpecs, tree.packages, config), { stdoutToStderr: !!config.json });
45676
- emitWrapperJson(config, {
45677
- ecosystem: "npm",
45678
- packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45679
- scanVerdict: "warn",
45680
- installRan: true,
45681
- installExitCode: code
45682
- });
45683
- process.exit(code);
45684
- }
45685
- if (result.action === "block") {
45686
- if (parsed.dgForce) {
45687
- const { dispatchInstallAudit: dispatchInstallAudit3 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
45688
- await dispatchInstallAudit3({
45824
+ );
45825
+ }
45826
+ } else if (d.verdict === "analysis_incomplete") {
45827
+ if (d.outcome === "refuse") {
45828
+ const specArg = topLevelSpecs.length > 0 ? topLevelSpecs.join(" ") : resolved.map((p) => `${p.name}@${p.version}`).join(" ");
45829
+ process.stderr.write(
45830
+ ` ${import_chalk5.default.cyan("?")} ${import_chalk5.default.bold("DG couldn't verify")} ${topLevel} \u2014 unverified, not safe.
45831
+ ${import_chalk5.default.dim(`install anyway: npm install ${specArg} --dg-force`)}
45832
+
45833
+ `
45834
+ );
45835
+ } else {
45836
+ process.stderr.write(import_chalk5.default.dim(` DG could not fully verify ${topLevel}; proceeding (mode is not block).
45837
+
45838
+ `));
45839
+ }
45840
+ }
45841
+ },
45842
+ async confirmProceed() {
45843
+ const { promptYesNo: promptYesNo2 } = await Promise.resolve().then(() => (init_prompt(), prompt_exports));
45844
+ const proceed = await promptYesNo2({ defaultAnswer: "y", message: ` Proceed?` });
45845
+ if (!proceed) process.stderr.write(import_chalk5.default.dim(" Install cancelled by user.\n\n"));
45846
+ return proceed;
45847
+ },
45848
+ runInstall: (args) => runNpm(args, { stdoutToStderr: !!config.json }),
45849
+ async audit(kind) {
45850
+ const { dispatchInstallAudit: dispatchInstallAudit2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
45851
+ await dispatchInstallAudit2({
45689
45852
  ecosystem: "npm",
45690
45853
  packages: result.packages,
45691
- decisionAction: "override",
45692
- bypassed: true,
45693
- bypassReason: parsed.dgForceReason
45694
- });
45695
- process.stderr.write(
45696
- import_chalk5.default.yellow(
45697
- import_chalk5.default.bold(
45698
- " --dg-force: Bypassing block. Install at your own risk.\n\n"
45699
- )
45700
- )
45701
- );
45702
- const code = await runNpm(buildInstallArgs(parsed, topLevelSpecs, tree.packages, config), { stdoutToStderr: !!config.json });
45703
- emitWrapperJson(config, {
45704
- ecosystem: "npm",
45705
- packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45706
- scanVerdict: "override",
45707
- installRan: true,
45708
- installExitCode: code
45854
+ decisionAction: kind,
45855
+ bypassed: kind === "override"
45709
45856
  });
45710
- process.exit(code);
45711
- }
45712
- const { dispatchInstallAudit: dispatchInstallAudit2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
45713
- await dispatchInstallAudit2({
45714
- ecosystem: "npm",
45715
- packages: result.packages,
45716
- decisionAction: "block",
45717
- bypassed: false
45718
- });
45719
- const topLevelBlocked = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
45720
- const blockedSpecArg = topLevelSpecs.length > 0 ? topLevelSpecs.join(" ") : topLevelBlocked.split(", ").map((s) => s.replace(/ /g, "@")).join(" ");
45721
- process.stderr.write(
45722
- ` ${import_chalk5.default.red("\u2717")} ${import_chalk5.default.bold("DG blocked")} ${topLevelBlocked}.
45723
- Real install was NOT run. To override:
45724
- ` + import_chalk5.default.dim(` npm install ${blockedSpecArg} --dg-force --dg-force-reason="<reason>"
45725
-
45726
- `)
45727
- );
45728
- emitWrapperJson(config, {
45729
- ecosystem: "npm",
45730
- packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45731
- scanVerdict: "block",
45732
- installRan: false,
45733
- installExitCode: null
45734
- });
45735
- process.exit(2);
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
- );
45857
+ },
45858
+ emit(record) {
45749
45859
  emitWrapperJson(config, {
45750
45860
  ecosystem: "npm",
45751
- packages: wrapperPackagesFromResult(result, new Set(resolved.map((p) => p.name))),
45752
- scanVerdict: "analysis_incomplete",
45753
- installRan: false,
45754
- installExitCode: null
45861
+ packages: wrapperPackagesFromResult(result, npmTopLevelNames),
45862
+ scanVerdict: record.scanVerdict,
45863
+ installRan: record.installRan,
45864
+ installExitCode: record.installExitCode,
45865
+ error: record.error
45755
45866
  });
45756
- process.exit(4);
45757
45867
  }
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
- }
45868
+ };
45869
+ const npmCtx = {
45870
+ ecosystem: "npm",
45871
+ apiKind: "npm",
45872
+ installArgs: npmInstallArgs,
45873
+ passthroughArgs: parsed.rawArgs,
45874
+ result,
45875
+ resolved,
45876
+ suppressedCount: 0
45877
+ };
45878
+ process.exit(await executeDecision(npmDecision, npmCtx, npmPresenter));
45773
45879
  }
45774
45880
  async function runStaticPip(pipArgs, config) {
45775
- config = mergeProjectConfig(config, process.argv.slice(2));
45776
45881
  const parsed = parsePipArgs(pipArgs);
45777
45882
  if (!parsed.shouldScan) {
45778
45883
  const code = await runPip(parsed.rawArgs, { stdoutToStderr: !!config.json });
@@ -45933,141 +46038,97 @@ async function runStaticPip(pipArgs, config) {
45933
46038
  }
45934
46039
  }
45935
46040
  const pipTopLevelNames = new Set(resolved.map((p) => p.name));
45936
- if (result.action === "pass") {
45937
- const topLevel = resolved.map((p) => `${p.name} ${p.version}`);
45938
- const passLine = topLevel.length === 1 ? ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel[0]} is safe` : ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel.length} packages safe`;
45939
- const installLine = topLevel.length === 1 ? ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel[0]}` : ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel.join(", ")}`;
45940
- process.stderr.write(`${passLine}
46041
+ const pipDecision = routeVerdict({
46042
+ verdict: verdictFromResult(result),
46043
+ mode: config.mode,
46044
+ strict: config.strict,
46045
+ dgForce: parsed.dgForce
46046
+ });
46047
+ const pipPresenter = {
46048
+ async announce(d) {
46049
+ if (d.verdict === "pass") {
46050
+ const topLevel2 = resolved.map((p) => `${p.name} ${p.version}`);
46051
+ const passLine = topLevel2.length === 1 ? ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel2[0]} is safe` : ` ${import_chalk5.default.green("\u2713")} ${import_chalk5.default.bold("DG verified:")} ${topLevel2.length} packages safe`;
46052
+ const installLine = topLevel2.length === 1 ? ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel2[0]}` : ` ${import_chalk5.default.green("\u2713")} Installing ${topLevel2.join(", ")}`;
46053
+ process.stderr.write(`${passLine}
45941
46054
  ${installLine}
45942
46055
  `);
45943
- printTrialBanner(result, config);
45944
- process.stderr.write("\n");
45945
- const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45946
- emitWrapperJson(config, {
45947
- ecosystem: "pypi",
45948
- packages: wrapperPackagesFromResult(result, pipTopLevelNames),
45949
- scanVerdict: "pass",
45950
- installRan: true,
45951
- installExitCode: code
45952
- });
45953
- process.exit(code);
45954
- }
45955
- const output = renderResultStatic(result, config);
45956
- (config.json ? process.stderr : process.stdout).write(output + "\n");
45957
- printTrialBanner(result, config);
45958
- if (result.action === "warn") {
45959
- const { promptYesNo: promptYesNo2 } = await Promise.resolve().then(() => (init_prompt(), prompt_exports));
45960
- const topLevel = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
45961
- process.stderr.write(
45962
- ` ${import_chalk5.default.yellow("\u26A0")} ${import_chalk5.default.bold("DG flagged")} ${topLevel}.
46056
+ printTrialBanner(result, config);
46057
+ process.stderr.write("\n");
46058
+ return;
46059
+ }
46060
+ const output = renderResultStatic(result, config);
46061
+ (config.json ? process.stderr : process.stdout).write(output + "\n");
46062
+ printTrialBanner(result, config);
46063
+ const topLevel = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
46064
+ if (d.verdict === "warn") {
46065
+ process.stderr.write(` ${import_chalk5.default.yellow("\u26A0")} ${import_chalk5.default.bold("DG flagged")} ${topLevel}.
46066
+ `);
46067
+ } else if (d.verdict === "block") {
46068
+ if (d.outcome === "install") {
46069
+ process.stderr.write(import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n")));
46070
+ } else {
46071
+ const pipBlockedSpecArg = resolved.map((p) => `${p.name}==${p.version}`).join(" ");
46072
+ process.stderr.write(
46073
+ ` ${import_chalk5.default.red("\u2717")} ${import_chalk5.default.bold("DG blocked")} ${topLevel}.
46074
+ ${import_chalk5.default.dim(`install anyway: pip install ${pipBlockedSpecArg} --dg-force`)}
46075
+
45963
46076
  `
45964
- );
45965
- const proceed = await promptYesNo2({ defaultAnswer: "y", message: " Proceed?" });
45966
- if (!proceed) {
45967
- process.stderr.write(import_chalk5.default.dim(" Install cancelled by user.\n\n"));
45968
- emitWrapperJson(config, {
45969
- ecosystem: "pypi",
45970
- packages: wrapperPackagesFromResult(result, pipTopLevelNames),
45971
- scanVerdict: "warn",
45972
- installRan: false,
45973
- installExitCode: null
45974
- });
45975
- process.exit(1);
45976
- }
45977
- const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
45978
- emitWrapperJson(config, {
45979
- ecosystem: "pypi",
45980
- packages: wrapperPackagesFromResult(result, pipTopLevelNames),
45981
- scanVerdict: "warn",
45982
- installRan: true,
45983
- installExitCode: code
45984
- });
45985
- process.exit(code);
45986
- }
45987
- if (result.action === "block") {
45988
- if (parsed.dgForce) {
45989
- const { dispatchInstallAudit: dispatchInstallAudit3 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
45990
- await dispatchInstallAudit3({
46077
+ );
46078
+ }
46079
+ } else if (d.verdict === "analysis_incomplete") {
46080
+ if (d.outcome === "refuse") {
46081
+ const pipSpecArg = resolved.map((p) => `${p.name}==${p.version}`).join(" ");
46082
+ process.stderr.write(
46083
+ ` ${import_chalk5.default.cyan("?")} ${import_chalk5.default.bold("DG couldn't verify")} ${topLevel} \u2014 unverified, not safe.
46084
+ ${import_chalk5.default.dim(`install anyway: pip install ${pipSpecArg} --dg-force`)}
46085
+
46086
+ `
46087
+ );
46088
+ } else {
46089
+ process.stderr.write(import_chalk5.default.dim(` DG could not fully verify ${topLevel}; proceeding (mode is not block).
46090
+
46091
+ `));
46092
+ }
46093
+ }
46094
+ },
46095
+ async confirmProceed() {
46096
+ const { promptYesNo: promptYesNo2 } = await Promise.resolve().then(() => (init_prompt(), prompt_exports));
46097
+ const proceed = await promptYesNo2({ defaultAnswer: "y", message: " Proceed?" });
46098
+ if (!proceed) process.stderr.write(import_chalk5.default.dim(" Install cancelled by user.\n\n"));
46099
+ return proceed;
46100
+ },
46101
+ runInstall: (args) => runPip(args, { stdoutToStderr: !!config.json }),
46102
+ async audit(kind) {
46103
+ const { dispatchInstallAudit: dispatchInstallAudit2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
46104
+ await dispatchInstallAudit2({
45991
46105
  ecosystem: "pypi",
45992
46106
  packages: result.packages,
45993
- decisionAction: "override",
45994
- bypassed: true,
45995
- bypassReason: parsed.dgForceReason
46107
+ decisionAction: kind,
46108
+ bypassed: kind === "override"
45996
46109
  });
45997
- process.stderr.write(
45998
- import_chalk5.default.yellow(import_chalk5.default.bold(" --dg-force: Bypassing block. Install at your own risk.\n\n"))
45999
- );
46000
- const code = await runPip(pipInstallArgs, { stdoutToStderr: !!config.json });
46001
- emitWrapperJson(config, {
46002
- ecosystem: "pypi",
46003
- packages: wrapperPackagesFromResult(result, pipTopLevelNames),
46004
- scanVerdict: "override",
46005
- installRan: true,
46006
- installExitCode: code
46007
- });
46008
- process.exit(code);
46009
- }
46010
- const { dispatchInstallAudit: dispatchInstallAudit2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
46011
- await dispatchInstallAudit2({
46012
- ecosystem: "pypi",
46013
- packages: result.packages,
46014
- decisionAction: "block",
46015
- bypassed: false
46016
- });
46017
- const pipTopLevelBlocked = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
46018
- const pipBlockedSpecArg = resolved.map((p) => `${p.name}==${p.version}`).join(" ");
46019
- process.stderr.write(
46020
- ` ${import_chalk5.default.red("\u2717")} ${import_chalk5.default.bold("DG blocked")} ${pipTopLevelBlocked}.
46021
- Real install was NOT run. To override:
46022
- ` + import_chalk5.default.dim(` pip install ${pipBlockedSpecArg} --dg-force --dg-force-reason="<reason>"
46023
-
46024
- `)
46025
- );
46026
- emitWrapperJson(config, {
46027
- ecosystem: "pypi",
46028
- packages: wrapperPackagesFromResult(result, pipTopLevelNames),
46029
- scanVerdict: "block",
46030
- installRan: false,
46031
- installExitCode: null
46032
- });
46033
- process.exit(2);
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
- );
46110
+ },
46111
+ emit(record) {
46047
46112
  emitWrapperJson(config, {
46048
46113
  ecosystem: "pypi",
46049
46114
  packages: wrapperPackagesFromResult(result, pipTopLevelNames),
46050
- scanVerdict: "analysis_incomplete",
46051
- installRan: false,
46052
- installExitCode: null
46115
+ scanVerdict: record.scanVerdict,
46116
+ installRan: record.installRan,
46117
+ installExitCode: record.installExitCode,
46118
+ error: record.error
46053
46119
  });
46054
- process.exit(4);
46055
46120
  }
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
- }
46121
+ };
46122
+ const pipCtx = {
46123
+ ecosystem: "pypi",
46124
+ apiKind: "pypi",
46125
+ installArgs: pipInstallArgs,
46126
+ passthroughArgs: parsed.rawArgs,
46127
+ result,
46128
+ resolved,
46129
+ suppressedCount: 0
46130
+ };
46131
+ process.exit(await executeDecision(pipDecision, pipCtx, pipPresenter));
46071
46132
  }
46072
46133
  async function runStaticLogin() {
46073
46134
  const {
@@ -46181,6 +46242,9 @@ var init_static_output = __esm({
46181
46242
  init_npm_wrapper();
46182
46243
  init_pip_wrapper();
46183
46244
  init_wrapper_shared();
46245
+ init_route();
46246
+ init_run();
46247
+ init_json();
46184
46248
  init_artifact_integrity();
46185
46249
  init_sanitize();
46186
46250
  init_format_helpers();
@@ -48680,7 +48744,7 @@ __export(publish_check_exports, {
48680
48744
  scanPayload: () => scanPayload,
48681
48745
  summarize: () => summarize
48682
48746
  });
48683
- import { spawn as spawn4 } from "node:child_process";
48747
+ import { spawn as spawn5 } from "node:child_process";
48684
48748
  import { readFileSync as readFileSync13, existsSync as existsSync19, readdirSync as readdirSync3 } from "node:fs";
48685
48749
  import { join as join12, basename as basename2 } from "node:path";
48686
48750
  import { createGunzip } from "node:zlib";
@@ -48692,7 +48756,7 @@ function sanitizeSnippet(s, max = 40) {
48692
48756
  }
48693
48757
  async function npmPackDryRun(cwd2 = process.cwd()) {
48694
48758
  return new Promise((resolve3) => {
48695
- const child = spawn4("npm", ["pack", "--dry-run", "--json"], {
48759
+ const child = spawn5("npm", ["pack", "--dry-run", "--json"], {
48696
48760
  cwd: cwd2,
48697
48761
  stdio: ["ignore", "pipe", "pipe"]
48698
48762
  });
@@ -50847,6 +50911,11 @@ async function runNpmScan(packages, skippedCount, config, dispatch) {
50847
50911
  dispatch({ type: "SCAN_COMPLETE", result, durationMs: Date.now() - startMs, skippedCount });
50848
50912
  } catch (error) {
50849
50913
  if (error instanceof FreeCapReachedError) {
50914
+ try {
50915
+ const { recordScanCapReached: recordScanCapReached2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
50916
+ recordScanCapReached2(error.scansUsed, error.maxScans, error.reason);
50917
+ } catch {
50918
+ }
50850
50919
  dispatch({ type: "FREE_CAP_REACHED", scansUsed: error.scansUsed, maxScans: error.maxScans, capReason: error.reason });
50851
50920
  return;
50852
50921
  }
@@ -50926,6 +50995,11 @@ async function scanProjects(projects, config, dispatch) {
50926
50995
  dispatch({ type: "SCAN_COMPLETE", result: merged, durationMs: merged.durationMs, skippedCount: 0, discoveredTotal });
50927
50996
  } catch (error) {
50928
50997
  if (error instanceof FreeCapReachedError) {
50998
+ try {
50999
+ const { recordScanCapReached: recordScanCapReached2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
51000
+ recordScanCapReached2(error.scansUsed, error.maxScans, error.reason);
51001
+ } catch {
51002
+ }
50929
51003
  dispatch({ type: "FREE_CAP_REACHED", scansUsed: error.scansUsed, maxScans: error.maxScans, capReason: error.reason });
50930
51004
  return;
50931
51005
  }
@@ -51726,22 +51800,18 @@ var init_readonly = __esm({
51726
51800
  // src/ui/hooks/useWrapperBase.ts
51727
51801
  function reducer4(_state, action) {
51728
51802
  switch (action.type) {
51729
- case "PASSTHROUGH":
51730
- return { phase: "passthrough" };
51731
51803
  case "RESOLVING":
51732
51804
  return { phase: "resolving", count: action.count };
51733
51805
  case "SCANNING":
51734
51806
  return { phase: "scanning", count: action.count };
51735
- case "PASS":
51736
- return { phase: "pass", count: action.count, result: action.result };
51737
51807
  case "WARN":
51738
- return { phase: "warn", result: action.result, dgForce: action.dgForce };
51739
- case "BLOCKED":
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 };
51808
+ return { phase: "warn", result: action.result };
51809
+ case "REFUSED":
51810
+ return { phase: "refused", result: action.result, verdict: action.verdict, cmd: action.cmd, exitCode: action.exitCode };
51811
+ case "DECLINED":
51812
+ return { phase: "declined", line: action.line, exitCode: action.exitCode };
51743
51813
  case "INSTALLING":
51744
- return { phase: "installing" };
51814
+ return { phase: "installing", line: action.line };
51745
51815
  case "DONE":
51746
51816
  return { phase: "done", exitCode: action.exitCode };
51747
51817
  case "ERROR":
@@ -51750,12 +51820,17 @@ function reducer4(_state, action) {
51750
51820
  return { phase: "free_cap_reached" };
51751
51821
  }
51752
51822
  }
51753
- function useInstallWrapper(rawArgs, config, opts, exit) {
51823
+ function useInstallWrapper(rawArgs, config, opts, handoff) {
51754
51824
  const [state, dispatch] = (0, import_react37.useReducer)(reducer4, { phase: "resolving", count: 0 });
51755
51825
  const started = (0, import_react37.useRef)(false);
51756
51826
  const parsedRef = (0, import_react37.useRef)(opts.parseArgs(rawArgs));
51757
51827
  const pendingInstall = (0, import_react37.useRef)(null);
51758
51828
  const rejectRef = (0, import_react37.useRef)(null);
51829
+ const ho = handoff ?? { install: null };
51830
+ const requestInstall = (args, line) => {
51831
+ ho.install = { run: opts.runInstall, args };
51832
+ dispatch({ type: "INSTALLING", line });
51833
+ };
51759
51834
  const confirmInstall = () => {
51760
51835
  if (pendingInstall.current) {
51761
51836
  pendingInstall.current();
@@ -51778,18 +51853,14 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51778
51853
  (async () => {
51779
51854
  try {
51780
51855
  if (!parsed.shouldScan) {
51781
- dispatch({ type: "PASSTHROUGH" });
51782
- const code = await opts.runInstall(parsed.rawArgs);
51783
- dispatch({ type: "DONE", exitCode: code });
51856
+ requestInstall(parsed.rawArgs, null);
51784
51857
  return;
51785
51858
  }
51786
51859
  let specs;
51787
51860
  if (parsed.packages.length === 0) {
51788
51861
  specs = opts.inferSpecsFromContext(parsed);
51789
51862
  if (specs.length === 0) {
51790
- dispatch({ type: "PASSTHROUGH" });
51791
- const code = await opts.runInstall(parsed.rawArgs);
51792
- dispatch({ type: "DONE", exitCode: code });
51863
+ requestInstall(parsed.rawArgs, null);
51793
51864
  return;
51794
51865
  }
51795
51866
  } else {
@@ -51798,9 +51869,7 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51798
51869
  dispatch({ type: "RESOLVING", count: specs.length });
51799
51870
  const { resolved } = await opts.resolvePackages(specs);
51800
51871
  if (resolved.length === 0) {
51801
- dispatch({ type: "PASSTHROUGH" });
51802
- const code = await opts.runInstall(parsed.rawArgs);
51803
- dispatch({ type: "DONE", exitCode: code });
51872
+ requestInstall(parsed.rawArgs, null);
51804
51873
  return;
51805
51874
  }
51806
51875
  const isRequirementsInstall = opts.ecosystem === "pypi" && (parsed.rawArgs.includes("-r") || parsed.rawArgs.includes("--requirement"));
@@ -51810,7 +51879,6 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51810
51879
  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
51880
  proceed: false
51812
51881
  });
51813
- dispatch({ type: "DONE", exitCode: 2 });
51814
51882
  return;
51815
51883
  }
51816
51884
  const pinnedArgs = isRequirementsInstall ? parsed.rawArgs : opts.ecosystem === "npm" ? pinTopLevelArgs(parsed.rawArgs, parsed.packages, resolved) : pinPipArgs(parsed.rawArgs, parsed.packages, resolved);
@@ -51830,114 +51898,61 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51830
51898
  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
51899
  proceed: false
51832
51900
  });
51833
- dispatch({ type: "DONE", exitCode: 2 });
51834
51901
  return;
51835
51902
  }
51836
51903
  }
51837
51904
  dispatch({ type: "SCANNING", count: scanSet.length });
51838
51905
  const result = await opts.callAnalyze(scanSet, config);
51839
- if (result.action === "pass") {
51840
- if (exit) exit();
51841
- const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
51842
- const line = formatPassLine(result, chalk18);
51843
- process.stderr.write(" " + line + "\n\n");
51844
- const code = await opts.runInstall(installArgs);
51845
- process.exit(code);
51906
+ const decision = routeVerdict({
51907
+ verdict: verdictFromResult(result),
51908
+ mode: config.mode,
51909
+ strict: config.strict,
51910
+ dgForce: parsed.dgForce
51911
+ });
51912
+ if (decision.outcome === "refuse") {
51913
+ const cmd = `${opts.ecosystem === "npm" ? "npm" : "pip"} ${parsed.rawArgs.join(" ")} --dg-force`;
51914
+ const v = decision.verdict === "analysis_incomplete" ? "incomplete" : decision.verdict === "block" ? "block" : "warn";
51915
+ dispatch({ type: "REFUSED", result, verdict: v, cmd, exitCode: decision.refuseExitCode });
51846
51916
  return;
51847
51917
  }
51848
- if (result.action === "warn") {
51849
- if (parsed.dgForce) {
51850
- const { recordBypassLocally: recordBypassLocally2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
51851
- recordBypassLocally2({
51852
- ecosystem: opts.ecosystem,
51853
- verdict: "warn",
51854
- trigger: "dg-force",
51855
- reason: parsed.dgForceReason,
51856
- packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51857
- });
51858
- dispatch({ type: "WARN", result, dgForce: true });
51859
- dispatch({ type: "INSTALLING" });
51860
- const code = await opts.runInstall(installArgs);
51861
- dispatch({ type: "DONE", exitCode: code });
51862
- return;
51863
- }
51864
- dispatch({ type: "WARN", result, dgForce: false });
51865
- const shouldProceed = await new Promise((resolve3) => {
51866
- pendingInstall.current = () => resolve3(true);
51867
- rejectRef.current = () => resolve3(false);
51918
+ const recordBypass = async (trigger) => {
51919
+ const { recordBypassLocally: recordBypassLocally2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
51920
+ recordBypassLocally2({
51921
+ ecosystem: opts.ecosystem,
51922
+ verdict: decision.verdict === "block" ? "block" : "warn",
51923
+ trigger,
51924
+ packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51868
51925
  });
51869
- if (shouldProceed) {
51870
- const { recordBypassLocally: recordBypassLocally2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
51871
- recordBypassLocally2({
51872
- ecosystem: opts.ecosystem,
51873
- verdict: "warn",
51874
- trigger: "interactive-confirm",
51875
- packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51876
- });
51877
- dispatch({ type: "INSTALLING" });
51878
- const code = await opts.runInstall(installArgs);
51879
- dispatch({ type: "DONE", exitCode: code });
51880
- } else {
51881
- dispatch({ type: "DONE", exitCode: 1 });
51882
- }
51883
- return;
51884
- }
51885
- if (result.action === "block") {
51886
- if (parsed.dgForce) {
51887
- const { recordBypassLocally: recordBypassLocally2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
51888
- recordBypassLocally2({
51889
- ecosystem: opts.ecosystem,
51890
- verdict: "block",
51891
- trigger: "dg-force",
51892
- reason: parsed.dgForceReason,
51893
- packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51894
- });
51895
- dispatch({ type: "BLOCKED", result, dgForce: true });
51896
- dispatch({ type: "INSTALLING" });
51897
- const code = await opts.runInstall(installArgs);
51898
- dispatch({ type: "DONE", exitCode: code });
51899
- return;
51900
- }
51901
- dispatch({ type: "BLOCKED", result, dgForce: false });
51902
- const shouldProceed = await new Promise((resolve3) => {
51926
+ };
51927
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
51928
+ const top = result.packages.length === 1 ? result.packages[0] : null;
51929
+ const name = top ? `${top.name}@${top.version}` : `${result.packages.length} packages`;
51930
+ const pinnedLine = (() => {
51931
+ if (decision.bypassed) {
51932
+ const sig = decision.verdict === "block" ? chalk18.red("\u2718") : chalk18.yellow("\u26A0");
51933
+ return ` ${sig} ${name} ${chalk18.dim(`(${decision.verdict}) \u2014 --dg-force override, installing`)}`;
51934
+ }
51935
+ if (decision.verdict === "analysis_incomplete") return ` ${chalk18.cyan("?")} ${name} ${chalk18.dim("\u2014 could not verify; proceeding")}`;
51936
+ if (decision.verdict === "pass") return ` ${chalk18.green("\u2713")} ${name} ${chalk18.dim("\u2014 clean")}`;
51937
+ return null;
51938
+ })();
51939
+ if (decision.outcome === "prompt") {
51940
+ dispatch({ type: "WARN", result });
51941
+ const accepted = await new Promise((resolve3) => {
51903
51942
  pendingInstall.current = () => resolve3(true);
51904
51943
  rejectRef.current = () => resolve3(false);
51905
51944
  });
51906
- if (shouldProceed) {
51907
- const { recordBypassLocally: recordBypassLocally2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
51908
- recordBypassLocally2({
51909
- ecosystem: opts.ecosystem,
51910
- verdict: "block",
51911
- trigger: "interactive-confirm",
51912
- packages: result.packages.map((p) => ({ name: p.name, version: p.version, score: p.score }))
51913
- });
51914
- dispatch({ type: "INSTALLING" });
51915
- const code = await opts.runInstall(installArgs);
51916
- dispatch({ type: "DONE", exitCode: code });
51917
- } else {
51918
- dispatch({ type: "DONE", exitCode: 2 });
51919
- }
51920
- return;
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 });
51945
+ if (!accepted) {
51946
+ dispatch({ type: "DECLINED", line: ` ${chalk18.yellow("\u2717")} ${name} ${chalk18.dim("\u2014 not installed")}`, exitCode: decision.refuseExitCode });
51933
51947
  return;
51934
51948
  }
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 });
51949
+ await recordBypass("interactive-confirm");
51950
+ requestInstall(installArgs, null);
51939
51951
  return;
51940
51952
  }
51953
+ if (decision.bypassed) await recordBypass("dg-force");
51954
+ requestInstall(decision.outcome === "passthrough" ? parsed.rawArgs : installArgs, pinnedLine);
51955
+ return;
51941
51956
  } catch (error) {
51942
51957
  if (error instanceof FreeCapReachedError) {
51943
51958
  dispatch({ type: "FREE_CAP_REACHED" });
@@ -51950,27 +51965,17 @@ function useInstallWrapper(rawArgs, config, opts, exit) {
51950
51965
  message: `Scan failed (${message}) and --mode is block. Install aborted. Use --dg-force to bypass.`,
51951
51966
  proceed: false
51952
51967
  });
51953
- dispatch({ type: "DONE", exitCode: 2 });
51954
51968
  return;
51955
51969
  }
51956
- dispatch({ type: "ERROR", message, proceed: true });
51957
- dispatch({ type: "INSTALLING" });
51958
- const code = await opts.runInstall(installArgs);
51959
- dispatch({ type: "DONE", exitCode: code });
51970
+ const chalk18 = (await Promise.resolve().then(() => __toESM(require_source(), 1))).default;
51971
+ requestInstall(installArgs, ` ${chalk18.yellow("\u26A0")} ${chalk18.dim(`scan failed (${message}); proceeding`)}`);
51960
51972
  }
51961
51973
  })();
51962
51974
  }, [rawArgs, config]);
51963
51975
  return { state, confirmInstall, rejectInstall };
51964
51976
  }
51965
- function formatPassLine(result, chalk18) {
51966
- if (result.packages.length === 1) {
51967
- const p = result.packages[0];
51968
- return chalk18.green("\u2713 ") + `${p.name}@${p.version}` + chalk18.dim(" \u2014 clean. Installing.");
51969
- }
51970
- return chalk18.green("\u2713 ") + `${result.packages.length} packages` + chalk18.dim(" \u2014 all clean. Installing.");
51971
- }
51972
- function useWrapper(args, config, ecosystem, exit) {
51973
- return useInstallWrapper(args, config, ecosystem === "npm" ? NPM_OPTIONS : PIP_OPTIONS, exit);
51977
+ function useWrapper(args, config, ecosystem, handoff) {
51978
+ return useInstallWrapper(args, config, ecosystem === "npm" ? NPM_OPTIONS : PIP_OPTIONS, handoff);
51974
51979
  }
51975
51980
  var import_react37, NPM_OPTIONS, PIP_OPTIONS;
51976
51981
  var init_useWrapperBase = __esm({
@@ -51979,6 +51984,8 @@ var init_useWrapperBase = __esm({
51979
51984
  import_react37 = __toESM(require_react(), 1);
51980
51985
  init_client();
51981
51986
  init_wrapper_shared();
51987
+ init_route();
51988
+ init_run();
51982
51989
  init_npm_wrapper();
51983
51990
  init_pip_wrapper();
51984
51991
  NPM_OPTIONS = {
@@ -51986,7 +51993,7 @@ var init_useWrapperBase = __esm({
51986
51993
  resolvePackages,
51987
51994
  resolveTree: resolveTreeNpm,
51988
51995
  callAnalyze: callAnalyzeAPI,
51989
- runInstall: runNpm,
51996
+ runInstall: (args) => runNpm(args, { trim: true }),
51990
51997
  inferSpecsFromContext: () => readBareInstallPackages(process.cwd()),
51991
51998
  ecosystem: "npm"
51992
51999
  };
@@ -51995,7 +52002,7 @@ var init_useWrapperBase = __esm({
51995
52002
  resolvePackages: resolvePackages2,
51996
52003
  resolveTree: resolveTreePip,
51997
52004
  callAnalyze: callPyPIAnalyzeAPI,
51998
- runInstall: runPip,
52005
+ runInstall: (args) => runPip(args, { trim: true }),
51999
52006
  inferSpecsFromContext: (parsed) => {
52000
52007
  const file = parsed.requirementsFile;
52001
52008
  return file ? parseRequirementsFile(file) : [];
@@ -52177,6 +52184,7 @@ var init_ConfirmPrompt = __esm({
52177
52184
  onReject();
52178
52185
  }
52179
52186
  });
52187
+ if (!message) return null;
52180
52188
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Box_default, { flexDirection: "column", children: [
52181
52189
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(Text, { children: [
52182
52190
  import_chalk17.default.red.bold("\u26A0"),
@@ -52232,7 +52240,8 @@ var init_WrapperVerdictLine = __esm({
52232
52240
  WrapperVerdictLine = ({
52233
52241
  result,
52234
52242
  verdict,
52235
- dgForce
52243
+ dgForce,
52244
+ refusal
52236
52245
  }) => {
52237
52246
  const total = result.packages.length;
52238
52247
  const counts = countSummary(result);
@@ -52258,12 +52267,13 @@ var init_WrapperVerdictLine = __esm({
52258
52267
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { dimColor: true, children: " \u2014 all clean. Installing." })
52259
52268
  ] });
52260
52269
  }
52261
- const sigil = verdict === "block" ? "\u2718" : "\u26A0";
52262
- const color = verdict === "block" ? "red" : "yellow";
52270
+ const sigil = verdict === "block" ? "\u2718" : verdict === "incomplete" ? "?" : "\u26A0";
52271
+ const color = verdict === "block" ? "red" : verdict === "incomplete" ? "cyan" : "yellow";
52263
52272
  const prompt = verdict === "block" ? "install anyway?" : "install?";
52264
52273
  if (total === 1) {
52265
52274
  const p = topPackage(result);
52266
52275
  const score = p ? p.score : result.score;
52276
+ const meta = verdict === "incomplete" ? `(could not verify)${reasonTag(p)}` : `(${verdict}, score ${score})${reasonTag(p)}`;
52267
52277
  return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Box_default, { flexDirection: "row", children: [
52268
52278
  /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { color, children: [
52269
52279
  sigil,
@@ -52274,18 +52284,23 @@ var init_WrapperVerdictLine = __esm({
52274
52284
  "@",
52275
52285
  p?.version
52276
52286
  ] }),
52277
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { dimColor: true, children: [
52278
- " (",
52279
- verdict,
52280
- ", score ",
52281
- score,
52282
- ")",
52283
- reasonTag(p),
52284
- " \u2014 "
52285
- ] }),
52286
- dgForce ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color, bold: true, children: "--dg-force: bypassing. Installing." }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { bold: true, children: [
52287
- prompt,
52288
- " [y/N]"
52287
+ refusal ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { dimColor: true, children: [
52288
+ " ",
52289
+ meta
52290
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
52291
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { dimColor: true, children: [
52292
+ " ",
52293
+ meta,
52294
+ " \u2014 "
52295
+ ] }),
52296
+ dgForce ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color, bold: true, children: "--dg-force: bypassing. Installing." }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { bold: true, children: [
52297
+ prompt,
52298
+ " [",
52299
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color: "green", children: "y" }),
52300
+ "/",
52301
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color: "red", children: "N" }),
52302
+ "]"
52303
+ ] })
52289
52304
  ] })
52290
52305
  ] });
52291
52306
  }
@@ -52303,14 +52318,23 @@ var init_WrapperVerdictLine = __esm({
52303
52318
  total,
52304
52319
  " packages"
52305
52320
  ] }),
52306
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { dimColor: true, children: [
52321
+ refusal ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { dimColor: true, children: [
52307
52322
  ": ",
52308
- parts.join(", "),
52309
- " \u2014 "
52310
- ] }),
52311
- dgForce ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color, bold: true, children: "--dg-force: bypassing. Installing." }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { bold: true, children: [
52312
- prompt,
52313
- " [y/N] [d] details"
52323
+ parts.join(", ")
52324
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
52325
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { dimColor: true, children: [
52326
+ ": ",
52327
+ parts.join(", "),
52328
+ " \u2014 "
52329
+ ] }),
52330
+ dgForce ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color, bold: true, children: "--dg-force: bypassing. Installing." }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Text, { bold: true, children: [
52331
+ prompt,
52332
+ " [",
52333
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color: "green", children: "y" }),
52334
+ "/",
52335
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Text, { color: "red", children: "N" }),
52336
+ "] [d] details"
52337
+ ] })
52314
52338
  ] })
52315
52339
  ] });
52316
52340
  };
@@ -52348,21 +52372,30 @@ var init_WrapperApp = __esm({
52348
52372
  installing: "Installing with pip..."
52349
52373
  }
52350
52374
  };
52351
- WrapperApp = ({ args, config, ecosystem }) => {
52375
+ WrapperApp = ({ args, config, ecosystem, handoff }) => {
52352
52376
  const { exit } = use_app_default();
52353
- const { state, confirmInstall, rejectInstall } = useWrapper(args, config, ecosystem, exit);
52377
+ const { state, confirmInstall, rejectInstall } = useWrapper(args, config, ecosystem, handoff);
52354
52378
  const [showDetails, setShowDetails] = (0, import_react38.useState)(false);
52355
52379
  use_input_default((input) => {
52356
- if (input === "d" && (state.phase === "warn" || state.phase === "blocked")) {
52380
+ if (input === "d" && state.phase === "warn") {
52357
52381
  setShowDetails((v) => !v);
52358
52382
  }
52359
52383
  });
52360
52384
  (0, import_react38.useEffect)(() => {
52361
- if (state.phase === "done") {
52385
+ if (state.phase === "done" || state.phase === "refused" || state.phase === "declined") {
52362
52386
  process.exitCode = state.exitCode;
52363
52387
  const timer = setTimeout(() => exit(), 0);
52364
52388
  return () => clearTimeout(timer);
52365
52389
  }
52390
+ if (state.phase === "installing") {
52391
+ const timer = setTimeout(() => exit(), 0);
52392
+ return () => clearTimeout(timer);
52393
+ }
52394
+ if (state.phase === "error") {
52395
+ process.exitCode = 2;
52396
+ const timer = setTimeout(() => exit(), 0);
52397
+ return () => clearTimeout(timer);
52398
+ }
52366
52399
  if (state.phase === "free_cap_reached") {
52367
52400
  process.exitCode = 1;
52368
52401
  const timer = setTimeout(() => exit(), 0);
@@ -52377,43 +52410,30 @@ var init_WrapperApp = __esm({
52377
52410
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner2, { label: labels.resolving(state.count, state.count !== 1 ? "s" : "") });
52378
52411
  case "scanning":
52379
52412
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner2, { label: labels.scanning(state.count, state.count !== 1 ? "s" : "") });
52380
- case "pass":
52381
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(WrapperVerdictLine, { result: state.result, verdict: "pass" });
52382
52413
  case "warn":
52383
52414
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", children: [
52384
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(WrapperVerdictLine, { result: state.result, verdict: "warn", dgForce: state.dgForce }),
52415
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(WrapperVerdictLine, { result: state.result, verdict: "warn" }),
52385
52416
  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 }) }),
52386
- !state.dgForce && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ConfirmPrompt, { message: "", onConfirm: handleConfirm, onReject: handleReject })
52417
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ConfirmPrompt, { message: "", onConfirm: handleConfirm, onReject: handleReject })
52387
52418
  ] });
52388
- case "blocked":
52419
+ case "refused":
52389
52420
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Box_default, { flexDirection: "column", children: [
52390
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(WrapperVerdictLine, { result: state.result, verdict: "block", dgForce: state.dgForce }),
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 }) }),
52392
- !state.dgForce && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ConfirmPrompt, { message: "", onConfirm: handleConfirm, onReject: handleReject })
52421
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(WrapperVerdictLine, { result: state.result, verdict: state.verdict, refusal: true }),
52422
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Text, { dimColor: true, children: [
52423
+ " install anyway: ",
52424
+ state.cmd
52425
+ ] })
52393
52426
  ] });
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) });
52427
+ case "declined":
52428
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: state.line });
52429
+ // The verdict line is Ink's final frame; it stays on screen after unmount and
52430
+ // the installer's (trimmed) output is printed under it by bin.ts.
52402
52431
  case "installing":
52403
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Spinner2, { label: labels.installing });
52432
+ return state.line ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Text, { children: state.line }) : null;
52404
52433
  case "done":
52405
52434
  return null;
52406
52435
  case "error":
52407
- if (state.proceed) {
52408
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Text, { color: "yellow", children: [
52409
- "Warning: Scan failed (",
52410
- state.message,
52411
- "). Proceeding with install."
52412
- ] });
52413
- }
52414
52436
  return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ErrorView, { error: new Error(state.message) });
52415
- case "passthrough":
52416
- return null;
52417
52437
  case "free_cap_reached": {
52418
52438
  let hasKey = false;
52419
52439
  try {
@@ -52449,9 +52469,9 @@ __export(conda_wrapper_exports, {
52449
52469
  adapter: () => adapter,
52450
52470
  runStaticConda: () => runStaticConda
52451
52471
  });
52452
- import { spawn as spawn5 } from "node:child_process";
52472
+ import { spawn as spawn6 } from "node:child_process";
52453
52473
  function parseCondaArgs(args) {
52454
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
52474
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
52455
52475
  const command = filtered[0] ?? "";
52456
52476
  const shouldScan = INSTALL_COMMANDS3.has(command);
52457
52477
  const packages = [];
@@ -52470,7 +52490,6 @@ function parseCondaArgs(args) {
52470
52490
  packages,
52471
52491
  rawArgs: filtered,
52472
52492
  dgForce,
52473
- dgForceReason,
52474
52493
  dgNoScripts,
52475
52494
  shouldScan
52476
52495
  };
@@ -52504,7 +52523,7 @@ async function runStaticConda(args, ecosystem, config) {
52504
52523
  return 127;
52505
52524
  }
52506
52525
  return await new Promise((resolve3) => {
52507
- const child = spawn5(real, parsed.rawArgs, { stdio: "inherit", env: childInstallEnv() });
52526
+ const child = spawn6(real, parsed.rawArgs, { stdio: "inherit", env: childInstallEnv() });
52508
52527
  child.on("close", (code) => resolve3(code ?? 1));
52509
52528
  child.on("error", () => resolve3(1));
52510
52529
  });
@@ -52551,7 +52570,7 @@ function pnpmFlagTakesValue(flag) {
52551
52570
  return valueFlagPrefixes.includes(flag);
52552
52571
  }
52553
52572
  function parsePnpmArgs(args) {
52554
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
52573
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
52555
52574
  const command = filtered[0] ?? "";
52556
52575
  const shouldScan = INSTALL_COMMANDS4.has(command);
52557
52576
  const packages = [];
@@ -52570,7 +52589,6 @@ function parsePnpmArgs(args) {
52570
52589
  packages,
52571
52590
  rawArgs: filtered,
52572
52591
  dgForce,
52573
- dgForceReason,
52574
52592
  dgNoScripts,
52575
52593
  shouldScan
52576
52594
  };
@@ -52649,7 +52667,7 @@ function yarnFlagTakesValue(flag) {
52649
52667
  return valueFlagPrefixes.includes(flag);
52650
52668
  }
52651
52669
  function parseYarnArgs(args) {
52652
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
52670
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
52653
52671
  const command = filtered[0] ?? "";
52654
52672
  const shouldScan = INSTALL_COMMANDS5.has(command);
52655
52673
  const packages = [];
@@ -52668,7 +52686,6 @@ function parseYarnArgs(args) {
52668
52686
  packages,
52669
52687
  rawArgs: filtered,
52670
52688
  dgForce,
52671
- dgForceReason,
52672
52689
  dgNoScripts,
52673
52690
  shouldScan
52674
52691
  };
@@ -52748,7 +52765,7 @@ function bunFlagTakesValue(flag) {
52748
52765
  return valueFlagPrefixes.includes(flag);
52749
52766
  }
52750
52767
  function parseBunArgs(args) {
52751
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
52768
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
52752
52769
  const command = filtered[0] ?? "";
52753
52770
  const shouldScan = INSTALL_COMMANDS6.has(command);
52754
52771
  const packages = [];
@@ -52767,7 +52784,6 @@ function parseBunArgs(args) {
52767
52784
  packages,
52768
52785
  rawArgs: filtered,
52769
52786
  dgForce,
52770
- dgForceReason,
52771
52787
  dgNoScripts,
52772
52788
  shouldScan
52773
52789
  };
@@ -52854,7 +52870,7 @@ function uvFlagTakesValue(flag) {
52854
52870
  return valueFlagPrefixes.includes(flag);
52855
52871
  }
52856
52872
  function parseUvArgs(args) {
52857
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
52873
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
52858
52874
  const first = filtered[0] ?? "";
52859
52875
  let command = "";
52860
52876
  let argStart = 1;
@@ -52903,7 +52919,6 @@ function parseUvArgs(args) {
52903
52919
  packages,
52904
52920
  rawArgs: filtered,
52905
52921
  dgForce,
52906
- dgForceReason,
52907
52922
  dgNoScripts,
52908
52923
  shouldScan
52909
52924
  };
@@ -52915,7 +52930,6 @@ async function resolveTopLevel5(parsed) {
52915
52930
  if (at <= 0) return s;
52916
52931
  return `${s.slice(0, at)}==${s.slice(at + 1)}`;
52917
52932
  });
52918
- void parsePipSpec;
52919
52933
  return await resolvePackages2(normalized);
52920
52934
  }
52921
52935
  async function resolveTransitive4(parsed) {
@@ -52966,7 +52980,7 @@ function pipxFlagTakesValue(flag) {
52966
52980
  return valueFlagPrefixes.includes(flag);
52967
52981
  }
52968
52982
  function parsePipxArgs(args) {
52969
- const { filtered, dgForce, dgForceReason, dgNoScripts } = stripDgFlags(args);
52983
+ const { filtered, dgForce, dgNoScripts } = stripDgFlags(args);
52970
52984
  const command = filtered[0] ?? "";
52971
52985
  const shouldScan = INSTALL_COMMANDS7.has(command) && command !== "upgrade-all";
52972
52986
  const packages = [];
@@ -52989,7 +53003,6 @@ function parsePipxArgs(args) {
52989
53003
  packages,
52990
53004
  rawArgs: filtered,
52991
53005
  dgForce,
52992
- dgForceReason,
52993
53006
  dgNoScripts,
52994
53007
  shouldScan
52995
53008
  };
@@ -53043,11 +53056,7 @@ var wrapper_factory_exports = {};
53043
53056
  __export(wrapper_factory_exports, {
53044
53057
  runEcosystemWrapper: () => runEcosystemWrapper
53045
53058
  });
53046
- import { spawn as spawn6 } from "node:child_process";
53047
- function emitJson(config, result) {
53048
- if (!config.json) return;
53049
- process.stdout.write(JSON.stringify(result, null, 2) + "\n");
53050
- }
53059
+ import { spawn as spawn7 } from "node:child_process";
53051
53060
  function shimSentinelEnv3() {
53052
53061
  return childInstallEnv();
53053
53062
  }
@@ -53059,7 +53068,7 @@ async function spawnRealBinary(adapter7, args) {
53059
53068
  return 127;
53060
53069
  }
53061
53070
  return await new Promise((resolve3) => {
53062
- const child = spawn6(real, args, { stdio: "inherit", env: shimSentinelEnv3() });
53071
+ const child = spawn7(real, args, { stdio: "inherit", env: shimSentinelEnv3() });
53063
53072
  child.on("close", (code) => resolve3(code ?? 1));
53064
53073
  child.on("error", () => resolve3(1));
53065
53074
  });
@@ -53110,7 +53119,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
53110
53119
  `)
53111
53120
  );
53112
53121
  }
53113
- emitJson(config, {
53122
+ emitWrapperJson(config, {
53114
53123
  ecosystem: adapter7.ecosystem,
53115
53124
  packages: [],
53116
53125
  scanVerdict: "scan_failed",
@@ -53167,7 +53176,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
53167
53176
  `)
53168
53177
  );
53169
53178
  }
53170
- emitJson(config, {
53179
+ emitWrapperJson(config, {
53171
53180
  ecosystem: adapter7.ecosystem,
53172
53181
  packages: [],
53173
53182
  scanVerdict: "scan_failed",
@@ -53198,7 +53207,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
53198
53207
 
53199
53208
  `)
53200
53209
  );
53201
- emitJson(config, {
53210
+ emitWrapperJson(config, {
53202
53211
  ecosystem: adapter7.ecosystem,
53203
53212
  packages: [],
53204
53213
  scanVerdict: "scan_failed",
@@ -53215,7 +53224,7 @@ async function runEcosystemWrapper(adapter7, args, config) {
53215
53224
 
53216
53225
  `)
53217
53226
  );
53218
- emitJson(config, {
53227
+ emitWrapperJson(config, {
53219
53228
  ecosystem: adapter7.ecosystem,
53220
53229
  packages: [],
53221
53230
  scanVerdict: "scan_failed",
@@ -53231,184 +53240,152 @@ async function runEcosystemWrapper(adapter7, args, config) {
53231
53240
  `)
53232
53241
  );
53233
53242
  }
53234
- const code2 = await spawnRealBinary(adapter7, installArgs);
53235
- emitJson(config, {
53243
+ const code = await spawnRealBinary(adapter7, installArgs);
53244
+ emitWrapperJson(config, {
53236
53245
  ecosystem: adapter7.ecosystem,
53237
53246
  packages: [],
53238
53247
  scanVerdict: "scan_failed",
53239
53248
  installRan: true,
53240
- installExitCode: code2,
53249
+ installExitCode: code,
53241
53250
  error: { code: "scan_failed", message: err.message }
53242
53251
  });
53243
- return code2;
53252
+ return code;
53244
53253
  }
53245
53254
  const allowlist = loadAllowlist(process.cwd());
53246
53255
  const { result: filteredResult, suppressedCount } = applyAllowlist(allowlist, result, adapter7.apiKind);
53247
53256
  result = filteredResult;
53248
53257
  const topLevelNames = new Set(resolved.map((p) => p.name));
53249
- if (result.action === "pass") {
53250
- const topLevel = resolved.map((p) => `${p.name} ${p.version}`);
53251
- const passLine = topLevel.length === 1 ? ` ${import_chalk19.default.green("\u2713")} ${import_chalk19.default.bold("DG verified:")} ${topLevel[0]} is safe` : ` ${import_chalk19.default.green("\u2713")} ${import_chalk19.default.bold("DG verified:")} ${topLevel.length} packages safe`;
53252
- const installLine = topLevel.length === 1 ? ` ${import_chalk19.default.green("\u2713")} Installing ${topLevel[0]}` : ` ${import_chalk19.default.green("\u2713")} Installing ${topLevel.join(", ")}`;
53253
- if (!config.json && !config.quiet) {
53254
- process.stderr.write(`${passLine}
53258
+ const verdict = verdictFromResult(result);
53259
+ const decision = routeVerdict({
53260
+ verdict,
53261
+ mode: config.mode,
53262
+ strict: config.strict,
53263
+ dgForce: parsed.dgForce
53264
+ });
53265
+ const ctx = {
53266
+ ecosystem: adapter7.ecosystem,
53267
+ apiKind: adapter7.apiKind,
53268
+ installArgs,
53269
+ passthroughArgs: parsed.rawArgs,
53270
+ result,
53271
+ resolved,
53272
+ suppressedCount,
53273
+ error: verdict === "analysis_incomplete" && decision.outcome === "refuse" ? { code: "analysis_incomplete", message: "scanner could not fully analyze the install set" } : void 0
53274
+ };
53275
+ const presenter = {
53276
+ announce(d) {
53277
+ switch (d.verdict) {
53278
+ case "pass": {
53279
+ if (config.json || config.quiet) return;
53280
+ const topLevel = resolved.map((p) => `${p.name} ${p.version}`);
53281
+ const passLine = topLevel.length === 1 ? ` ${import_chalk19.default.green("\u2713")} ${import_chalk19.default.bold("DG verified:")} ${topLevel[0]} is safe` : ` ${import_chalk19.default.green("\u2713")} ${import_chalk19.default.bold("DG verified:")} ${topLevel.length} packages safe`;
53282
+ const installLine = topLevel.length === 1 ? ` ${import_chalk19.default.green("\u2713")} Installing ${topLevel[0]}` : ` ${import_chalk19.default.green("\u2713")} Installing ${topLevel.join(", ")}`;
53283
+ process.stderr.write(`${passLine}
53255
53284
  ${installLine}
53256
53285
  `);
53257
- if (suppressedCount > 0) {
53258
- process.stderr.write(import_chalk19.default.dim(` (${suppressedCount} finding${suppressedCount === 1 ? "" : "s"} suppressed by .dg-allowlist.json)
53286
+ if (suppressedCount > 0) {
53287
+ process.stderr.write(import_chalk19.default.dim(` (${suppressedCount} finding${suppressedCount === 1 ? "" : "s"} suppressed by .dg-allowlist.json)
53259
53288
  `));
53260
- }
53261
- process.stderr.write("\n");
53262
- }
53263
- const code2 = await spawnRealBinary(adapter7, installArgs);
53264
- emitJson(config, {
53265
- ecosystem: adapter7.ecosystem,
53266
- packages: packagesFromResult(result, topLevelNames),
53267
- scanVerdict: "pass",
53268
- installRan: true,
53269
- installExitCode: code2,
53270
- suppressedByAllowlist: suppressedCount > 0 ? suppressedCount : void 0
53271
- });
53272
- return code2;
53273
- }
53274
- if (result.action === "warn") {
53275
- if (!config.json && !config.quiet) {
53276
- const topLevelList = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
53277
- process.stderr.write(` ${import_chalk19.default.yellow("\u26A0")} ${import_chalk19.default.bold("DG flagged")} ${topLevelList}.
53289
+ }
53290
+ process.stderr.write("\n");
53291
+ return;
53292
+ }
53293
+ case "warn": {
53294
+ if (config.json || config.quiet) return;
53295
+ const topLevelList = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
53296
+ process.stderr.write(` ${import_chalk19.default.yellow("\u26A0")} ${import_chalk19.default.bold("DG flagged")} ${topLevelList}.
53278
53297
  `);
53279
- const blockedPkgs = result.packages.filter((p) => derivePackageActionPublic(p) === "warn");
53280
- for (const p of blockedPkgs.slice(0, 5)) {
53281
- if (p.findings && p.findings.length > 0) {
53282
- for (const f of p.findings.slice(0, 3)) {
53283
- process.stderr.write(import_chalk19.default.dim(` \u2022 ${f.title ?? "finding"}
53298
+ const flaggedPkgs = result.packages.filter((p) => derivePackageActionPublic(p) === "warn");
53299
+ for (const p of flaggedPkgs.slice(0, 5)) {
53300
+ if (p.findings && p.findings.length > 0) {
53301
+ for (const f of p.findings.slice(0, 3)) {
53302
+ process.stderr.write(import_chalk19.default.dim(` \u2022 ${f.title ?? "finding"}
53303
+ `));
53304
+ }
53305
+ }
53306
+ }
53307
+ if (suppressedCount > 0) {
53308
+ process.stderr.write(import_chalk19.default.dim(` (${suppressedCount} additional finding${suppressedCount === 1 ? "" : "s"} suppressed by .dg-allowlist.json)
53284
53309
  `));
53285
53310
  }
53311
+ return;
53286
53312
  }
53287
- }
53288
- if (suppressedCount > 0) {
53289
- process.stderr.write(import_chalk19.default.dim(` (${suppressedCount} additional finding${suppressedCount === 1 ? "" : "s"} suppressed by .dg-allowlist.json)
53313
+ case "block": {
53314
+ if (d.outcome === "install") {
53315
+ if (!config.json && !config.quiet) {
53316
+ process.stderr.write(import_chalk19.default.yellow.bold(` --dg-force: bypassing block. Install at your own risk.
53317
+
53290
53318
  `));
53319
+ }
53320
+ } else if (!config.json) {
53321
+ const blockedList = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
53322
+ process.stderr.write(
53323
+ ` ${import_chalk19.default.red("\u2717")} ${import_chalk19.default.bold("DG blocked")} ${blockedList}.
53324
+ ${import_chalk19.default.dim(`install anyway: ${adapter7.realBinaryName} ${parsed.rawArgs.join(" ")} --dg-force`)}
53325
+
53326
+ `
53327
+ );
53328
+ }
53329
+ return;
53330
+ }
53331
+ case "analysis_incomplete": {
53332
+ const list = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
53333
+ if (d.outcome === "refuse") {
53334
+ if (!config.json) {
53335
+ process.stderr.write(
53336
+ ` ${import_chalk19.default.cyan("?")} ${import_chalk19.default.bold("DG couldn't verify")} ${list} \u2014 unverified, not safe.
53337
+ ${import_chalk19.default.dim(`install anyway: ${adapter7.realBinaryName} ${parsed.rawArgs.join(" ")} --dg-force`)}
53338
+
53339
+ `
53340
+ );
53341
+ }
53342
+ } else if (!config.json && !config.quiet) {
53343
+ process.stderr.write(
53344
+ import_chalk19.default.yellow(` \u26A0 DG could not fully verify ${list} (analysis incomplete). Proceeding with install (mode=${config.mode}).
53345
+ `)
53346
+ );
53347
+ }
53348
+ return;
53349
+ }
53350
+ default:
53351
+ return;
53352
+ }
53353
+ },
53354
+ async confirmProceed() {
53355
+ if (!(process.stderr.isTTY && !process.env.CI && !config.json)) {
53356
+ if (!config.json && !config.quiet) process.stderr.write(import_chalk19.default.dim(" Proceeding (non-interactive).\n"));
53357
+ return true;
53291
53358
  }
53292
- }
53293
- if (process.stderr.isTTY && !process.env.CI && !config.json) {
53294
53359
  const { promptYesNo: promptYesNo2 } = await Promise.resolve().then(() => (init_prompt(), prompt_exports));
53295
53360
  const proceed = await promptYesNo2({ defaultAnswer: "y", message: " Proceed?" });
53296
- if (!proceed) {
53297
- process.stderr.write(import_chalk19.default.dim(" Install cancelled by user.\n\n"));
53298
- emitJson(config, {
53299
- ecosystem: adapter7.ecosystem,
53300
- packages: packagesFromResult(result, topLevelNames),
53301
- scanVerdict: "warn",
53302
- installRan: false,
53303
- installExitCode: null
53304
- });
53305
- return 1;
53306
- }
53307
- } else if (!config.json && !config.quiet) {
53308
- process.stderr.write(import_chalk19.default.dim(" Proceeding (non-interactive).\n"));
53309
- }
53310
- const code2 = await spawnRealBinary(adapter7, installArgs);
53311
- emitJson(config, {
53312
- ecosystem: adapter7.ecosystem,
53313
- packages: packagesFromResult(result, topLevelNames),
53314
- scanVerdict: "warn",
53315
- installRan: true,
53316
- installExitCode: code2,
53317
- suppressedByAllowlist: suppressedCount > 0 ? suppressedCount : void 0
53318
- });
53319
- return code2;
53320
- }
53321
- if (result.action === "block") {
53322
- if (parsed.dgForce) {
53361
+ if (!proceed) process.stderr.write(import_chalk19.default.dim(" Install cancelled by user.\n\n"));
53362
+ return proceed;
53363
+ },
53364
+ runInstall: (args2) => spawnRealBinary(adapter7, args2),
53365
+ async audit(kind) {
53323
53366
  try {
53324
53367
  await dispatchInstallAudit({
53325
53368
  ecosystem: adapter7.apiKind,
53326
53369
  packages: result.packages,
53327
- decisionAction: "override",
53328
- bypassed: true,
53329
- bypassReason: parsed.dgForceReason
53370
+ decisionAction: kind,
53371
+ bypassed: kind === "override"
53330
53372
  });
53331
53373
  } catch {
53332
53374
  }
53333
- if (!config.json && !config.quiet) {
53334
- process.stderr.write(import_chalk19.default.yellow.bold(` --dg-force: bypassing block. Install at your own risk.
53335
-
53336
- `));
53337
- }
53338
- const code2 = await spawnRealBinary(adapter7, installArgs);
53339
- emitJson(config, {
53375
+ },
53376
+ emit(record) {
53377
+ emitWrapperJson(config, {
53340
53378
  ecosystem: adapter7.ecosystem,
53341
53379
  packages: packagesFromResult(result, topLevelNames),
53342
- scanVerdict: "override",
53343
- installRan: true,
53344
- installExitCode: code2
53380
+ scanVerdict: record.scanVerdict,
53381
+ installRan: record.installRan,
53382
+ installExitCode: record.installExitCode,
53383
+ error: record.error,
53384
+ suppressedByAllowlist: record.suppressedByAllowlist
53345
53385
  });
53346
- return code2;
53347
- }
53348
- try {
53349
- await dispatchInstallAudit({
53350
- ecosystem: adapter7.apiKind,
53351
- packages: result.packages,
53352
- decisionAction: "block",
53353
- bypassed: false
53354
- });
53355
- } catch {
53356
- }
53357
- const blockedList = resolved.map((p) => `${p.name} ${p.version}`).join(", ");
53358
- if (!config.json) {
53359
- process.stderr.write(
53360
- ` ${import_chalk19.default.red("\u2717")} ${import_chalk19.default.bold("DG blocked")} ${blockedList}.
53361
- Real install was NOT run. To override:
53362
- ` + import_chalk19.default.dim(` ${adapter7.realBinaryName} ${parsed.rawArgs.join(" ")} --dg-force --dg-force-reason="<reason>"
53363
-
53364
- `)
53365
- );
53366
- }
53367
- emitJson(config, {
53368
- ecosystem: adapter7.ecosystem,
53369
- packages: packagesFromResult(result, topLevelNames),
53370
- scanVerdict: "block",
53371
- installRan: false,
53372
- installExitCode: null
53373
- });
53374
- return 2;
53375
- }
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
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);
53404
- emitJson(config, {
53405
- ecosystem: adapter7.ecosystem,
53406
- packages: packagesFromResult(result, topLevelNames),
53407
- scanVerdict: "analysis_incomplete",
53408
- installRan: true,
53409
- installExitCode: code
53410
- });
53411
- return code;
53387
+ };
53388
+ return await executeDecision(decision, ctx, presenter);
53412
53389
  }
53413
53390
  var import_chalk19;
53414
53391
  var init_wrapper_factory = __esm({
@@ -53423,6 +53400,9 @@ var init_wrapper_factory = __esm({
53423
53400
  init_wrapper_shared();
53424
53401
  init_npm_wrapper();
53425
53402
  init_pip_wrapper();
53403
+ init_route();
53404
+ init_run();
53405
+ init_json();
53426
53406
  }
53427
53407
  });
53428
53408
 
@@ -53675,8 +53655,6 @@ async function main() {
53675
53655
  }
53676
53656
  if (result.action === "block") {
53677
53657
  try {
53678
- const reasonIdx = args.indexOf("--dg-force-reason");
53679
- const bypassReason = reasonIdx >= 0 ? args[reasonIdx + 1] : void 0;
53680
53658
  const { dispatchPublishCheckAudit: dispatchPublishCheckAudit2 } = await Promise.resolve().then(() => (init_audit_dispatcher(), audit_dispatcher_exports));
53681
53659
  const at = result.artifact.lastIndexOf("@");
53682
53660
  const pkgName = at > 0 ? result.artifact.slice(0, at) : result.artifact;
@@ -53687,8 +53665,7 @@ async function main() {
53687
53665
  packageVersion: pkgVersion,
53688
53666
  score: result.score,
53689
53667
  decisionAction: force ? "override" : "block",
53690
- bypassed: !!force,
53691
- bypassReason
53668
+ bypassed: !!force
53692
53669
  });
53693
53670
  } catch {
53694
53671
  }
@@ -53860,6 +53837,12 @@ async function main() {
53860
53837
  return;
53861
53838
  }
53862
53839
  }
53840
+ async function runHandoff(handoff) {
53841
+ if (!handoff.install) {
53842
+ return typeof process.exitCode === "number" ? process.exitCode : 0;
53843
+ }
53844
+ return handoff.install.run(handoff.install.args);
53845
+ }
53863
53846
  async function handleWrapInternal(argv) {
53864
53847
  let ecosystem = argv[0];
53865
53848
  if (!ecosystem) {
@@ -53896,9 +53879,9 @@ async function handleWrapInternal(argv) {
53896
53879
  const { isReadonlySubcommand: isReadonlySubcommand2 } = await Promise.resolve().then(() => (init_readonly(), readonly_exports));
53897
53880
  const ecoTyped = ecosystem;
53898
53881
  const spawnReal = async (real, args) => {
53899
- const { spawn: spawn7 } = await import("node:child_process");
53882
+ const { spawn: spawn8 } = await import("node:child_process");
53900
53883
  const { childInstallEnv: childInstallEnv2 } = await Promise.resolve().then(() => (init_install(), install_exports));
53901
- const child = spawn7(real, args, { stdio: "inherit", env: childInstallEnv2() });
53884
+ const child = spawn8(real, args, { stdio: "inherit", env: childInstallEnv2() });
53902
53885
  return await new Promise((resolve3) => {
53903
53886
  child.on("close", (code) => resolve3(code ?? 1));
53904
53887
  child.on("error", () => resolve3(1));
@@ -53925,11 +53908,12 @@ async function handleWrapInternal(argv) {
53925
53908
  const { render: render2 } = await init_build2().then(() => build_exports);
53926
53909
  const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
53927
53910
  const { WrapperApp: WrapperApp2 } = await init_WrapperApp().then(() => WrapperApp_exports);
53911
+ const handoff = { install: null };
53928
53912
  const { waitUntilExit } = render2(
53929
- React22.createElement(WrapperApp2, { config, args: wrapperArgs, ecosystem: "npm" })
53913
+ React22.createElement(WrapperApp2, { config, args: wrapperArgs, ecosystem: "npm", handoff })
53930
53914
  );
53931
53915
  await waitUntilExit();
53932
- return 0;
53916
+ return runHandoff(handoff);
53933
53917
  }
53934
53918
  if (ecosystem === "pip" || ecosystem === "pip3") {
53935
53919
  if (config.json || !process.stdout.isTTY) {
@@ -53940,11 +53924,12 @@ async function handleWrapInternal(argv) {
53940
53924
  const { render: render2 } = await init_build2().then(() => build_exports);
53941
53925
  const React22 = await Promise.resolve().then(() => __toESM(require_react(), 1));
53942
53926
  const { WrapperApp: WrapperApp2 } = await init_WrapperApp().then(() => WrapperApp_exports);
53927
+ const handoff = { install: null };
53943
53928
  const { waitUntilExit } = render2(
53944
- React22.createElement(WrapperApp2, { config, args: wrapperArgs, ecosystem: "pypi" })
53929
+ React22.createElement(WrapperApp2, { config, args: wrapperArgs, ecosystem: "pypi", handoff })
53945
53930
  );
53946
53931
  await waitUntilExit();
53947
- return 0;
53932
+ return runHandoff(handoff);
53948
53933
  }
53949
53934
  if (ecosystem === "conda" || ecosystem === "mamba") {
53950
53935
  const { runStaticConda: runStaticConda2 } = await Promise.resolve().then(() => (init_conda_wrapper(), conda_wrapper_exports));