@westbayberry/dg 2.0.3 → 2.0.4

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/setup/plan.js +24 -5
  2. package/package.json +1 -1
@@ -14,6 +14,8 @@ import { OPTIONAL_SUPPORT_GATES } from "./optional-support.js";
14
14
  export const SHIM_COMMANDS = Object.freeze(["npm", "npx", "pnpm", "pnpx", "yarn", "pip", "pipx", "uv", "uvx", "cargo"]);
15
15
  export const SHIM_SENTINEL = "dg-shim-v1";
16
16
  export const RC_SENTINEL = "dg-shell-rc-v1";
17
+ export const RC_FUNCTIONS_SENTINEL = "dg-shim-functions-v1";
18
+ const RC_SHIM_HELPER = "__dg_shim";
17
19
  export const GUARD_HOOK_SENTINEL = "dg-git-hook-v1";
18
20
  export const RC_BEGIN = "# >>> dg setup >>>";
19
21
  export const RC_END = "# <<< dg setup <<<";
@@ -273,6 +275,7 @@ export function doctorReport(options = {}) {
273
275
  });
274
276
  const rcEntries = registryRead.registry.entries.filter((entry) => entry.owner === "dg" && entry.kind === "rc");
275
277
  const missingRc = rcEntries.filter((entry) => !readText(entry.path).includes(RC_SENTINEL));
278
+ const functionsPresent = rcEntries.some((entry) => readText(entry.path).includes(RC_FUNCTIONS_SENTINEL));
276
279
  checks.push({
277
280
  name: "shell-rc",
278
281
  status: rcEntries.length > 0 && missingRc.length === 0 ? "pass" : "warn",
@@ -286,7 +289,7 @@ export function doctorReport(options = {}) {
286
289
  ? "No legacy dg pip hooks in user site-packages"
287
290
  : `Legacy dg pip hooks break pip in: ${staleHookSites.join(", ")}`
288
291
  });
289
- checks.push(pathPrecedenceCheck(env, shimDir));
292
+ checks.push(pathPrecedenceCheck(env, shimDir, functionsPresent));
290
293
  checks.push({
291
294
  name: "stale-sessions",
292
295
  status: staleSessions.length === 0 ? "pass" : "warn",
@@ -510,11 +513,20 @@ function withRcBlock(existing, plan) {
510
513
  const prefix = withoutExisting.length > 0 && !withoutExisting.endsWith("\n") ? `${withoutExisting}\n` : withoutExisting;
511
514
  return `${prefix}${block}`;
512
515
  }
516
+ // The PATH export covers child processes that inherit it; the shell functions
517
+ // win even when a virtualenv prepends its own bin ahead of the shim dir, since
518
+ // a function is resolved before PATH. Each delegates to the fail-open shim and
519
+ // falls back to the real command if the shim is gone.
513
520
  function posixRcBlock(shimDir) {
514
- return `${RC_BEGIN}\n# ${RC_SENTINEL}\nexport PATH="${escapeDoubleQuotedSh(shimDir)}:$PATH"\n${RC_END}\n`;
521
+ const dir = escapeDoubleQuotedSh(shimDir);
522
+ const helper = `${RC_SHIM_HELPER}() { local __dg_c="$1"; shift; if [ -x "${dir}/$__dg_c" ]; then "${dir}/$__dg_c" "$@"; else command "$__dg_c" "$@"; fi; }`;
523
+ const fns = SHIM_COMMANDS.map((command) => `${command}() { ${RC_SHIM_HELPER} ${command} "$@"; }`).join("\n");
524
+ return `${RC_BEGIN}\n# ${RC_SENTINEL}\n# ${RC_FUNCTIONS_SENTINEL}\nexport PATH="${dir}:$PATH"\n${helper}\n${fns}\n${RC_END}\n`;
515
525
  }
516
526
  function fishRcBlock(shimDir) {
517
- return `${RC_BEGIN}\n# ${RC_SENTINEL}\nfish_add_path -p "${escapeDoubleQuotedFish(shimDir)}"\n${RC_END}\n`;
527
+ const dir = escapeDoubleQuotedFish(shimDir);
528
+ const fns = SHIM_COMMANDS.map((command) => `function ${command}; if test -x "${dir}/${command}"; "${dir}/${command}" $argv; else; command ${command} $argv; end; end`).join("\n");
529
+ return `${RC_BEGIN}\n# ${RC_SENTINEL}\n# ${RC_FUNCTIONS_SENTINEL}\nfish_add_path -p "${dir}"\n${fns}\n${RC_END}\n`;
518
530
  }
519
531
  function stripRcBlock(existing) {
520
532
  const pattern = new RegExp(`${escapeRegex(RC_BEGIN)}\\n[\\s\\S]*?${escapeRegex(RC_END)}\\n?`, "g");
@@ -778,7 +790,7 @@ function serviceCheck(env) {
778
790
  message: `Service mode is running at ${state.proxy.proxyUrl}; trust installed: ${state.trustInstalled ? "yes" : "no"}`
779
791
  };
780
792
  }
781
- function pathPrecedenceCheck(env, shimDir) {
793
+ function pathPrecedenceCheck(env, shimDir, functionsPresent) {
782
794
  const pathEntries = (env.PATH ?? "").split(delimiter).filter(Boolean);
783
795
  const shimIndex = pathEntries.indexOf(shimDir);
784
796
  const activateFix = `activate this shell: ${currentShellActivation(env)} — or open a new terminal`;
@@ -812,11 +824,18 @@ function pathPrecedenceCheck(env, shimDir) {
812
824
  };
813
825
  }
814
826
  if (offender) {
827
+ if (functionsPresent) {
828
+ return {
829
+ name: "path",
830
+ status: "pass",
831
+ message: `${offender.dir} resolves ${offender.command} first (e.g. an active virtualenv); dg shell functions intercept bare installs regardless`
832
+ };
833
+ }
815
834
  return {
816
835
  name: "path",
817
836
  status: "warn",
818
837
  message: `${shimDir} is on PATH but ${offender.dir} resolves ${offender.command} first`,
819
- fix: activateFix
838
+ fix: `re-run dg setup to intercept inside virtualenvs — or ${activateFix}`
820
839
  };
821
840
  }
822
841
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@westbayberry/dg",
3
- "version": "2.0.3",
3
+ "version": "2.0.4",
4
4
  "description": "Dependency Guardian supply-chain firewall CLI",
5
5
  "type": "module",
6
6
  "bin": {