@westbayberry/dg 1.3.2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -201
- package/NOTICE +1 -4
- package/README.md +293 -0
- package/dist/api/analyze.js +210 -0
- package/dist/audit/deep.js +180 -0
- package/dist/audit/detectors.js +247 -0
- package/dist/audit/events.js +41 -0
- package/dist/audit/rules.js +426 -0
- package/dist/audit-ui/AuditApp.js +39 -0
- package/dist/audit-ui/components/AuditHeader.js +24 -0
- package/dist/audit-ui/components/AuditResultsView.js +307 -0
- package/dist/audit-ui/components/DeepStatusRow.js +11 -0
- package/dist/audit-ui/export.js +85 -0
- package/dist/audit-ui/format.js +34 -0
- package/dist/audit-ui/launch.js +34 -0
- package/dist/auth/device-login.js +271 -0
- package/dist/auth/env-token.js +6 -0
- package/dist/auth/login-app.js +156 -0
- package/dist/auth/store.js +147 -0
- package/dist/bin/dg.js +71 -0
- package/dist/commands/audit.js +357 -0
- package/dist/commands/completion.js +116 -0
- package/dist/commands/config.js +99 -0
- package/dist/commands/doctor.js +39 -0
- package/dist/commands/explain.js +100 -0
- package/dist/commands/guard-commit.js +158 -0
- package/dist/commands/help.js +74 -0
- package/dist/commands/licenses.js +435 -0
- package/dist/commands/login.js +81 -0
- package/dist/commands/logout.js +37 -0
- package/dist/commands/router.js +98 -0
- package/dist/commands/scan.js +18 -0
- package/dist/commands/service.js +475 -0
- package/dist/commands/setup.js +302 -0
- package/dist/commands/status.js +115 -0
- package/dist/commands/suggest.js +35 -0
- package/dist/commands/types.js +4 -0
- package/dist/commands/unavailable.js +11 -0
- package/dist/commands/uninstall.js +111 -0
- package/dist/commands/update.js +210 -0
- package/dist/commands/verify.js +151 -0
- package/dist/commands/version.js +22 -0
- package/dist/commands/wrap.js +55 -0
- package/dist/config/settings.js +302 -0
- package/dist/install-ui/LiveInstall.js +24 -0
- package/dist/install-ui/block-render.js +83 -0
- package/dist/install-ui/live-install-app.js +48 -0
- package/dist/install-ui/prompt.js +24 -0
- package/dist/launcher/classify.js +116 -0
- package/dist/launcher/env.js +53 -0
- package/dist/launcher/live-install.js +50 -0
- package/dist/launcher/output-redaction.js +77 -0
- package/dist/launcher/preflight-prompt.js +139 -0
- package/dist/launcher/resolve-real-binary.js +73 -0
- package/dist/launcher/run.js +417 -0
- package/dist/policy/evaluate.js +128 -0
- package/dist/presentation/mode.js +52 -0
- package/dist/presentation/theme.js +29 -0
- package/dist/proxy/buffer-budget.js +64 -0
- package/dist/proxy/ca.js +126 -0
- package/dist/proxy/classify-host.js +26 -0
- package/dist/proxy/enforcement.js +102 -0
- package/dist/proxy/metadata-map.js +336 -0
- package/dist/proxy/server.js +909 -0
- package/dist/proxy/upstream-proxy.js +102 -0
- package/dist/proxy/worker.js +39 -0
- package/dist/publish-set/collect.js +51 -0
- package/dist/publish-set/no-exec-shell.js +19 -0
- package/dist/publish-set/npm.js +109 -0
- package/dist/publish-set/pack.js +36 -0
- package/dist/publish-set/pypi.js +59 -0
- package/dist/runtime/cli.js +17 -0
- package/dist/runtime/first-run.js +60 -0
- package/dist/runtime/node-version.js +58 -0
- package/dist/runtime/nudges.js +105 -0
- package/dist/scan/analyze-worker.js +21 -0
- package/dist/scan/collect.js +153 -0
- package/dist/scan/command.js +159 -0
- package/dist/scan/discovery.js +209 -0
- package/dist/scan/render.js +240 -0
- package/dist/scan/scanner-report.js +82 -0
- package/dist/scan/staged.js +173 -0
- package/dist/scan/types.js +1 -0
- package/dist/scan-ui/LegacyApp.js +156 -0
- package/dist/scan-ui/alt-screen.js +84 -0
- package/dist/scan-ui/api-aliases.js +1 -0
- package/dist/scan-ui/components/ErrorView.js +23 -0
- package/dist/scan-ui/components/InteractiveResultsView.js +1166 -0
- package/dist/scan-ui/components/ProgressBar.js +89 -0
- package/dist/scan-ui/components/ProjectSelector.js +62 -0
- package/dist/scan-ui/components/ScoreHeader.js +20 -0
- package/dist/scan-ui/components/SetupBanner.js +13 -0
- package/dist/scan-ui/components/Spinner.js +4 -0
- package/dist/scan-ui/format-helpers.js +40 -0
- package/dist/scan-ui/hooks/useExpandAnimation.js +40 -0
- package/dist/scan-ui/hooks/useScan.js +113 -0
- package/dist/scan-ui/hooks/useTerminalSize.js +24 -0
- package/dist/scan-ui/launch.js +27 -0
- package/dist/scan-ui/logo.js +91 -0
- package/dist/scan-ui/shims.js +30 -0
- package/dist/security/sanitize.js +28 -0
- package/dist/service/state.js +837 -0
- package/dist/service/trust-store.js +234 -0
- package/dist/service/worker.js +88 -0
- package/dist/setup/git-hook.js +244 -0
- package/dist/setup/optional-support.js +58 -0
- package/dist/setup/plan.js +899 -0
- package/dist/state/cleanup-registry.js +60 -0
- package/dist/state/index.js +5 -0
- package/dist/state/locks.js +161 -0
- package/dist/state/paths.js +24 -0
- package/dist/state/sessions.js +170 -0
- package/dist/state/store.js +50 -0
- package/dist/telemetry/events.js +40 -0
- package/dist/util/git.js +20 -0
- package/dist/util/tty-prompt.js +43 -0
- package/dist/verify/local.js +400 -0
- package/dist/verify/package-check.js +240 -0
- package/dist/verify/preflight.js +698 -0
- package/dist/verify/render.js +184 -0
- package/dist/verify/types.js +1 -0
- package/package.json +33 -50
- package/dist/index.mjs +0 -54141
- package/dist/postinstall.mjs +0 -731
- package/dist/python-hook/dg_pip_hook.pth +0 -1
- package/dist/python-hook/dg_pip_hook.py +0 -130
package/dist/postinstall.mjs
DELETED
|
@@ -1,731 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// src/postinstall.ts
|
|
3
|
-
import { homedir as homedir7, userInfo } from "node:os";
|
|
4
|
-
|
|
5
|
-
// src/shims/install.ts
|
|
6
|
-
import { homedir as homedir5 } from "node:os";
|
|
7
|
-
import { join as join4, dirname as dirname2 } from "node:path";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
|
-
import { chmodSync, chownSync, existsSync as existsSync4, readdirSync, readFileSync as readFileSync3, statSync as statSync2, appendFileSync as appendFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
10
|
-
import { spawnSync } from "node:child_process";
|
|
11
|
-
import { randomBytes } from "node:crypto";
|
|
12
|
-
|
|
13
|
-
// src/paths.ts
|
|
14
|
-
import { homedir } from "node:os";
|
|
15
|
-
import { join, isAbsolute } from "node:path";
|
|
16
|
-
var ROOT_DIR_NAME = "dg";
|
|
17
|
-
function safeAbsolute(p, fallback) {
|
|
18
|
-
if (!p || typeof p !== "string") return fallback;
|
|
19
|
-
if (!isAbsolute(p)) return fallback;
|
|
20
|
-
return p;
|
|
21
|
-
}
|
|
22
|
-
function dgRoot() {
|
|
23
|
-
return join(homedir(), `.${ROOT_DIR_NAME}`);
|
|
24
|
-
}
|
|
25
|
-
function dgStateDir() {
|
|
26
|
-
const xdg = safeAbsolute(process.env.XDG_STATE_HOME, "");
|
|
27
|
-
if (xdg) return join(xdg, ROOT_DIR_NAME);
|
|
28
|
-
return join(dgRoot(), "state");
|
|
29
|
-
}
|
|
30
|
-
function dgStatePath(name) {
|
|
31
|
-
return join(dgStateDir(), name);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// src/shims/safe-fs.ts
|
|
35
|
-
import { existsSync, lstatSync, mkdirSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
36
|
-
import { dirname, sep } from "node:path";
|
|
37
|
-
import { homedir as homedir2 } from "node:os";
|
|
38
|
-
var UnsafePathError = class extends Error {
|
|
39
|
-
constructor(message, path) {
|
|
40
|
-
super(message);
|
|
41
|
-
this.path = path;
|
|
42
|
-
this.name = "UnsafePathError";
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
function ensureUnderHome(target) {
|
|
46
|
-
const home = homedir2();
|
|
47
|
-
if (target !== home && !target.startsWith(home + sep)) {
|
|
48
|
-
throw new UnsafePathError(`refusing to operate on path outside $HOME: ${target}`, target);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function lstatNoSymlink(path) {
|
|
52
|
-
let st;
|
|
53
|
-
try {
|
|
54
|
-
st = lstatSync(path);
|
|
55
|
-
} catch (e) {
|
|
56
|
-
const code = e.code;
|
|
57
|
-
if (code === "ENOENT") return;
|
|
58
|
-
throw e;
|
|
59
|
-
}
|
|
60
|
-
if (st.isSymbolicLink()) {
|
|
61
|
-
throw new UnsafePathError(`refusing: ${path} is a symlink`, path);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
function safeMkdirRecursive(target, mode = 493) {
|
|
65
|
-
ensureUnderHome(target);
|
|
66
|
-
const home = homedir2();
|
|
67
|
-
const rel = target.slice(home.length).split(sep).filter(Boolean);
|
|
68
|
-
let cur = home;
|
|
69
|
-
for (const segment of rel) {
|
|
70
|
-
cur = cur + sep + segment;
|
|
71
|
-
lstatNoSymlink(cur);
|
|
72
|
-
if (!existsSync(cur)) {
|
|
73
|
-
mkdirSync(cur, { mode });
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function safeWriteFile(target, content, mode = 420) {
|
|
78
|
-
ensureUnderHome(target);
|
|
79
|
-
lstatNoSymlink(dirname(target));
|
|
80
|
-
lstatNoSymlink(target);
|
|
81
|
-
writeFileSync(target, content, { mode });
|
|
82
|
-
}
|
|
83
|
-
function atomicWriteFile(target, content, mode = 420) {
|
|
84
|
-
ensureUnderHome(target);
|
|
85
|
-
lstatNoSymlink(dirname(target));
|
|
86
|
-
lstatNoSymlink(target);
|
|
87
|
-
const tmp = `${target}.tmp.${process.pid}.${Date.now()}`;
|
|
88
|
-
writeFileSync(tmp, content, { mode });
|
|
89
|
-
renameSync(tmp, target);
|
|
90
|
-
}
|
|
91
|
-
function isExecutable(path) {
|
|
92
|
-
try {
|
|
93
|
-
const st = statSync(path);
|
|
94
|
-
return st.isFile() && (st.mode & 73) !== 0;
|
|
95
|
-
} catch {
|
|
96
|
-
return false;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// src/shims/templates.ts
|
|
101
|
-
var ECOSYSTEMS = [
|
|
102
|
-
"npm",
|
|
103
|
-
"pnpm",
|
|
104
|
-
"yarn",
|
|
105
|
-
"bun",
|
|
106
|
-
"pip",
|
|
107
|
-
"pip3",
|
|
108
|
-
"uv",
|
|
109
|
-
"pipx",
|
|
110
|
-
"conda",
|
|
111
|
-
"mamba"
|
|
112
|
-
];
|
|
113
|
-
var UNIX_SHIM_BODY = `#!/bin/sh
|
|
114
|
-
nonce=$(cat "$HOME/.dg/state/shim-nonce" 2>/dev/null)
|
|
115
|
-
if [ -n "\${DG_SHIM_ACTIVE:-}" ]; then
|
|
116
|
-
cleaned_path=$(printf '%s' "$PATH" | awk -v RS=':' -v ORS=':' '$0 != ENVIRON["HOME"]"/.dg/shims"' | sed 's/:$//')
|
|
117
|
-
# Only honor DG_SHIM_ACTIVE as the recursion guard when it equals the
|
|
118
|
-
# on-disk nonce \u2014 that is the value our own wrapper sets before running the
|
|
119
|
-
# real installer. A non-matching value was set outside dg (stale or a
|
|
120
|
-
# bypass attempt) and must NOT skip scanning.
|
|
121
|
-
if [ -n "$nonce" ] && [ "$DG_SHIM_ACTIVE" = "$nonce" ]; then
|
|
122
|
-
real_bin=$(PATH="$cleaned_path" command -v __ECOSYSTEM__)
|
|
123
|
-
if [ -n "$real_bin" ]; then
|
|
124
|
-
exec "$real_bin" "$@"
|
|
125
|
-
fi
|
|
126
|
-
echo "dg: real __ECOSYSTEM__ not found on PATH" >&2
|
|
127
|
-
exit 127
|
|
128
|
-
fi
|
|
129
|
-
if [ -z "$nonce" ]; then
|
|
130
|
-
echo "dg: shim nonce missing (reinstall dg) \u2014 cannot verify; passing through __ECOSYSTEM__ UNSCANNED." >&2
|
|
131
|
-
real_bin=$(PATH="$cleaned_path" command -v __ECOSYSTEM__)
|
|
132
|
-
if [ -n "$real_bin" ]; then exec "$real_bin" "$@"; fi
|
|
133
|
-
exit 127
|
|
134
|
-
fi
|
|
135
|
-
echo "dg: ignoring externally-set DG_SHIM_ACTIVE (nonce mismatch); scanning __ECOSYSTEM__." >&2
|
|
136
|
-
fi
|
|
137
|
-
dg_entry=$(cat "$HOME/.dg/state/dg-entry" 2>/dev/null)
|
|
138
|
-
if [ -n "$dg_entry" ] && [ -x "$dg_entry" ]; then
|
|
139
|
-
DG_SHIM_ACTIVE="$nonce" DG_SHIM_PARENT_PATH="$PATH" exec "$dg_entry" __wrap __ECOSYSTEM__ "$@"
|
|
140
|
-
fi
|
|
141
|
-
cleaned_path=$(printf '%s' "$PATH" | awk -v RS=':' -v ORS=':' '$0 != ENVIRON["HOME"]"/.dg/shims"' | sed 's/:$//')
|
|
142
|
-
dg_bin=$(PATH="$cleaned_path" command -v dg)
|
|
143
|
-
if [ -n "$dg_bin" ]; then
|
|
144
|
-
DG_SHIM_ACTIVE="$nonce" DG_SHIM_PARENT_PATH="$PATH" exec "$dg_bin" __wrap __ECOSYSTEM__ "$@"
|
|
145
|
-
fi
|
|
146
|
-
real_bin=$(PATH="$cleaned_path" command -v __ECOSYSTEM__)
|
|
147
|
-
if [ -n "$real_bin" ]; then
|
|
148
|
-
printf '%s dg unresolved; passthrough __ECOSYSTEM__\\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ 2>/dev/null)" >> "$HOME/.dg/state/bypass.log" 2>/dev/null
|
|
149
|
-
exec "$real_bin" "$@"
|
|
150
|
-
fi
|
|
151
|
-
echo "dg: neither dg nor real __ECOSYSTEM__ found on PATH" >&2
|
|
152
|
-
exit 127
|
|
153
|
-
`;
|
|
154
|
-
var WINDOWS_SHIM_BODY = `@echo off
|
|
155
|
-
setlocal enabledelayedexpansion
|
|
156
|
-
set "DG_SHIM_NONCE="
|
|
157
|
-
if exist "%USERPROFILE%\\.dg\\state\\shim-nonce" set /p DG_SHIM_NONCE=<"%USERPROFILE%\\.dg\\state\\shim-nonce"
|
|
158
|
-
if not "%DG_SHIM_ACTIVE%"=="" (
|
|
159
|
-
set "_dg_realpath="
|
|
160
|
-
for /f "tokens=*" %%i in ('where __ECOSYSTEM__ 2^>nul') do (
|
|
161
|
-
echo %%i | findstr /v /c:"%USERPROFILE%\\.dg\\shims" >nul && (
|
|
162
|
-
if not defined _dg_realpath set "_dg_realpath=%%i"
|
|
163
|
-
)
|
|
164
|
-
)
|
|
165
|
-
rem Only honor DG_SHIM_ACTIVE as the recursion guard when it equals the nonce.
|
|
166
|
-
if "%DG_SHIM_ACTIVE%"=="!DG_SHIM_NONCE!" (
|
|
167
|
-
if defined _dg_realpath (
|
|
168
|
-
"!_dg_realpath!" %*
|
|
169
|
-
exit /b !errorlevel!
|
|
170
|
-
)
|
|
171
|
-
echo dg: real __ECOSYSTEM__ not found on PATH 1>&2
|
|
172
|
-
exit /b 127
|
|
173
|
-
)
|
|
174
|
-
if "!DG_SHIM_NONCE!"=="" (
|
|
175
|
-
echo dg: shim nonce missing ^(reinstall dg^) -- passing through __ECOSYSTEM__ UNSCANNED. 1>&2
|
|
176
|
-
if defined _dg_realpath (
|
|
177
|
-
"!_dg_realpath!" %*
|
|
178
|
-
exit /b !errorlevel!
|
|
179
|
-
)
|
|
180
|
-
exit /b 127
|
|
181
|
-
)
|
|
182
|
-
echo dg: ignoring externally-set DG_SHIM_ACTIVE ^(nonce mismatch^); scanning __ECOSYSTEM__. 1>&2
|
|
183
|
-
)
|
|
184
|
-
set "DG_ENTRY="
|
|
185
|
-
if exist "%USERPROFILE%\\.dg\\state\\dg-entry" set /p DG_ENTRY=<"%USERPROFILE%\\.dg\\state\\dg-entry"
|
|
186
|
-
set "DG_SHIM_ACTIVE=!DG_SHIM_NONCE!"
|
|
187
|
-
set "DG_SHIM_PARENT_PATH=%PATH%"
|
|
188
|
-
if defined DG_ENTRY (
|
|
189
|
-
if exist "!DG_ENTRY!" (
|
|
190
|
-
node "!DG_ENTRY!" __wrap __ECOSYSTEM__ %*
|
|
191
|
-
exit /b !errorlevel!
|
|
192
|
-
)
|
|
193
|
-
)
|
|
194
|
-
set "_dg_cli="
|
|
195
|
-
for /f "tokens=*" %%i in ('where dg 2^>nul') do (
|
|
196
|
-
echo %%i | findstr /v /c:"%USERPROFILE%\\.dg\\shims" >nul && (
|
|
197
|
-
if not defined _dg_cli set "_dg_cli=%%i"
|
|
198
|
-
)
|
|
199
|
-
)
|
|
200
|
-
if defined _dg_cli (
|
|
201
|
-
"!_dg_cli!" __wrap __ECOSYSTEM__ %*
|
|
202
|
-
exit /b !errorlevel!
|
|
203
|
-
)
|
|
204
|
-
set "_dg_realpm="
|
|
205
|
-
for /f "tokens=*" %%i in ('where __ECOSYSTEM__ 2^>nul') do (
|
|
206
|
-
echo %%i | findstr /v /c:"%USERPROFILE%\\.dg\\shims" >nul && (
|
|
207
|
-
if not defined _dg_realpm set "_dg_realpm=%%i"
|
|
208
|
-
)
|
|
209
|
-
)
|
|
210
|
-
if defined _dg_realpm (
|
|
211
|
-
>>"%USERPROFILE%\\.dg\\state\\bypass.log" echo dg unresolved; passthrough __ECOSYSTEM__
|
|
212
|
-
"!_dg_realpm!" %*
|
|
213
|
-
exit /b !errorlevel!
|
|
214
|
-
)
|
|
215
|
-
echo dg: neither dg nor real __ECOSYSTEM__ found on PATH 1>&2
|
|
216
|
-
exit /b 127
|
|
217
|
-
`;
|
|
218
|
-
function renderShim(opts) {
|
|
219
|
-
const body = opts.platform === "windows" ? WINDOWS_SHIM_BODY : UNIX_SHIM_BODY;
|
|
220
|
-
return body.replace(/__ECOSYSTEM__/g, opts.ecosystem);
|
|
221
|
-
}
|
|
222
|
-
function shimFilename(ecosystem, platform) {
|
|
223
|
-
return platform === "windows" ? `${ecosystem}.cmd` : ecosystem;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// src/shims/rc-syntax.ts
|
|
227
|
-
import { homedir as homedir3 } from "node:os";
|
|
228
|
-
import { join as join2 } from "node:path";
|
|
229
|
-
import { existsSync as existsSync2, readFileSync, lstatSync as lstatSync2, appendFileSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
230
|
-
var RC_SENTINEL_OPEN = "# >>> dg-managed >>>";
|
|
231
|
-
var RC_SENTINEL_CLOSE = "# <<< dg-managed <<<";
|
|
232
|
-
function expandHome(path) {
|
|
233
|
-
if (path.startsWith("~/")) return join2(homedir3(), path.slice(2));
|
|
234
|
-
return path;
|
|
235
|
-
}
|
|
236
|
-
function detectShellKind(envShell) {
|
|
237
|
-
const s = (envShell ?? "").toLowerCase();
|
|
238
|
-
if (s.includes("zsh")) return "zsh";
|
|
239
|
-
if (s.includes("fish")) return "fish";
|
|
240
|
-
if (s.includes("bash")) return "bash";
|
|
241
|
-
return "sh";
|
|
242
|
-
}
|
|
243
|
-
function rcCandidates(kind) {
|
|
244
|
-
const home = homedir3();
|
|
245
|
-
switch (kind) {
|
|
246
|
-
case "zsh":
|
|
247
|
-
return [join2(home, ".zshrc")];
|
|
248
|
-
case "bash":
|
|
249
|
-
return [join2(home, ".bashrc"), join2(home, ".bash_profile")];
|
|
250
|
-
case "fish":
|
|
251
|
-
return [join2(home, ".config", "fish", "config.fish")];
|
|
252
|
-
case "sh":
|
|
253
|
-
return [join2(home, ".profile")];
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
function pathSnippet(kind) {
|
|
257
|
-
if (kind === "fish") {
|
|
258
|
-
return 'set -gx PATH "$HOME/.dg/shims" $PATH';
|
|
259
|
-
}
|
|
260
|
-
return 'export PATH="$HOME/.dg/shims:$PATH"';
|
|
261
|
-
}
|
|
262
|
-
function appendSentinelBlock(rcPath, snippet) {
|
|
263
|
-
const resolved = expandHome(rcPath);
|
|
264
|
-
try {
|
|
265
|
-
ensureUnderHome(resolved);
|
|
266
|
-
} catch (e) {
|
|
267
|
-
return { status: "failed", path: resolved, reason: e.message };
|
|
268
|
-
}
|
|
269
|
-
try {
|
|
270
|
-
lstatNoSymlink(resolved);
|
|
271
|
-
} catch (e) {
|
|
272
|
-
if (e instanceof UnsafePathError) {
|
|
273
|
-
return { status: "failed", path: resolved, reason: e.message };
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (existsSync2(resolved)) {
|
|
277
|
-
const st = lstatSync2(resolved);
|
|
278
|
-
if (!st.isFile()) {
|
|
279
|
-
return { status: "failed", path: resolved, reason: "rc path is not a regular file" };
|
|
280
|
-
}
|
|
281
|
-
const existing = readFileSync(resolved, "utf-8");
|
|
282
|
-
if (existing.includes(RC_SENTINEL_OPEN)) {
|
|
283
|
-
return { status: "already-present", path: resolved };
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
const block = `
|
|
287
|
-
${RC_SENTINEL_OPEN}
|
|
288
|
-
${snippet}
|
|
289
|
-
${RC_SENTINEL_CLOSE}
|
|
290
|
-
`;
|
|
291
|
-
try {
|
|
292
|
-
if (existsSync2(resolved)) {
|
|
293
|
-
appendFileSync(resolved, block, { encoding: "utf-8" });
|
|
294
|
-
} else {
|
|
295
|
-
writeFileSync2(resolved, block, { encoding: "utf-8", mode: 420 });
|
|
296
|
-
}
|
|
297
|
-
return { status: "appended", path: resolved };
|
|
298
|
-
} catch (e) {
|
|
299
|
-
return { status: "failed", path: resolved, reason: e.message };
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// src/shims/resolve.ts
|
|
304
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "node:fs";
|
|
305
|
-
import { join as join3, delimiter, sep as sep2 } from "node:path";
|
|
306
|
-
import { homedir as homedir4 } from "node:os";
|
|
307
|
-
var CACHE_PATH = () => dgStatePath("real-binaries.json");
|
|
308
|
-
var NO_CACHE = /* @__PURE__ */ new Set(["pip", "pip3"]);
|
|
309
|
-
function shimDir() {
|
|
310
|
-
return join3(homedir4(), ".dg", "shims");
|
|
311
|
-
}
|
|
312
|
-
function walkPathExcludingShimDir(name, extraExtensions = []) {
|
|
313
|
-
const raw = process.env.PATH ?? "/usr/bin:/bin";
|
|
314
|
-
const parts = raw.split(delimiter).filter(Boolean);
|
|
315
|
-
const shims = shimDir();
|
|
316
|
-
const exts = extraExtensions.length > 0 ? extraExtensions : platformExtensions();
|
|
317
|
-
for (const dir of parts) {
|
|
318
|
-
if (dir === shims || dir.startsWith(shims + sep2)) continue;
|
|
319
|
-
for (const ext of ["", ...exts]) {
|
|
320
|
-
const candidate = join3(dir, name + ext);
|
|
321
|
-
if (isExecutable(candidate)) return candidate;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
return null;
|
|
325
|
-
}
|
|
326
|
-
function walkPath(name, extraExtensions) {
|
|
327
|
-
return walkPathExcludingShimDir(name, extraExtensions);
|
|
328
|
-
}
|
|
329
|
-
function platformExtensions() {
|
|
330
|
-
if (process.platform === "win32") return [".cmd", ".exe", ".bat"];
|
|
331
|
-
return [];
|
|
332
|
-
}
|
|
333
|
-
function readCache() {
|
|
334
|
-
try {
|
|
335
|
-
const raw = readFileSync2(CACHE_PATH(), "utf-8");
|
|
336
|
-
const parsed = JSON.parse(raw);
|
|
337
|
-
if (typeof parsed === "object" && parsed !== null) {
|
|
338
|
-
return parsed;
|
|
339
|
-
}
|
|
340
|
-
} catch {
|
|
341
|
-
}
|
|
342
|
-
return {};
|
|
343
|
-
}
|
|
344
|
-
function writeCache(cache) {
|
|
345
|
-
try {
|
|
346
|
-
atomicWriteFile(CACHE_PATH(), JSON.stringify(cache, null, 2), 420);
|
|
347
|
-
} catch {
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
function resolveRealBinary(ecosystem) {
|
|
351
|
-
const exts = platformExtensions();
|
|
352
|
-
if (NO_CACHE.has(ecosystem)) {
|
|
353
|
-
return walkPath(ecosystem, exts);
|
|
354
|
-
}
|
|
355
|
-
const cache = readCache();
|
|
356
|
-
const cached = cache[ecosystem];
|
|
357
|
-
if (cached && existsSync3(cached) && isExecutable(cached)) {
|
|
358
|
-
return cached;
|
|
359
|
-
}
|
|
360
|
-
const resolved = walkPath(ecosystem, exts);
|
|
361
|
-
if (resolved) {
|
|
362
|
-
cache[ecosystem] = resolved;
|
|
363
|
-
writeCache(cache);
|
|
364
|
-
} else if (cached) {
|
|
365
|
-
delete cache[ecosystem];
|
|
366
|
-
writeCache(cache);
|
|
367
|
-
}
|
|
368
|
-
return resolved;
|
|
369
|
-
}
|
|
370
|
-
function clearResolveCache() {
|
|
371
|
-
try {
|
|
372
|
-
atomicWriteFile(CACHE_PATH(), JSON.stringify({}, null, 2), 420);
|
|
373
|
-
} catch {
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
function realBinaryCachePath() {
|
|
377
|
-
return CACHE_PATH();
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// src/shims/install.ts
|
|
381
|
-
function currentDgEntry() {
|
|
382
|
-
try {
|
|
383
|
-
const entry = join4(dirname2(fileURLToPath(import.meta.url)), "index.mjs");
|
|
384
|
-
if (existsSync4(entry)) return entry;
|
|
385
|
-
} catch {
|
|
386
|
-
}
|
|
387
|
-
try {
|
|
388
|
-
return walkPathExcludingShimDir("dg");
|
|
389
|
-
} catch {
|
|
390
|
-
return null;
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
function chownIfNeeded(path, uid, gid) {
|
|
394
|
-
if (uid === void 0 || gid === void 0) return;
|
|
395
|
-
if (process.platform === "win32") return;
|
|
396
|
-
try {
|
|
397
|
-
chownSync(path, uid, gid);
|
|
398
|
-
} catch {
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
function persistWindowsPath(shimsDir, outcomes) {
|
|
402
|
-
if (process.platform !== "win32") return;
|
|
403
|
-
const currentPath = process.env.PATH ?? "";
|
|
404
|
-
if (currentPath.toLowerCase().includes(shimsDir.toLowerCase())) {
|
|
405
|
-
outcomes.push({ status: "already-present", path: "user PATH (HKCU\\Environment)" });
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
try {
|
|
409
|
-
const result = spawnSync("setx", ["PATH", `${shimsDir};${currentPath}`], { stdio: ["ignore", "pipe", "pipe"] });
|
|
410
|
-
if (result.status === 0) {
|
|
411
|
-
outcomes.push({ status: "appended", path: "user PATH (HKCU\\Environment)" });
|
|
412
|
-
} else {
|
|
413
|
-
outcomes.push({
|
|
414
|
-
status: "failed",
|
|
415
|
-
path: "user PATH (HKCU\\Environment)",
|
|
416
|
-
reason: result.stderr.toString().trim() || `setx exited ${result.status}`
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
} catch (e) {
|
|
420
|
-
outcomes.push({
|
|
421
|
-
status: "failed",
|
|
422
|
-
path: "user PATH (HKCU\\Environment)",
|
|
423
|
-
reason: e.message
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
function updatePowerShellProfile(targetHome, shimsDir, outcomes) {
|
|
428
|
-
if (process.platform !== "win32") return;
|
|
429
|
-
const profilePath = join4(targetHome, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1");
|
|
430
|
-
if (!existsSync4(profilePath)) {
|
|
431
|
-
outcomes.push({ status: "already-present", path: profilePath });
|
|
432
|
-
return;
|
|
433
|
-
}
|
|
434
|
-
try {
|
|
435
|
-
const existing = readFileSync3(profilePath, "utf-8");
|
|
436
|
-
if (existing.includes(">>> dg-managed >>>")) {
|
|
437
|
-
outcomes.push({ status: "already-present", path: profilePath });
|
|
438
|
-
return;
|
|
439
|
-
}
|
|
440
|
-
const block = `
|
|
441
|
-
# >>> dg-managed >>>
|
|
442
|
-
$env:Path = "${shimsDir};$env:Path"
|
|
443
|
-
# <<< dg-managed <<<
|
|
444
|
-
`;
|
|
445
|
-
appendFileSync2(profilePath, block, { encoding: "utf-8" });
|
|
446
|
-
outcomes.push({ status: "appended", path: profilePath });
|
|
447
|
-
} catch (e) {
|
|
448
|
-
outcomes.push({ status: "failed", path: profilePath, reason: e.message });
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
function chownTreeIfNeeded(root, uid, gid) {
|
|
452
|
-
if (uid === void 0 || gid === void 0) return;
|
|
453
|
-
if (process.platform === "win32") return;
|
|
454
|
-
if (!existsSync4(root)) return;
|
|
455
|
-
chownIfNeeded(root, uid, gid);
|
|
456
|
-
try {
|
|
457
|
-
for (const entry of readdirSync(root)) {
|
|
458
|
-
const child = join4(root, entry);
|
|
459
|
-
const st = statSync2(child);
|
|
460
|
-
if (st.isDirectory()) {
|
|
461
|
-
chownTreeIfNeeded(child, uid, gid);
|
|
462
|
-
} else {
|
|
463
|
-
chownIfNeeded(child, uid, gid);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
} catch {
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
function installShims(opts = {}) {
|
|
470
|
-
const targetHome = opts.targetHome ?? homedir5();
|
|
471
|
-
const platform = opts.platform ?? (process.platform === "win32" ? "windows" : "unix");
|
|
472
|
-
const dgRoot2 = join4(targetHome, ".dg");
|
|
473
|
-
const shimsDir = join4(targetHome, ".dg", "shims");
|
|
474
|
-
const stateDir = join4(targetHome, ".dg", "state");
|
|
475
|
-
safeMkdirRecursive(dgRoot2, 493);
|
|
476
|
-
safeMkdirRecursive(stateDir, 493);
|
|
477
|
-
safeMkdirRecursive(shimsDir, 493);
|
|
478
|
-
const nonce = randomBytes(16).toString("hex");
|
|
479
|
-
const noncePathResolved = join4(stateDir, "shim-nonce");
|
|
480
|
-
safeWriteFile(noncePathResolved, nonce, 384);
|
|
481
|
-
chownIfNeeded(noncePathResolved, opts.targetUid, opts.targetGid);
|
|
482
|
-
const dgEntry = currentDgEntry();
|
|
483
|
-
const dgEntryPathResolved = join4(stateDir, "dg-entry");
|
|
484
|
-
if (dgEntry) {
|
|
485
|
-
safeWriteFile(dgEntryPathResolved, dgEntry + "\n", 420);
|
|
486
|
-
chownIfNeeded(dgEntryPathResolved, opts.targetUid, opts.targetGid);
|
|
487
|
-
}
|
|
488
|
-
const shimsCreated = [];
|
|
489
|
-
for (const eco of ECOSYSTEMS) {
|
|
490
|
-
const filename = shimFilename(eco, platform);
|
|
491
|
-
const fullPath = join4(shimsDir, filename);
|
|
492
|
-
const body = renderShim({ ecosystem: eco, platform });
|
|
493
|
-
safeWriteFile(fullPath, body, platform === "windows" ? 420 : 493);
|
|
494
|
-
if (platform !== "windows") chmodSync(fullPath, 493);
|
|
495
|
-
chownIfNeeded(fullPath, opts.targetUid, opts.targetGid);
|
|
496
|
-
shimsCreated.push(filename);
|
|
497
|
-
}
|
|
498
|
-
if (opts.refreshTemplates) {
|
|
499
|
-
clearResolveCache();
|
|
500
|
-
}
|
|
501
|
-
const resolvedRealBinaries = {};
|
|
502
|
-
for (const eco of ["npm", "pnpm", "yarn", "bun", "uv", "pipx", "conda", "mamba"]) {
|
|
503
|
-
resolvedRealBinaries[eco] = resolveRealBinary(eco);
|
|
504
|
-
}
|
|
505
|
-
const cachePathResolved = realBinaryCachePath();
|
|
506
|
-
if (existsSync4(cachePathResolved)) {
|
|
507
|
-
chownIfNeeded(cachePathResolved, opts.targetUid, opts.targetGid);
|
|
508
|
-
}
|
|
509
|
-
const rcOutcomes = [];
|
|
510
|
-
if (!opts.skipRcEdit && platform !== "windows") {
|
|
511
|
-
const shellKind = detectShellKind(process.env.SHELL);
|
|
512
|
-
const snippet = pathSnippet(shellKind);
|
|
513
|
-
const candidates = rcCandidates(shellKind).map(
|
|
514
|
-
(p) => p.replace(homedir5(), targetHome)
|
|
515
|
-
);
|
|
516
|
-
for (const candidate of candidates) {
|
|
517
|
-
const outcome = appendSentinelBlock(candidate, snippet);
|
|
518
|
-
rcOutcomes.push(outcome);
|
|
519
|
-
if (outcome.status === "appended") {
|
|
520
|
-
chownIfNeeded(outcome.path, opts.targetUid, opts.targetGid);
|
|
521
|
-
}
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
if (!opts.skipRcEdit && platform === "windows") {
|
|
525
|
-
persistWindowsPath(shimsDir, rcOutcomes);
|
|
526
|
-
updatePowerShellProfile(targetHome, shimsDir, rcOutcomes);
|
|
527
|
-
}
|
|
528
|
-
const receipt = {
|
|
529
|
-
schemaVersion: 1,
|
|
530
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
531
|
-
platform,
|
|
532
|
-
shimsDir,
|
|
533
|
-
shimsCreated,
|
|
534
|
-
rcOutcomes,
|
|
535
|
-
nonceFile: noncePathResolved,
|
|
536
|
-
cacheFile: cachePathResolved,
|
|
537
|
-
dgEntry: dgEntry ?? null,
|
|
538
|
-
nodeVersion: process.version,
|
|
539
|
-
dgVersion: process.env.DG_CLI_VERSION ?? "unknown"
|
|
540
|
-
};
|
|
541
|
-
const receiptResolved = join4(stateDir, "install-receipt.json");
|
|
542
|
-
safeWriteFile(receiptResolved, JSON.stringify(receipt, null, 2), 420);
|
|
543
|
-
chownIfNeeded(receiptResolved, opts.targetUid, opts.targetGid);
|
|
544
|
-
chownTreeIfNeeded(dgRoot2, opts.targetUid, opts.targetGid);
|
|
545
|
-
return {
|
|
546
|
-
shimsCreated,
|
|
547
|
-
rcOutcomes,
|
|
548
|
-
noncePath: noncePathResolved,
|
|
549
|
-
receiptPath: receiptResolved,
|
|
550
|
-
cachePath: cachePathResolved,
|
|
551
|
-
resolvedRealBinaries
|
|
552
|
-
};
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
// src/python-hook/install.ts
|
|
556
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, unlinkSync as unlinkSync2, readdirSync as readdirSync2, statSync as statSync3 } from "node:fs";
|
|
557
|
-
import { dirname as dirname3, join as join5, resolve } from "node:path";
|
|
558
|
-
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
559
|
-
import { homedir as homedir6 } from "node:os";
|
|
560
|
-
var SUPPORTED_PYTHON_VERSIONS = [
|
|
561
|
-
"python3.13",
|
|
562
|
-
"python3.12",
|
|
563
|
-
"python3.11",
|
|
564
|
-
"python3.10",
|
|
565
|
-
"python3.9",
|
|
566
|
-
"python3.8",
|
|
567
|
-
"python3"
|
|
568
|
-
];
|
|
569
|
-
function moduleAssetDir() {
|
|
570
|
-
const scriptPath = process.argv[1] ?? "";
|
|
571
|
-
const candidates = [
|
|
572
|
-
resolve(dirname3(scriptPath), "python-hook"),
|
|
573
|
-
resolve(dirname3(scriptPath), "..", "python-hook"),
|
|
574
|
-
resolve(dirname3(scriptPath), "src", "python-hook")
|
|
575
|
-
];
|
|
576
|
-
for (const c of candidates) {
|
|
577
|
-
if (existsSync5(join5(c, "dg_pip_hook.py"))) return c;
|
|
578
|
-
}
|
|
579
|
-
return resolve(dirname3(scriptPath));
|
|
580
|
-
}
|
|
581
|
-
function probeUserSite(pythonName) {
|
|
582
|
-
try {
|
|
583
|
-
const result = spawnSync2(pythonName, ["-c", "import site; print(site.getusersitepackages())"], {
|
|
584
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
585
|
-
timeout: 5e3
|
|
586
|
-
});
|
|
587
|
-
if (result.status !== 0) return null;
|
|
588
|
-
const out = result.stdout.toString().trim();
|
|
589
|
-
if (!out) return null;
|
|
590
|
-
const home = homedir6();
|
|
591
|
-
if (!out.startsWith(home)) return null;
|
|
592
|
-
return out;
|
|
593
|
-
} catch {
|
|
594
|
-
return null;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
function installPythonHooks(opts = {}) {
|
|
598
|
-
const home = opts.targetHome ?? homedir6();
|
|
599
|
-
const assetDir = moduleAssetDir();
|
|
600
|
-
const hookPyPath = join5(assetDir, "dg_pip_hook.py");
|
|
601
|
-
const pthPath = join5(assetDir, "dg_pip_hook.pth");
|
|
602
|
-
if (!existsSync5(hookPyPath) || !existsSync5(pthPath)) {
|
|
603
|
-
return {
|
|
604
|
-
results: [{ pythonVersion: "(any)", userSite: "", status: "failed", reason: "hook asset files missing" }],
|
|
605
|
-
receiptPath: ""
|
|
606
|
-
};
|
|
607
|
-
}
|
|
608
|
-
const hookPy = readFileSync4(hookPyPath, "utf-8");
|
|
609
|
-
const pthFile = readFileSync4(pthPath, "utf-8");
|
|
610
|
-
const results = [];
|
|
611
|
-
const seenSites = /* @__PURE__ */ new Set();
|
|
612
|
-
for (const py of SUPPORTED_PYTHON_VERSIONS) {
|
|
613
|
-
const userSite = probeUserSite(py);
|
|
614
|
-
if (!userSite) {
|
|
615
|
-
continue;
|
|
616
|
-
}
|
|
617
|
-
if (seenSites.has(userSite)) {
|
|
618
|
-
continue;
|
|
619
|
-
}
|
|
620
|
-
seenSites.add(userSite);
|
|
621
|
-
try {
|
|
622
|
-
if (!userSite.startsWith(home)) {
|
|
623
|
-
results.push({ pythonVersion: py, userSite, status: "skipped", reason: "user-site outside $HOME" });
|
|
624
|
-
continue;
|
|
625
|
-
}
|
|
626
|
-
safeMkdirRecursive(userSite, 493);
|
|
627
|
-
safeWriteFile(join5(userSite, "dg_pip_hook.py"), hookPy, 420);
|
|
628
|
-
safeWriteFile(join5(userSite, "dg_pip_hook.pth"), pthFile, 420);
|
|
629
|
-
results.push({ pythonVersion: py, userSite, status: "installed" });
|
|
630
|
-
} catch (err) {
|
|
631
|
-
results.push({ pythonVersion: py, userSite, status: "failed", reason: err.message });
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
const receiptPath = dgStatePath("python-hook-receipt.json");
|
|
635
|
-
try {
|
|
636
|
-
safeWriteFile(
|
|
637
|
-
receiptPath,
|
|
638
|
-
JSON.stringify({ schemaVersion: 1, installedAt: (/* @__PURE__ */ new Date()).toISOString(), results }, null, 2),
|
|
639
|
-
420
|
|
640
|
-
);
|
|
641
|
-
} catch {
|
|
642
|
-
}
|
|
643
|
-
return { results, receiptPath };
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
// src/postinstall.ts
|
|
647
|
-
function detectSudo() {
|
|
648
|
-
if (process.platform === "win32") return null;
|
|
649
|
-
const uid = typeof process.getuid === "function" ? process.getuid() : -1;
|
|
650
|
-
if (uid !== 0) return null;
|
|
651
|
-
const sudoUser = process.env.SUDO_USER;
|
|
652
|
-
if (!sudoUser || sudoUser === "root") return null;
|
|
653
|
-
try {
|
|
654
|
-
const info = userInfo();
|
|
655
|
-
if (info.username === sudoUser) {
|
|
656
|
-
return { targetHome: info.homedir, targetUid: info.uid, targetGid: info.gid };
|
|
657
|
-
}
|
|
658
|
-
} catch {
|
|
659
|
-
}
|
|
660
|
-
const sudoUid = parseInt(process.env.SUDO_UID ?? "", 10);
|
|
661
|
-
const sudoGid = parseInt(process.env.SUDO_GID ?? "", 10);
|
|
662
|
-
if (!Number.isFinite(sudoUid) || !Number.isFinite(sudoGid)) return null;
|
|
663
|
-
const home = `/home/${sudoUser}`;
|
|
664
|
-
return { targetHome: home, targetUid: sudoUid, targetGid: sudoGid };
|
|
665
|
-
}
|
|
666
|
-
function shouldSkipSilently() {
|
|
667
|
-
if (process.env.DG_FORCE_POSTINSTALL === "1") return false;
|
|
668
|
-
const ciFlags = [
|
|
669
|
-
"CI",
|
|
670
|
-
"GITHUB_ACTIONS",
|
|
671
|
-
"GITLAB_CI",
|
|
672
|
-
"BUILDKITE",
|
|
673
|
-
"CIRCLECI",
|
|
674
|
-
"JENKINS_URL",
|
|
675
|
-
"DRONE",
|
|
676
|
-
"TRAVIS",
|
|
677
|
-
"TF_BUILD"
|
|
678
|
-
];
|
|
679
|
-
for (const flag of ciFlags) {
|
|
680
|
-
if (process.env[flag] && process.env[flag] !== "false" && process.env[flag] !== "0") return true;
|
|
681
|
-
}
|
|
682
|
-
if (process.env.DG_NO_RC_EDIT === "1") return true;
|
|
683
|
-
return false;
|
|
684
|
-
}
|
|
685
|
-
function emit(msg) {
|
|
686
|
-
process.stderr.write(msg + "\n");
|
|
687
|
-
}
|
|
688
|
-
async function main() {
|
|
689
|
-
if (shouldSkipSilently()) return;
|
|
690
|
-
const sudo = process.platform === "win32" ? null : detectSudo();
|
|
691
|
-
const targetHome = sudo?.targetHome ?? homedir7();
|
|
692
|
-
const targetUid = sudo?.targetUid;
|
|
693
|
-
const targetGid = sudo?.targetGid;
|
|
694
|
-
try {
|
|
695
|
-
const result = installShims({ targetHome, targetUid, targetGid });
|
|
696
|
-
const rcAppended = result.rcOutcomes.filter((o) => o.status === "appended").map((o) => o.path);
|
|
697
|
-
const ecosystemsWired = result.shimsCreated.length;
|
|
698
|
-
let pythonVersions = [];
|
|
699
|
-
try {
|
|
700
|
-
const pyResult = installPythonHooks({ targetHome, uid: targetUid, gid: targetGid });
|
|
701
|
-
pythonVersions = pyResult.results.filter((r) => r.status === "installed").map((r) => r.pythonVersion);
|
|
702
|
-
} catch {
|
|
703
|
-
}
|
|
704
|
-
void ecosystemsWired;
|
|
705
|
-
const rcPath = rcAppended[0] ?? result.rcOutcomes.find((o) => o.status === "already-present")?.path ?? null;
|
|
706
|
-
const shimDir2 = `${targetHome}/.dg/shims`;
|
|
707
|
-
const activeNow = (process.env.PATH ?? "").split(":").includes(shimDir2);
|
|
708
|
-
emit("\u2713 Dependency Guardian installed.");
|
|
709
|
-
emit("\u2713 Wired: npm, pnpm, yarn, bun, pip, pip3, uv, pipx, conda, mamba.");
|
|
710
|
-
if (pythonVersions.length > 0) {
|
|
711
|
-
emit(`\u2713 python -m pip \u2014 wired on ${pythonVersions.join(", ")}.`);
|
|
712
|
-
}
|
|
713
|
-
if (rcPath) emit(`\u2713 Added ${shimDir2} to PATH in ${rcPath}.`);
|
|
714
|
-
emit("");
|
|
715
|
-
if (!activeNow) {
|
|
716
|
-
emit(" \u26A0 One more step \u2014 activate it in your shell:");
|
|
717
|
-
emit(rcPath ? ` source ${rcPath} (or just open a new terminal)` : " open a new terminal");
|
|
718
|
-
emit(" Until you do, installs in THIS shell still run unscanned.");
|
|
719
|
-
emit("");
|
|
720
|
-
}
|
|
721
|
-
emit(" Then:");
|
|
722
|
-
emit(" dg login authenticate your account");
|
|
723
|
-
emit(" dg status see what's protected (and if this shell is active)");
|
|
724
|
-
emit(" dg uninstall remove everything");
|
|
725
|
-
} catch (err) {
|
|
726
|
-
emit("\u2139\uFE0F Dependency Guardian installed.");
|
|
727
|
-
emit(` Setup did not complete: ${err.message}`);
|
|
728
|
-
emit(" Reinstall with `npm install -g @westbayberry/dg` to retry.");
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
void main();
|