@westbayberry/dg 1.0.52 → 1.0.56
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/README.md +5 -1
- package/dist/index.mjs +349 -168
- package/dist/packages/cli/src/alt-screen.js +36 -0
- package/dist/packages/cli/src/api.js +322 -0
- package/dist/packages/cli/src/auth.js +218 -0
- package/dist/packages/cli/src/bin.js +386 -0
- package/dist/packages/cli/src/config.js +228 -0
- package/dist/packages/cli/src/discover.js +126 -0
- package/dist/packages/cli/src/first-run.js +135 -0
- package/dist/packages/cli/src/hook.js +360 -0
- package/dist/packages/cli/src/lockfile.js +303 -0
- package/dist/packages/cli/src/npm-wrapper.js +218 -0
- package/dist/packages/cli/src/pip-wrapper.js +273 -0
- package/dist/packages/cli/src/sanitize.js +38 -0
- package/dist/packages/cli/src/scan-core.js +144 -0
- package/dist/packages/cli/src/setup-status.js +46 -0
- package/dist/packages/cli/src/static-output.js +625 -0
- package/dist/packages/cli/src/telemetry.js +141 -0
- package/dist/packages/cli/src/ui/App.js +137 -0
- package/dist/packages/cli/src/ui/InitApp.js +391 -0
- package/dist/packages/cli/src/ui/LoginApp.js +51 -0
- package/dist/packages/cli/src/ui/NpmWrapperApp.js +73 -0
- package/dist/packages/cli/src/ui/PipWrapperApp.js +72 -0
- package/dist/packages/cli/src/ui/components/ConfirmPrompt.js +24 -0
- package/dist/packages/cli/src/ui/components/DemoScanAnimation.js +26 -0
- package/dist/packages/cli/src/ui/components/DurationLine.js +7 -0
- package/dist/packages/cli/src/ui/components/ErrorView.js +30 -0
- package/dist/packages/cli/src/ui/components/FileSavePrompt.js +210 -0
- package/dist/packages/cli/src/ui/components/InteractiveResultsView.js +557 -0
- package/dist/packages/cli/src/ui/components/Mascot.js +33 -0
- package/dist/packages/cli/src/ui/components/ProgressBar.js +51 -0
- package/dist/packages/cli/src/ui/components/ProgressDots.js +35 -0
- package/dist/packages/cli/src/ui/components/ProjectSelector.js +60 -0
- package/dist/packages/cli/src/ui/components/ResultsView.js +105 -0
- package/dist/packages/cli/src/ui/components/ScanResultCard.js +54 -0
- package/dist/packages/cli/src/ui/components/ScoreHeader.js +142 -0
- package/dist/packages/cli/src/ui/components/SetupBanner.js +17 -0
- package/dist/packages/cli/src/ui/components/Spinner.js +11 -0
- package/dist/packages/cli/src/ui/hooks/useExpandAnimation.js +44 -0
- package/dist/packages/cli/src/ui/hooks/useInit.js +341 -0
- package/dist/packages/cli/src/ui/hooks/useLogin.js +121 -0
- package/dist/packages/cli/src/ui/hooks/useNpmWrapper.js +192 -0
- package/dist/packages/cli/src/ui/hooks/usePipWrapper.js +195 -0
- package/dist/packages/cli/src/ui/hooks/useScan.js +202 -0
- package/dist/packages/cli/src/ui/hooks/useTerminalSize.js +29 -0
- package/dist/packages/cli/src/update-check.js +152 -0
- package/dist/packages/cli/src/wizard-demo-data.js +63 -0
- package/dist/src/ecosystem.js +2 -0
- package/dist/src/lockfile/diff.js +38 -0
- package/dist/src/lockfile/parse_package_json.js +41 -0
- package/dist/src/lockfile/parse_package_lock.js +55 -0
- package/dist/src/lockfile/parse_pipfile_lock.js +69 -0
- package/dist/src/lockfile/parse_pnpm_lock.js +62 -0
- package/dist/src/lockfile/parse_poetry_lock.js +71 -0
- package/dist/src/lockfile/parse_requirements.js +83 -0
- package/dist/src/lockfile/parse_yarn_lock.js +66 -0
- package/dist/src/logger.js +21 -0
- package/dist/src/npm/h2pool.js +161 -0
- package/dist/src/npm/registry.js +299 -0
- package/dist/src/npm/tarball.js +274 -0
- package/dist/src/pypi/registry.js +299 -0
- package/dist/src/pypi/tarball.js +361 -0
- package/dist/src/types.js +2 -0
- package/package.json +6 -3
package/dist/index.mjs
CHANGED
|
@@ -19192,9 +19192,9 @@ function handleContentBlockStart(event, state) {
|
|
|
19192
19192
|
function handleContentBlockDelta(event, state, recordOutputs) {
|
|
19193
19193
|
if (event.type !== "content_block_delta" || !event.delta) return;
|
|
19194
19194
|
if (typeof event.index === "number" && "partial_json" in event.delta && typeof event.delta.partial_json === "string") {
|
|
19195
|
-
const
|
|
19196
|
-
if (
|
|
19197
|
-
|
|
19195
|
+
const active2 = state.activeToolBlocks[event.index];
|
|
19196
|
+
if (active2) {
|
|
19197
|
+
active2.inputJsonParts.push(event.delta.partial_json);
|
|
19198
19198
|
}
|
|
19199
19199
|
}
|
|
19200
19200
|
if (recordOutputs && typeof event.delta.text === "string") {
|
|
@@ -19203,9 +19203,9 @@ function handleContentBlockDelta(event, state, recordOutputs) {
|
|
|
19203
19203
|
}
|
|
19204
19204
|
function handleContentBlockStop(event, state) {
|
|
19205
19205
|
if (event.type !== "content_block_stop" || typeof event.index !== "number") return;
|
|
19206
|
-
const
|
|
19207
|
-
if (!
|
|
19208
|
-
const raw =
|
|
19206
|
+
const active2 = state.activeToolBlocks[event.index];
|
|
19207
|
+
if (!active2) return;
|
|
19208
|
+
const raw = active2.inputJsonParts.join("");
|
|
19209
19209
|
let parsedInput;
|
|
19210
19210
|
try {
|
|
19211
19211
|
parsedInput = raw ? JSON.parse(raw) : {};
|
|
@@ -19214,8 +19214,8 @@ function handleContentBlockStop(event, state) {
|
|
|
19214
19214
|
}
|
|
19215
19215
|
state.toolCalls.push({
|
|
19216
19216
|
type: "tool_use",
|
|
19217
|
-
id:
|
|
19218
|
-
name:
|
|
19217
|
+
id: active2.id,
|
|
19218
|
+
name: active2.name,
|
|
19219
19219
|
input: parsedInput
|
|
19220
19220
|
});
|
|
19221
19221
|
delete state.activeToolBlocks[event.index];
|
|
@@ -46241,9 +46241,10 @@ __export(auth_exports, {
|
|
|
46241
46241
|
maskKey: () => maskKey,
|
|
46242
46242
|
openBrowser: () => openBrowser,
|
|
46243
46243
|
pollAuthSession: () => pollAuthSession,
|
|
46244
|
-
saveCredentials: () => saveCredentials
|
|
46244
|
+
saveCredentials: () => saveCredentials,
|
|
46245
|
+
scrubAuthToken: () => scrubAuthToken
|
|
46245
46246
|
});
|
|
46246
|
-
import { readFileSync as readFileSync2, writeFileSync, unlinkSync, existsSync as existsSync2, chmodSync } from "node:fs";
|
|
46247
|
+
import { readFileSync as readFileSync2, writeFileSync, unlinkSync, existsSync as existsSync2, chmodSync, lstatSync, openSync, fchmodSync, closeSync, constants as fsConstants } from "node:fs";
|
|
46247
46248
|
import { join as join4 } from "node:path";
|
|
46248
46249
|
import { homedir } from "node:os";
|
|
46249
46250
|
import { spawn } from "node:child_process";
|
|
@@ -46296,7 +46297,47 @@ async function pollAuthSession(sessionId) {
|
|
|
46296
46297
|
function configPath() {
|
|
46297
46298
|
return join4(homedir(), CONFIG_FILE);
|
|
46298
46299
|
}
|
|
46300
|
+
function ensureConfigPerms(path2) {
|
|
46301
|
+
let st;
|
|
46302
|
+
try {
|
|
46303
|
+
st = lstatSync(path2);
|
|
46304
|
+
} catch {
|
|
46305
|
+
return;
|
|
46306
|
+
}
|
|
46307
|
+
if (!st || typeof st.isSymbolicLink !== "function") return;
|
|
46308
|
+
if (st.isSymbolicLink()) {
|
|
46309
|
+
process.stderr.write(
|
|
46310
|
+
`Warning: ${path2} is a symlink; refusing to chmod (would affect the symlink target). Replace with a regular file to enforce 0o600.
|
|
46311
|
+
`
|
|
46312
|
+
);
|
|
46313
|
+
return;
|
|
46314
|
+
}
|
|
46315
|
+
if (typeof st.isFile === "function" && !st.isFile()) return;
|
|
46316
|
+
const mode = (st.mode ?? 384) & 511;
|
|
46317
|
+
if (mode === 384) return;
|
|
46318
|
+
process.stderr.write(
|
|
46319
|
+
`Warning: ${path2} has perms 0o${mode.toString(8)} (expected 0o600); re-tightening.
|
|
46320
|
+
`
|
|
46321
|
+
);
|
|
46322
|
+
let fd;
|
|
46323
|
+
try {
|
|
46324
|
+
fd = openSync(path2, fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW);
|
|
46325
|
+
fchmodSync(fd, 384);
|
|
46326
|
+
} catch {
|
|
46327
|
+
} finally {
|
|
46328
|
+
if (fd !== void 0) {
|
|
46329
|
+
try {
|
|
46330
|
+
closeSync(fd);
|
|
46331
|
+
} catch {
|
|
46332
|
+
}
|
|
46333
|
+
}
|
|
46334
|
+
}
|
|
46335
|
+
}
|
|
46336
|
+
function scrubAuthToken(s) {
|
|
46337
|
+
return s.replace(/\bdgk_[A-Za-z0-9]{16,}\b/g, "dgk_<REDACTED>").replace(/\bBearer\s+[A-Za-z0-9_.-]{24,}\b/g, "Bearer <REDACTED>");
|
|
46338
|
+
}
|
|
46299
46339
|
function readConfig() {
|
|
46340
|
+
ensureConfigPerms(configPath());
|
|
46300
46341
|
let raw;
|
|
46301
46342
|
try {
|
|
46302
46343
|
raw = readFileSync2(configPath(), "utf-8");
|
|
@@ -46418,20 +46459,65 @@ var config_exports = {};
|
|
|
46418
46459
|
__export(config_exports, {
|
|
46419
46460
|
USAGE: () => USAGE,
|
|
46420
46461
|
getVersion: () => getVersion,
|
|
46421
|
-
parseConfig: () => parseConfig
|
|
46462
|
+
parseConfig: () => parseConfig,
|
|
46463
|
+
warnUnknownDgrcKeys: () => warnUnknownDgrcKeys
|
|
46422
46464
|
});
|
|
46423
46465
|
import { parseArgs } from "node:util";
|
|
46424
46466
|
import { readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
|
|
46425
46467
|
import { join as join5, dirname as dirname3 } from "node:path";
|
|
46426
46468
|
import { fileURLToPath } from "node:url";
|
|
46427
46469
|
import { homedir as homedir2 } from "node:os";
|
|
46470
|
+
function levenshtein(a, b) {
|
|
46471
|
+
if (a === b) return 0;
|
|
46472
|
+
if (a.length === 0) return b.length;
|
|
46473
|
+
if (b.length === 0) return a.length;
|
|
46474
|
+
const m = a.length;
|
|
46475
|
+
const n = b.length;
|
|
46476
|
+
let prev = Array.from({ length: n + 1 }, (_, i) => i);
|
|
46477
|
+
let curr = new Array(n + 1);
|
|
46478
|
+
for (let i = 1; i <= m; i++) {
|
|
46479
|
+
curr[0] = i;
|
|
46480
|
+
for (let j = 1; j <= n; j++) {
|
|
46481
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
46482
|
+
curr[j] = Math.min(curr[j - 1] + 1, prev[j] + 1, prev[j - 1] + cost);
|
|
46483
|
+
}
|
|
46484
|
+
[prev, curr] = [curr, prev];
|
|
46485
|
+
}
|
|
46486
|
+
return prev[n];
|
|
46487
|
+
}
|
|
46488
|
+
function warnUnknownDgrcKeys(parsed, source) {
|
|
46489
|
+
for (const key of Object.keys(parsed)) {
|
|
46490
|
+
if (KNOWN_DGRC_KEYS.includes(key)) continue;
|
|
46491
|
+
if (INTERNAL_DGRC_KEYS.includes(key)) continue;
|
|
46492
|
+
let bestKey = null;
|
|
46493
|
+
let bestDistance = Infinity;
|
|
46494
|
+
for (const known of KNOWN_DGRC_KEYS) {
|
|
46495
|
+
const d = levenshtein(key, known);
|
|
46496
|
+
if (d < bestDistance) {
|
|
46497
|
+
bestDistance = d;
|
|
46498
|
+
bestKey = known;
|
|
46499
|
+
}
|
|
46500
|
+
}
|
|
46501
|
+
const suggestion = bestKey && bestDistance <= 2 ? ` (did you mean "${bestKey}"?)` : ` (valid keys: ${KNOWN_DGRC_KEYS.join(", ")})`;
|
|
46502
|
+
process.stderr.write(
|
|
46503
|
+
`Warning: unknown key "${key}" in ${source}${suggestion}; ignored.
|
|
46504
|
+
`
|
|
46505
|
+
);
|
|
46506
|
+
}
|
|
46507
|
+
}
|
|
46428
46508
|
function loadDgrc() {
|
|
46429
46509
|
const cwdPath = join5(process.cwd(), ".dgrc.json");
|
|
46430
46510
|
const homePath = join5(homedir2(), ".dgrc.json");
|
|
46431
46511
|
let config3 = {};
|
|
46432
46512
|
if (existsSync3(homePath)) {
|
|
46433
46513
|
try {
|
|
46434
|
-
|
|
46514
|
+
const home = JSON.parse(readFileSync3(homePath, "utf-8"));
|
|
46515
|
+
warnUnknownDgrcKeys(home, homePath);
|
|
46516
|
+
const homeFiltered = {};
|
|
46517
|
+
for (const k of KNOWN_DGRC_KEYS) {
|
|
46518
|
+
if (k in home) homeFiltered[k] = home[k];
|
|
46519
|
+
}
|
|
46520
|
+
config3 = homeFiltered;
|
|
46435
46521
|
} catch {
|
|
46436
46522
|
process.stderr.write(`Warning: Failed to parse ${homePath}, ignoring.
|
|
46437
46523
|
`);
|
|
@@ -46440,8 +46526,11 @@ function loadDgrc() {
|
|
|
46440
46526
|
if (existsSync3(cwdPath) && cwdPath !== homePath) {
|
|
46441
46527
|
try {
|
|
46442
46528
|
const cwd2 = JSON.parse(readFileSync3(cwdPath, "utf-8"));
|
|
46443
|
-
|
|
46444
|
-
|
|
46529
|
+
warnUnknownDgrcKeys(cwd2, cwdPath);
|
|
46530
|
+
for (const k of KNOWN_DGRC_KEYS) {
|
|
46531
|
+
if (k === "apiKey" || k === "apiUrl") continue;
|
|
46532
|
+
if (k in cwd2) config3[k] = cwd2[k];
|
|
46533
|
+
}
|
|
46445
46534
|
} catch {
|
|
46446
46535
|
process.stderr.write(`Warning: Failed to parse ${cwdPath}, ignoring.
|
|
46447
46536
|
`);
|
|
@@ -46454,6 +46543,14 @@ function validateApiUrl(url) {
|
|
|
46454
46543
|
const parsed = new URL(url);
|
|
46455
46544
|
const rawHost = parsed.hostname;
|
|
46456
46545
|
const host = rawHost.startsWith("[") && rawHost.endsWith("]") ? rawHost.slice(1, -1) : rawHost;
|
|
46546
|
+
const isLinkLocal = /^169\.254\./.test(host) || /^fe[89ab][0-9a-f]:/i.test(host);
|
|
46547
|
+
if (isLinkLocal) {
|
|
46548
|
+
process.stderr.write(
|
|
46549
|
+
`Error: API URL host ${host} is link-local / metadata; refusing (SSRF defense). If you genuinely need this, set DG_API_URL to the explicit hostname of your test target.
|
|
46550
|
+
`
|
|
46551
|
+
);
|
|
46552
|
+
process.exit(1);
|
|
46553
|
+
}
|
|
46457
46554
|
const isLocal = host === "localhost" || // IPv4: loopback, RFC 1918, CGNAT. Proper octet regex — not prefix matching,
|
|
46458
46555
|
// which would wrongly accept `192.1680.0.1` or `100.1.2.3` (public).
|
|
46459
46556
|
/^(127\.|10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\.)/.test(host) || // IPv6: loopback and unique local (fc00::/7 → fc** or fd**)
|
|
@@ -46492,7 +46589,8 @@ function parseConfig(argv, strictFlags = true) {
|
|
|
46492
46589
|
mode: { type: "string" },
|
|
46493
46590
|
"max-packages": { type: "string" },
|
|
46494
46591
|
json: { type: "boolean", default: false },
|
|
46495
|
-
"scan-all": { type: "boolean", default:
|
|
46592
|
+
"scan-all": { type: "boolean", default: true },
|
|
46593
|
+
"changed-only": { type: "boolean", default: false },
|
|
46496
46594
|
"base-lockfile": { type: "string" },
|
|
46497
46595
|
workspace: { type: "string", short: "w" },
|
|
46498
46596
|
output: { type: "string", short: "o" },
|
|
@@ -46533,8 +46631,7 @@ function parseConfig(argv, strictFlags = true) {
|
|
|
46533
46631
|
}
|
|
46534
46632
|
const command = positionals[0] ?? "scan";
|
|
46535
46633
|
const dgrc = loadDgrc();
|
|
46536
|
-
const apiKey = dgrc.apiKey && typeof dgrc.apiKey === "string" && dgrc.apiKey.startsWith("dg_live_") ? dgrc.apiKey : null;
|
|
46537
|
-
const deviceId = getOrCreateDeviceId();
|
|
46634
|
+
const apiKey = dgrc.apiKey && typeof dgrc.apiKey === "string" && (dgrc.apiKey.startsWith("dg_live_") || dgrc.apiKey.startsWith("dg_test_")) ? dgrc.apiKey : null;
|
|
46538
46635
|
const modeRaw = values.mode ?? process.env.DG_MODE ?? dgrc.mode ?? "warn";
|
|
46539
46636
|
if (!["block", "warn", "off"].includes(modeRaw)) {
|
|
46540
46637
|
process.stderr.write(
|
|
@@ -46549,16 +46646,18 @@ function parseConfig(argv, strictFlags = true) {
|
|
|
46549
46646
|
process.stderr.write("Error: --max-packages must be a number between 1 and 10000\n");
|
|
46550
46647
|
process.exit(1);
|
|
46551
46648
|
}
|
|
46649
|
+
const apiUrl = validateApiUrl(
|
|
46650
|
+
values["api-url"] ?? process.env.DG_API_URL ?? dgrc.apiUrl ?? "https://api.westbayberry.com"
|
|
46651
|
+
);
|
|
46652
|
+
const deviceId = getOrCreateDeviceId();
|
|
46552
46653
|
return {
|
|
46553
46654
|
apiKey,
|
|
46554
46655
|
deviceId,
|
|
46555
|
-
apiUrl
|
|
46556
|
-
values["api-url"] ?? process.env.DG_API_URL ?? dgrc.apiUrl ?? "https://api.westbayberry.com"
|
|
46557
|
-
),
|
|
46656
|
+
apiUrl,
|
|
46558
46657
|
mode: modeRaw,
|
|
46559
46658
|
maxPackages,
|
|
46560
46659
|
json: values.json,
|
|
46561
|
-
scanAll: values["scan-all"],
|
|
46660
|
+
scanAll: values["changed-only"] ? false : values["scan-all"],
|
|
46562
46661
|
baseLockfile: values["base-lockfile"] ?? null,
|
|
46563
46662
|
workspace: values.workspace ?? process.env.DG_WORKSPACE ?? null,
|
|
46564
46663
|
outputFile: values.output ?? null,
|
|
@@ -46566,11 +46665,13 @@ function parseConfig(argv, strictFlags = true) {
|
|
|
46566
46665
|
debug: debug2
|
|
46567
46666
|
};
|
|
46568
46667
|
}
|
|
46569
|
-
var USAGE;
|
|
46668
|
+
var KNOWN_DGRC_KEYS, INTERNAL_DGRC_KEYS, USAGE;
|
|
46570
46669
|
var init_config = __esm({
|
|
46571
46670
|
"src/config.ts"() {
|
|
46572
46671
|
"use strict";
|
|
46573
46672
|
init_auth();
|
|
46673
|
+
KNOWN_DGRC_KEYS = ["apiKey", "apiUrl", "mode", "maxPackages"];
|
|
46674
|
+
INTERNAL_DGRC_KEYS = ["deviceId", "firstRunCompletedAt"];
|
|
46574
46675
|
USAGE = `
|
|
46575
46676
|
Dependency Guardian \u2014 Supply chain security scanner
|
|
46576
46677
|
|
|
@@ -46603,7 +46704,8 @@ var init_config = __esm({
|
|
|
46603
46704
|
--mode <mode> block | warn | off (default: warn)
|
|
46604
46705
|
--max-packages <n> Max packages per scan (default: 10000)
|
|
46605
46706
|
--json Output JSON for CI parsing
|
|
46606
|
-
--scan-all Scan all packages
|
|
46707
|
+
--scan-all Scan all packages (default)
|
|
46708
|
+
--changed-only Only scan packages changed since base lockfile
|
|
46607
46709
|
--base-lockfile <path> Path to base lockfile for explicit diff
|
|
46608
46710
|
--workspace <dir> Scan a specific workspace subdirectory
|
|
46609
46711
|
--output, -o <file> Save JSON results to file (use with --json)
|
|
@@ -46718,7 +46820,13 @@ function parsePackageSpec(spec) {
|
|
|
46718
46820
|
versionSpec: spec.slice(atIdx + 1)
|
|
46719
46821
|
};
|
|
46720
46822
|
}
|
|
46823
|
+
function isFlagLikeSpec(spec) {
|
|
46824
|
+
return spec.startsWith("-");
|
|
46825
|
+
}
|
|
46721
46826
|
async function resolveVersion(spec) {
|
|
46827
|
+
if (isFlagLikeSpec(spec)) {
|
|
46828
|
+
return null;
|
|
46829
|
+
}
|
|
46722
46830
|
return new Promise((resolve2) => {
|
|
46723
46831
|
const child = spawn2("npm", ["view", spec, "version"], {
|
|
46724
46832
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -48378,6 +48486,34 @@ var init_update_check = __esm({
|
|
|
48378
48486
|
}
|
|
48379
48487
|
});
|
|
48380
48488
|
|
|
48489
|
+
// src/alt-screen.ts
|
|
48490
|
+
var alt_screen_exports = {};
|
|
48491
|
+
__export(alt_screen_exports, {
|
|
48492
|
+
altScreenActive: () => altScreenActive,
|
|
48493
|
+
enterAltScreen: () => enterAltScreen,
|
|
48494
|
+
leaveAltScreen: () => leaveAltScreen
|
|
48495
|
+
});
|
|
48496
|
+
function enterAltScreen() {
|
|
48497
|
+
if (!process.stdout.isTTY || active) return;
|
|
48498
|
+
process.stdout.write("\x1B[?1049h\x1B[2J\x1B[H");
|
|
48499
|
+
active = true;
|
|
48500
|
+
}
|
|
48501
|
+
function leaveAltScreen() {
|
|
48502
|
+
if (!active) return;
|
|
48503
|
+
process.stdout.write("\x1B[?1049l\x1B[?25h");
|
|
48504
|
+
active = false;
|
|
48505
|
+
}
|
|
48506
|
+
function altScreenActive() {
|
|
48507
|
+
return active;
|
|
48508
|
+
}
|
|
48509
|
+
var active;
|
|
48510
|
+
var init_alt_screen = __esm({
|
|
48511
|
+
"src/alt-screen.ts"() {
|
|
48512
|
+
"use strict";
|
|
48513
|
+
active = false;
|
|
48514
|
+
}
|
|
48515
|
+
});
|
|
48516
|
+
|
|
48381
48517
|
// node_modules/react/cjs/react.production.min.js
|
|
48382
48518
|
var require_react_production_min = __commonJS({
|
|
48383
48519
|
"node_modules/react/cjs/react.production.min.js"(exports) {
|
|
@@ -82374,18 +82510,26 @@ var discover_exports = {};
|
|
|
82374
82510
|
__export(discover_exports, {
|
|
82375
82511
|
discoverProjects: () => discoverProjects
|
|
82376
82512
|
});
|
|
82377
|
-
import {
|
|
82513
|
+
import { readFileSync as readFileSync7, readdirSync, lstatSync as lstatSync2 } from "node:fs";
|
|
82378
82514
|
import { join as join8, relative as relative2, basename as basename2 } from "node:path";
|
|
82379
82515
|
function discoverProjects(root) {
|
|
82380
82516
|
const projects = [];
|
|
82381
82517
|
walk(root, root, 0, projects);
|
|
82382
82518
|
return projects.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
82383
82519
|
}
|
|
82520
|
+
function isSafeRegularFile(path2) {
|
|
82521
|
+
try {
|
|
82522
|
+
const st = lstatSync2(path2);
|
|
82523
|
+
return st.isFile() && !st.isSymbolicLink();
|
|
82524
|
+
} catch {
|
|
82525
|
+
return false;
|
|
82526
|
+
}
|
|
82527
|
+
}
|
|
82384
82528
|
function walk(dir, root, depth, out) {
|
|
82385
82529
|
if (depth > MAX_DEPTH) return;
|
|
82386
82530
|
for (const lockfile of NPM_LOCKFILES) {
|
|
82387
82531
|
const lockPath = join8(dir, lockfile);
|
|
82388
|
-
if (
|
|
82532
|
+
if (isSafeRegularFile(lockPath)) {
|
|
82389
82533
|
const count = countNpmPackages(lockPath);
|
|
82390
82534
|
if (count > 0) {
|
|
82391
82535
|
out.push({
|
|
@@ -82401,7 +82545,7 @@ function walk(dir, root, depth, out) {
|
|
|
82401
82545
|
}
|
|
82402
82546
|
for (const depFile of PYTHON_DEPFILES) {
|
|
82403
82547
|
const depPath = join8(dir, depFile);
|
|
82404
|
-
if (
|
|
82548
|
+
if (isSafeRegularFile(depPath)) {
|
|
82405
82549
|
const count = countPythonPackages(depPath, depFile);
|
|
82406
82550
|
if (count > 0) {
|
|
82407
82551
|
out.push({
|
|
@@ -82425,7 +82569,7 @@ function walk(dir, root, depth, out) {
|
|
|
82425
82569
|
if (SKIP_DIRS.has(entry) || entry.startsWith(".")) continue;
|
|
82426
82570
|
const full = join8(dir, entry);
|
|
82427
82571
|
try {
|
|
82428
|
-
const st =
|
|
82572
|
+
const st = lstatSync2(full);
|
|
82429
82573
|
if (st.isDirectory() && !st.isSymbolicLink()) {
|
|
82430
82574
|
walk(full, root, depth + 1, out);
|
|
82431
82575
|
}
|
|
@@ -82518,7 +82662,8 @@ __export(hook_exports, {
|
|
|
82518
82662
|
});
|
|
82519
82663
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
82520
82664
|
import {
|
|
82521
|
-
existsSync as
|
|
82665
|
+
existsSync as existsSync6,
|
|
82666
|
+
lstatSync as lstatSync3,
|
|
82522
82667
|
readFileSync as readFileSync8,
|
|
82523
82668
|
writeFileSync as writeFileSync3,
|
|
82524
82669
|
mkdirSync,
|
|
@@ -82526,9 +82671,40 @@ import {
|
|
|
82526
82671
|
unlinkSync as unlinkSync2
|
|
82527
82672
|
} from "node:fs";
|
|
82528
82673
|
import { join as join9, dirname as dirname4 } from "node:path";
|
|
82529
|
-
function
|
|
82674
|
+
function assertSafeWriteTarget(target) {
|
|
82675
|
+
const parent = dirname4(target);
|
|
82530
82676
|
try {
|
|
82531
|
-
|
|
82677
|
+
const parentStat = lstatSync3(parent);
|
|
82678
|
+
if (parentStat.isSymbolicLink()) {
|
|
82679
|
+
throw new Error(
|
|
82680
|
+
`refusing to write to ${target}: parent dir ${parent} is a symlink (possible path-traversal attack)`
|
|
82681
|
+
);
|
|
82682
|
+
}
|
|
82683
|
+
} catch (e) {
|
|
82684
|
+
if (e instanceof Error && e.message.startsWith("refusing")) {
|
|
82685
|
+
throw e;
|
|
82686
|
+
}
|
|
82687
|
+
}
|
|
82688
|
+
try {
|
|
82689
|
+
const targetStat = lstatSync3(target);
|
|
82690
|
+
if (targetStat.isSymbolicLink()) {
|
|
82691
|
+
throw new Error(
|
|
82692
|
+
`refusing to write to ${target}: target is a symlink (possible path-traversal attack)`
|
|
82693
|
+
);
|
|
82694
|
+
}
|
|
82695
|
+
} catch (e) {
|
|
82696
|
+
if (e instanceof Error && e.message.startsWith("refusing")) {
|
|
82697
|
+
throw e;
|
|
82698
|
+
}
|
|
82699
|
+
}
|
|
82700
|
+
}
|
|
82701
|
+
function safeWriteFileSync(target, content) {
|
|
82702
|
+
assertSafeWriteTarget(target);
|
|
82703
|
+
writeFileSync3(target, content);
|
|
82704
|
+
}
|
|
82705
|
+
function findHooksDir() {
|
|
82706
|
+
try {
|
|
82707
|
+
return execFileSync2("git", ["rev-parse", "--git-path", "hooks"], {
|
|
82532
82708
|
encoding: "utf-8",
|
|
82533
82709
|
stdio: ["pipe", "pipe", "pipe"]
|
|
82534
82710
|
}).trim();
|
|
@@ -82551,9 +82727,9 @@ function detectHookFramework(repoRoot) {
|
|
|
82551
82727
|
const huskyHook = join9(root, ".husky", "pre-commit");
|
|
82552
82728
|
const lefthookConfig = join9(root, "lefthook.yml");
|
|
82553
82729
|
const lefthookConfigYaml = join9(root, "lefthook.yaml");
|
|
82554
|
-
const
|
|
82555
|
-
const bareHook = join9(
|
|
82556
|
-
if (
|
|
82730
|
+
const hooksDir = findHooksDir();
|
|
82731
|
+
const bareHook = join9(hooksDir, "pre-commit");
|
|
82732
|
+
if (existsSync6(huskyHook)) {
|
|
82557
82733
|
const content = readFileSync8(huskyHook, "utf-8");
|
|
82558
82734
|
return {
|
|
82559
82735
|
framework: "husky",
|
|
@@ -82562,7 +82738,7 @@ function detectHookFramework(repoRoot) {
|
|
|
82562
82738
|
};
|
|
82563
82739
|
}
|
|
82564
82740
|
for (const cfg of [lefthookConfig, lefthookConfigYaml]) {
|
|
82565
|
-
if (
|
|
82741
|
+
if (existsSync6(cfg)) {
|
|
82566
82742
|
const content = readFileSync8(cfg, "utf-8");
|
|
82567
82743
|
const installed2 = /^\s+dependency-guardian\s*:/m.test(content);
|
|
82568
82744
|
return {
|
|
@@ -82573,7 +82749,7 @@ function detectHookFramework(repoRoot) {
|
|
|
82573
82749
|
}
|
|
82574
82750
|
}
|
|
82575
82751
|
let installed = false;
|
|
82576
|
-
if (
|
|
82752
|
+
if (existsSync6(bareHook)) {
|
|
82577
82753
|
installed = readFileSync8(bareHook, "utf-8").includes(HOOK_MARKER);
|
|
82578
82754
|
}
|
|
82579
82755
|
return {
|
|
@@ -82595,7 +82771,7 @@ ${HUSKY_SNIPPET}`;
|
|
|
82595
82771
|
|
|
82596
82772
|
${LEFTHOOK_ENTRY}`;
|
|
82597
82773
|
case "bare":
|
|
82598
|
-
if (
|
|
82774
|
+
if (existsSync6(info.targetFile)) {
|
|
82599
82775
|
return `Will append to existing hook at ${info.targetFile}:
|
|
82600
82776
|
${HOOK_SECTION}`;
|
|
82601
82777
|
}
|
|
@@ -82609,7 +82785,7 @@ function installHuskyHook(targetFile) {
|
|
|
82609
82785
|
process.stderr.write(" Hook already installed in Husky.\n");
|
|
82610
82786
|
return;
|
|
82611
82787
|
}
|
|
82612
|
-
|
|
82788
|
+
safeWriteFileSync(targetFile, existing.trimEnd() + "\n" + HUSKY_SNIPPET);
|
|
82613
82789
|
try {
|
|
82614
82790
|
chmodSync2(targetFile, 493);
|
|
82615
82791
|
} catch {
|
|
@@ -82631,7 +82807,7 @@ function installLefthookHook(targetFile) {
|
|
|
82631
82807
|
/^(\s{2}commands\s*:\s*)$/m,
|
|
82632
82808
|
`$1
|
|
82633
82809
|
${LEFTHOOK_MARKER}:
|
|
82634
|
-
glob: "{package-lock.json,yarn.lock,pnpm-lock.yaml,npm-shrinkwrap.json}"
|
|
82810
|
+
glob: "**/{package-lock.json,yarn.lock,pnpm-lock.yaml,npm-shrinkwrap.json,requirements.txt,requirements-*.txt,Pipfile.lock,poetry.lock}"
|
|
82635
82811
|
run: dg scan --mode block`
|
|
82636
82812
|
);
|
|
82637
82813
|
} else {
|
|
@@ -82645,20 +82821,20 @@ function installLefthookHook(targetFile) {
|
|
|
82645
82821
|
} else {
|
|
82646
82822
|
updated = existing.trimEnd() + "\n\n" + LEFTHOOK_ENTRY;
|
|
82647
82823
|
}
|
|
82648
|
-
|
|
82824
|
+
safeWriteFileSync(targetFile, updated);
|
|
82649
82825
|
process.stderr.write(` Added Dependency Guardian to ${targetFile}
|
|
82650
82826
|
`);
|
|
82651
82827
|
}
|
|
82652
82828
|
function installBareHook(targetFile) {
|
|
82653
82829
|
const hooksDir = dirname4(targetFile);
|
|
82654
82830
|
mkdirSync(hooksDir, { recursive: true });
|
|
82655
|
-
if (
|
|
82831
|
+
if (existsSync6(targetFile)) {
|
|
82656
82832
|
const existing = readFileSync8(targetFile, "utf-8");
|
|
82657
82833
|
if (existing.includes(HOOK_MARKER)) {
|
|
82658
82834
|
process.stderr.write(" Hook already installed.\n");
|
|
82659
82835
|
return;
|
|
82660
82836
|
}
|
|
82661
|
-
|
|
82837
|
+
safeWriteFileSync(targetFile, existing.trimEnd() + "\n" + HOOK_SECTION);
|
|
82662
82838
|
chmodSync2(targetFile, 493);
|
|
82663
82839
|
process.stderr.write(
|
|
82664
82840
|
` Appended Dependency Guardian hook to existing ${targetFile}
|
|
@@ -82666,7 +82842,7 @@ function installBareHook(targetFile) {
|
|
|
82666
82842
|
);
|
|
82667
82843
|
return;
|
|
82668
82844
|
}
|
|
82669
|
-
|
|
82845
|
+
safeWriteFileSync(targetFile, HOOK_SCRIPT);
|
|
82670
82846
|
chmodSync2(targetFile, 493);
|
|
82671
82847
|
process.stderr.write(` Installed git pre-commit hook at ${targetFile}
|
|
82672
82848
|
`);
|
|
@@ -82689,12 +82865,12 @@ function installHook() {
|
|
|
82689
82865
|
installHookForFramework(info);
|
|
82690
82866
|
}
|
|
82691
82867
|
function uninstallHook() {
|
|
82692
|
-
const
|
|
82693
|
-
const hookPath = join9(
|
|
82868
|
+
const hooksDir = findHooksDir();
|
|
82869
|
+
const hookPath = join9(hooksDir, "pre-commit");
|
|
82694
82870
|
try {
|
|
82695
82871
|
const root = findRepoRoot();
|
|
82696
82872
|
const huskyPath = join9(root, ".husky", "pre-commit");
|
|
82697
|
-
if (
|
|
82873
|
+
if (existsSync6(huskyPath)) {
|
|
82698
82874
|
const content2 = readFileSync8(huskyPath, "utf-8");
|
|
82699
82875
|
if (content2.includes(HOOK_MARKER)) {
|
|
82700
82876
|
const startIdx2 = content2.indexOf(MARKER_START);
|
|
@@ -82703,7 +82879,7 @@ function uninstallHook() {
|
|
|
82703
82879
|
const before = content2.slice(0, startIdx2).trimEnd();
|
|
82704
82880
|
const after = content2.slice(endIdx2 + MARKER_END.length).trimStart();
|
|
82705
82881
|
const remaining = (before + (after ? "\n" + after : "")).trimEnd() + "\n";
|
|
82706
|
-
|
|
82882
|
+
safeWriteFileSync(huskyPath, remaining);
|
|
82707
82883
|
process.stderr.write(
|
|
82708
82884
|
` Removed Dependency Guardian section from ${huskyPath}
|
|
82709
82885
|
`
|
|
@@ -82713,14 +82889,14 @@ function uninstallHook() {
|
|
|
82713
82889
|
}
|
|
82714
82890
|
}
|
|
82715
82891
|
for (const cfg of [join9(root, "lefthook.yml"), join9(root, "lefthook.yaml")]) {
|
|
82716
|
-
if (
|
|
82892
|
+
if (existsSync6(cfg)) {
|
|
82717
82893
|
const content2 = readFileSync8(cfg, "utf-8");
|
|
82718
82894
|
if (/^\s+dependency-guardian\s*:/m.test(content2)) {
|
|
82719
82895
|
const stripped = content2.replace(
|
|
82720
82896
|
/^\s+dependency-guardian\s*:\s*\n(?:\s{6,}.*\n)+/gm,
|
|
82721
82897
|
""
|
|
82722
82898
|
);
|
|
82723
|
-
|
|
82899
|
+
safeWriteFileSync(cfg, stripped);
|
|
82724
82900
|
process.stderr.write(
|
|
82725
82901
|
` Removed Dependency Guardian section from ${cfg}
|
|
82726
82902
|
`
|
|
@@ -82731,7 +82907,7 @@ function uninstallHook() {
|
|
|
82731
82907
|
}
|
|
82732
82908
|
} catch {
|
|
82733
82909
|
}
|
|
82734
|
-
if (!
|
|
82910
|
+
if (!existsSync6(hookPath)) {
|
|
82735
82911
|
process.stderr.write(" No hook to remove.\n");
|
|
82736
82912
|
return;
|
|
82737
82913
|
}
|
|
@@ -82754,7 +82930,7 @@ function uninstallHook() {
|
|
|
82754
82930
|
const before = content.slice(0, startIdx).trimEnd();
|
|
82755
82931
|
const after = content.slice(endIdx + MARKER_END.length).trimStart();
|
|
82756
82932
|
const remaining = (before + (after ? "\n" + after : "")).trimEnd() + "\n";
|
|
82757
|
-
|
|
82933
|
+
safeWriteFileSync(hookPath, remaining);
|
|
82758
82934
|
process.stderr.write(
|
|
82759
82935
|
` Removed Dependency Guardian section from ${hookPath}
|
|
82760
82936
|
`
|
|
@@ -82800,16 +82976,12 @@ var init_hook = __esm({
|
|
|
82800
82976
|
HOOK_SCRIPT = `#!/bin/sh
|
|
82801
82977
|
${HOOK_MARKER} \u2014 installed by \`dg hook install\`
|
|
82802
82978
|
|
|
82803
|
-
#
|
|
82804
|
-
|
|
82805
|
-
|
|
82806
|
-
|
|
82807
|
-
|
|
82808
|
-
|
|
82809
|
-
fi
|
|
82810
|
-
done
|
|
82811
|
-
|
|
82812
|
-
if [ -z "$STAGED" ]; then
|
|
82979
|
+
# Match any of the watched lockfiles, including in subdirectories
|
|
82980
|
+
# (monorepos) \u2014 the regex anchors at start-of-path OR after a slash.
|
|
82981
|
+
# Mirrors the GitHub-App side which is monorepo-aware via basename
|
|
82982
|
+
# matching against NPM_DEPENDENCY_FILES + isPythonDepFile.
|
|
82983
|
+
if ! git diff --cached --name-only | grep -qE \\
|
|
82984
|
+
'(^|/)(package-lock\\.json|npm-shrinkwrap\\.json|yarn\\.lock|pnpm-lock\\.yaml|requirements(-[^/]+)?\\.txt|Pipfile\\.lock|poetry\\.lock)$'; then
|
|
82813
82985
|
exit 0
|
|
82814
82986
|
fi
|
|
82815
82987
|
|
|
@@ -82846,7 +83018,7 @@ ${MARKER_START}
|
|
|
82846
83018
|
${HOOK_MARKER} \u2014 installed by \`dg hook install\`
|
|
82847
83019
|
DG_BIN=$(command -v dg 2>/dev/null || command -v dependency-guardian 2>/dev/null)
|
|
82848
83020
|
if [ -n "$DG_BIN" ]; then
|
|
82849
|
-
if git diff --cached --name-only | grep -qE '
|
|
83021
|
+
if git diff --cached --name-only | grep -qE '(^|/)(package-lock\\.json|npm-shrinkwrap\\.json|yarn\\.lock|pnpm-lock\\.yaml|requirements(-[^/]+)?\\.txt|Pipfile\\.lock|poetry\\.lock)$'; then
|
|
82850
83022
|
echo "Dependency Guardian: lockfile change detected, scanning..." >&2
|
|
82851
83023
|
NO_COLOR=1 "$DG_BIN" scan --mode block
|
|
82852
83024
|
DG_EXIT=$?
|
|
@@ -82861,7 +83033,7 @@ ${MARKER_END}
|
|
|
82861
83033
|
LEFTHOOK_ENTRY = ` pre-commit:
|
|
82862
83034
|
commands:
|
|
82863
83035
|
${LEFTHOOK_MARKER}:
|
|
82864
|
-
glob: "{package-lock.json,yarn.lock,pnpm-lock.yaml,npm-shrinkwrap.json}"
|
|
83036
|
+
glob: "**/{package-lock.json,yarn.lock,pnpm-lock.yaml,npm-shrinkwrap.json,requirements.txt,requirements-*.txt,Pipfile.lock,poetry.lock}"
|
|
82865
83037
|
run: dg scan --mode block
|
|
82866
83038
|
`;
|
|
82867
83039
|
USAGE2 = `
|
|
@@ -83126,7 +83298,7 @@ var init_parse_package_json = __esm({
|
|
|
83126
83298
|
|
|
83127
83299
|
// src/lockfile.ts
|
|
83128
83300
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
83129
|
-
import { readFileSync as readFileSync9, existsSync as
|
|
83301
|
+
import { readFileSync as readFileSync9, existsSync as existsSync7, statSync } from "node:fs";
|
|
83130
83302
|
import { join as join10 } from "node:path";
|
|
83131
83303
|
function readFileSafe(path2) {
|
|
83132
83304
|
const size = statSync(path2).size;
|
|
@@ -83143,7 +83315,7 @@ function discoverChanges(cwd2, config3) {
|
|
|
83143
83315
|
const pythonDepFiles = ["requirements.txt", "Pipfile.lock", "poetry.lock"];
|
|
83144
83316
|
let pythonPackages = [];
|
|
83145
83317
|
for (const pyFile of pythonDepFiles) {
|
|
83146
|
-
if (
|
|
83318
|
+
if (existsSync7(join10(cwd2, pyFile))) {
|
|
83147
83319
|
const pyPkgs = parsePythonDepFile(cwd2, pyFile);
|
|
83148
83320
|
for (const p of pyPkgs) {
|
|
83149
83321
|
if (p.version === "latest") continue;
|
|
@@ -83168,66 +83340,53 @@ function discoverChanges(cwd2, config3) {
|
|
|
83168
83340
|
const headContent = readFileSafe(lockfileInfo.path);
|
|
83169
83341
|
const headParsed = parseLockfileByType(headContent, lockfileInfo.type);
|
|
83170
83342
|
const directDeps = getDirectDeps(cwd2);
|
|
83171
|
-
if (config3.scanAll) {
|
|
83172
|
-
const packages2 = [];
|
|
83173
|
-
for (const [name, entry] of headParsed.packages) {
|
|
83174
|
-
if (packages2.length >= config3.maxPackages) break;
|
|
83175
|
-
if (entry.optional && entry.hasPlatformRestriction) continue;
|
|
83176
|
-
if (name === SELF_PACKAGE) continue;
|
|
83177
|
-
packages2.push({
|
|
83178
|
-
name,
|
|
83179
|
-
version: entry.version,
|
|
83180
|
-
previousVersion: null,
|
|
83181
|
-
isNew: true
|
|
83182
|
-
});
|
|
83183
|
-
}
|
|
83184
|
-
return { packages: packages2, pythonPackages, method: "scan-all", skipped: [] };
|
|
83185
|
-
}
|
|
83186
83343
|
if (config3.baseLockfile) {
|
|
83187
|
-
if (!
|
|
83344
|
+
if (!existsSync7(config3.baseLockfile)) {
|
|
83188
83345
|
throw new Error(`Base lockfile not found: ${config3.baseLockfile}`);
|
|
83189
83346
|
}
|
|
83190
|
-
const
|
|
83191
|
-
const baseParsed = parseLockfile(baseContent2);
|
|
83192
|
-
const diff2 = diffLockfiles(baseParsed, headParsed, config3.maxPackages, directDeps);
|
|
83193
|
-
return {
|
|
83194
|
-
packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
|
|
83195
|
-
pythonPackages,
|
|
83196
|
-
method: "base-lockfile",
|
|
83197
|
-
skipped: diff2.skipped
|
|
83198
|
-
};
|
|
83199
|
-
}
|
|
83200
|
-
const baseContent = getGitBaseLockfile(cwd2);
|
|
83201
|
-
if (baseContent !== null) {
|
|
83347
|
+
const baseContent = readFileSafe(config3.baseLockfile);
|
|
83202
83348
|
const baseParsed = parseLockfile(baseContent);
|
|
83203
83349
|
const diff2 = diffLockfiles(baseParsed, headParsed, config3.maxPackages, directDeps);
|
|
83204
83350
|
return {
|
|
83205
83351
|
packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
|
|
83206
83352
|
pythonPackages,
|
|
83207
|
-
method: "
|
|
83353
|
+
method: "base-lockfile",
|
|
83208
83354
|
skipped: diff2.skipped
|
|
83209
83355
|
};
|
|
83210
83356
|
}
|
|
83211
|
-
|
|
83212
|
-
|
|
83213
|
-
|
|
83214
|
-
|
|
83215
|
-
|
|
83216
|
-
const diff2 = diffPackageJsons(basePkgJson, headPkgJson, config3.maxPackages);
|
|
83217
|
-
const resolved = diff2.changes.map((change) => {
|
|
83218
|
-
const lockEntry = headParsed.packages.get(change.name);
|
|
83219
|
-
return {
|
|
83220
|
-
...change,
|
|
83221
|
-
newVersion: lockEntry?.version ?? change.newVersion
|
|
83222
|
-
};
|
|
83223
|
-
});
|
|
83357
|
+
if (!config3.scanAll) {
|
|
83358
|
+
const baseContent = getGitBaseLockfile(cwd2);
|
|
83359
|
+
if (baseContent !== null) {
|
|
83360
|
+
const baseParsed = parseLockfile(baseContent);
|
|
83361
|
+
const diff2 = diffLockfiles(baseParsed, headParsed, config3.maxPackages, directDeps);
|
|
83224
83362
|
return {
|
|
83225
|
-
packages:
|
|
83363
|
+
packages: diff2.changes.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
|
|
83226
83364
|
pythonPackages,
|
|
83227
|
-
method: "
|
|
83228
|
-
skipped:
|
|
83365
|
+
method: "git-diff",
|
|
83366
|
+
skipped: diff2.skipped
|
|
83229
83367
|
};
|
|
83230
83368
|
}
|
|
83369
|
+
const pkgJsonPath = join10(cwd2, "package.json");
|
|
83370
|
+
if (existsSync7(pkgJsonPath)) {
|
|
83371
|
+
const headPkgJson = readFileSafe(pkgJsonPath);
|
|
83372
|
+
const basePkgJson = getGitBaseFile(cwd2, "package.json");
|
|
83373
|
+
if (basePkgJson !== null) {
|
|
83374
|
+
const diff2 = diffPackageJsons(basePkgJson, headPkgJson, config3.maxPackages);
|
|
83375
|
+
const resolved = diff2.changes.map((change) => {
|
|
83376
|
+
const lockEntry = headParsed.packages.get(change.name);
|
|
83377
|
+
return {
|
|
83378
|
+
...change,
|
|
83379
|
+
newVersion: lockEntry?.version ?? change.newVersion
|
|
83380
|
+
};
|
|
83381
|
+
});
|
|
83382
|
+
return {
|
|
83383
|
+
packages: resolved.map(toPackageInput).filter((p) => p.name !== SELF_PACKAGE),
|
|
83384
|
+
pythonPackages,
|
|
83385
|
+
method: "fallback",
|
|
83386
|
+
skipped: []
|
|
83387
|
+
};
|
|
83388
|
+
}
|
|
83389
|
+
}
|
|
83231
83390
|
}
|
|
83232
83391
|
const packages = [];
|
|
83233
83392
|
for (const [name, entry] of headParsed.packages) {
|
|
@@ -83241,7 +83400,7 @@ function discoverChanges(cwd2, config3) {
|
|
|
83241
83400
|
isNew: true
|
|
83242
83401
|
});
|
|
83243
83402
|
}
|
|
83244
|
-
return { packages, pythonPackages, method: "
|
|
83403
|
+
return { packages, pythonPackages, method: "scan-all", skipped: [] };
|
|
83245
83404
|
}
|
|
83246
83405
|
function findLockfile(cwd2) {
|
|
83247
83406
|
const candidates = [
|
|
@@ -83252,7 +83411,7 @@ function findLockfile(cwd2) {
|
|
|
83252
83411
|
];
|
|
83253
83412
|
for (const [name, type] of candidates) {
|
|
83254
83413
|
const p = join10(cwd2, name);
|
|
83255
|
-
if (
|
|
83414
|
+
if (existsSync7(p)) return { path: p, type };
|
|
83256
83415
|
}
|
|
83257
83416
|
return null;
|
|
83258
83417
|
}
|
|
@@ -83514,7 +83673,7 @@ async function callAnalyzeAPI(packages, config3, onProgress) {
|
|
|
83514
83673
|
const results = [];
|
|
83515
83674
|
let completed = 0;
|
|
83516
83675
|
const tTotal = Date.now();
|
|
83517
|
-
if (onProgress) onProgress(0, packages.length,
|
|
83676
|
+
if (onProgress) onProgress(0, packages.length, []);
|
|
83518
83677
|
for (let i = 0; i < batches.length; i++) {
|
|
83519
83678
|
const batch = batches[i];
|
|
83520
83679
|
const tBatch = Date.now();
|
|
@@ -83522,7 +83681,7 @@ async function callAnalyzeAPI(packages, config3, onProgress) {
|
|
|
83522
83681
|
if (process.env.DG_PERF) console.error(`[CLI-PERF] batch ${i + 1}/${batches.length}: ${batch.length} packages \u2192 ${Date.now() - tBatch}ms`);
|
|
83523
83682
|
completed += batch.length;
|
|
83524
83683
|
if (onProgress) {
|
|
83525
|
-
onProgress(completed, packages.length,
|
|
83684
|
+
onProgress(completed, packages.length, batch.map((p) => p.name));
|
|
83526
83685
|
}
|
|
83527
83686
|
results.push(result);
|
|
83528
83687
|
}
|
|
@@ -83901,6 +84060,10 @@ function initialState(dryRun, firstRun) {
|
|
|
83901
84060
|
};
|
|
83902
84061
|
}
|
|
83903
84062
|
function reducer(state, action) {
|
|
84063
|
+
if (process.env.DG_DEBUG_WIZARD && action.type !== "scan_progress") {
|
|
84064
|
+
process.stderr.write(`[wizard] action=${action.type} phase=${state.phase}
|
|
84065
|
+
`);
|
|
84066
|
+
}
|
|
83904
84067
|
switch (action.type) {
|
|
83905
84068
|
// ── First-run guided tour transitions ──────────────────────────────────
|
|
83906
84069
|
case "welcome_yes":
|
|
@@ -84119,18 +84282,26 @@ function useInit(opts = {}) {
|
|
|
84119
84282
|
const projects = state.projects.length > 0 ? state.projects : [{ path: opts.cwd ?? process.cwd() }];
|
|
84120
84283
|
const allOutcomes = [];
|
|
84121
84284
|
for (const proj of projects) {
|
|
84285
|
+
if (process.env.DG_DEBUG_WIZARD) process.stderr.write(`[wizard] scanning ${proj.path}
|
|
84286
|
+
`);
|
|
84122
84287
|
const outcome = await scanFn(proj.path, config3, (p) => {
|
|
84123
84288
|
dispatch({ type: "scan_progress", progress: p });
|
|
84124
84289
|
});
|
|
84290
|
+
if (process.env.DG_DEBUG_WIZARD) process.stderr.write(`[wizard] scan done ${proj.path} status=${outcome.status}
|
|
84291
|
+
`);
|
|
84125
84292
|
allOutcomes.push(outcome);
|
|
84126
84293
|
}
|
|
84127
|
-
const allPackages =
|
|
84128
|
-
|
|
84129
|
-
)
|
|
84130
|
-
|
|
84131
|
-
|
|
84132
|
-
|
|
84133
|
-
|
|
84294
|
+
const allPackages = [];
|
|
84295
|
+
const seen = /* @__PURE__ */ new Set();
|
|
84296
|
+
for (const outcome of allOutcomes) {
|
|
84297
|
+
for (const pkg of outcome.result?.result.packages ?? []) {
|
|
84298
|
+
const key = `${pkg.name}@${pkg.version}`;
|
|
84299
|
+
if (seen.has(key)) continue;
|
|
84300
|
+
seen.add(key);
|
|
84301
|
+
allPackages.push(pkg);
|
|
84302
|
+
}
|
|
84303
|
+
}
|
|
84304
|
+
const totalScanned = seen.size;
|
|
84134
84305
|
const totalDuration = allOutcomes.reduce(
|
|
84135
84306
|
(sum, o) => sum + (o.result?.durationMs ?? 0),
|
|
84136
84307
|
0
|
|
@@ -87239,20 +87410,14 @@ var init_InitApp = __esm({
|
|
|
87239
87410
|
const { exit } = use_app_default();
|
|
87240
87411
|
useTerminalSize();
|
|
87241
87412
|
const [yesNoCursor, setYesNoCursor] = (0, import_react27.useState)(defaultYesNoCursor(state.phase));
|
|
87242
|
-
const
|
|
87413
|
+
const prevPhaseRef = (0, import_react27.useRef)(state.phase);
|
|
87414
|
+
const [, forceTick] = (0, import_react27.useState)(0);
|
|
87243
87415
|
(0, import_react27.useEffect)(() => {
|
|
87244
|
-
if (
|
|
87245
|
-
|
|
87246
|
-
|
|
87247
|
-
|
|
87248
|
-
|
|
87249
|
-
if (altScreenActiveRef.current) {
|
|
87250
|
-
process.stdout.write("\x1B[?1049l");
|
|
87251
|
-
altScreenActiveRef.current = false;
|
|
87252
|
-
}
|
|
87253
|
-
process.stdout.write("\x1B[?25h");
|
|
87254
|
-
};
|
|
87255
|
-
}, []);
|
|
87416
|
+
if (prevPhaseRef.current === "run_scan" && state.phase === "result_first_scan") {
|
|
87417
|
+
Promise.resolve().then(() => forceTick((n) => n + 1));
|
|
87418
|
+
}
|
|
87419
|
+
prevPhaseRef.current = state.phase;
|
|
87420
|
+
}, [state.phase]);
|
|
87256
87421
|
(0, import_react27.useEffect)(() => {
|
|
87257
87422
|
if (YES_NO_PHASES.has(state.phase)) {
|
|
87258
87423
|
setYesNoCursor(defaultYesNoCursor(state.phase));
|
|
@@ -87654,8 +87819,7 @@ var init_InitApp = __esm({
|
|
|
87654
87819
|
case "run_scan": {
|
|
87655
87820
|
const p = state.scanProgress;
|
|
87656
87821
|
if (p && p.total > 0) {
|
|
87657
|
-
|
|
87658
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ProgressBar, { value: p.done, total: p.total, label: currentLabel });
|
|
87822
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ProgressBar, { value: p.done, total: p.total });
|
|
87659
87823
|
}
|
|
87660
87824
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Scene, { mood: "scanning", color: "cyan", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spinner2, { label: "Scanning..." }) });
|
|
87661
87825
|
}
|
|
@@ -87907,19 +88071,25 @@ async function maybeOfferFirstRunWizard(opts) {
|
|
|
87907
88071
|
const { render: render2 } = await init_build2().then(() => build_exports);
|
|
87908
88072
|
const React21 = await Promise.resolve().then(() => __toESM(require_react()));
|
|
87909
88073
|
const { InitApp: InitApp2 } = await init_InitApp().then(() => InitApp_exports);
|
|
87910
|
-
const {
|
|
87911
|
-
|
|
87912
|
-
|
|
87913
|
-
|
|
87914
|
-
|
|
87915
|
-
|
|
87916
|
-
|
|
87917
|
-
|
|
87918
|
-
|
|
87919
|
-
|
|
87920
|
-
|
|
87921
|
-
|
|
87922
|
-
|
|
88074
|
+
const { enterAltScreen: enterAltScreen2, leaveAltScreen: leaveAltScreen2 } = await Promise.resolve().then(() => (init_alt_screen(), alt_screen_exports));
|
|
88075
|
+
enterAltScreen2();
|
|
88076
|
+
try {
|
|
88077
|
+
const { waitUntilExit } = render2(
|
|
88078
|
+
React21.createElement(InitApp2, {
|
|
88079
|
+
firstRun: true,
|
|
88080
|
+
onReachedDone: () => {
|
|
88081
|
+
reachedDone = true;
|
|
88082
|
+
},
|
|
88083
|
+
onScanRan: () => {
|
|
88084
|
+
scanRanInWizard = true;
|
|
88085
|
+
}
|
|
88086
|
+
})
|
|
88087
|
+
);
|
|
88088
|
+
mounted = true;
|
|
88089
|
+
await waitUntilExit();
|
|
88090
|
+
} finally {
|
|
88091
|
+
leaveAltScreen2();
|
|
88092
|
+
}
|
|
87923
88093
|
} catch {
|
|
87924
88094
|
return;
|
|
87925
88095
|
}
|
|
@@ -88169,7 +88339,7 @@ var init_LoginApp = __esm({
|
|
|
88169
88339
|
|
|
88170
88340
|
// src/pip-wrapper.ts
|
|
88171
88341
|
import { spawn as spawn3 } from "node:child_process";
|
|
88172
|
-
import { readFileSync as readFileSync10, existsSync as
|
|
88342
|
+
import { readFileSync as readFileSync10, existsSync as existsSync8 } from "node:fs";
|
|
88173
88343
|
function parsePipArgs(args) {
|
|
88174
88344
|
let dgForce = false;
|
|
88175
88345
|
const filtered = [];
|
|
@@ -88232,7 +88402,7 @@ function pipFlagTakesValue(flag) {
|
|
|
88232
88402
|
return false;
|
|
88233
88403
|
}
|
|
88234
88404
|
function parseRequirementsFile(filePath) {
|
|
88235
|
-
if (!
|
|
88405
|
+
if (!existsSync8(filePath)) return [];
|
|
88236
88406
|
try {
|
|
88237
88407
|
const content = readFileSync10(filePath, "utf-8");
|
|
88238
88408
|
const specs = [];
|
|
@@ -88372,7 +88542,7 @@ var FileSavePrompt_exports = {};
|
|
|
88372
88542
|
__export(FileSavePrompt_exports, {
|
|
88373
88543
|
FileSavePrompt: () => FileSavePrompt
|
|
88374
88544
|
});
|
|
88375
|
-
import { existsSync as
|
|
88545
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync4 } from "node:fs";
|
|
88376
88546
|
import { dirname as dirname5, join as join11 } from "node:path";
|
|
88377
88547
|
function listDirectory(dir) {
|
|
88378
88548
|
try {
|
|
@@ -88474,7 +88644,7 @@ var init_FileSavePrompt = __esm({
|
|
|
88474
88644
|
if (key.return) {
|
|
88475
88645
|
const fullName = ensureJsonExtension(state.filename);
|
|
88476
88646
|
const fullPath = join11(state.directory, fullName);
|
|
88477
|
-
if (!state.confirmOverwrite &&
|
|
88647
|
+
if (!state.confirmOverwrite && existsSync9(fullPath)) {
|
|
88478
88648
|
dispatch({ type: "CONFIRM_OVERWRITE" });
|
|
88479
88649
|
return;
|
|
88480
88650
|
}
|
|
@@ -89735,7 +89905,7 @@ var init_ScoreHeader = __esm({
|
|
|
89735
89905
|
});
|
|
89736
89906
|
|
|
89737
89907
|
// src/ui/hooks/useExpandAnimation.ts
|
|
89738
|
-
function useExpandAnimation(targetHeight,
|
|
89908
|
+
function useExpandAnimation(targetHeight, active2, durationMs = 180) {
|
|
89739
89909
|
const [visibleLines, setVisibleLines] = (0, import_react32.useState)(0);
|
|
89740
89910
|
const timerRef = (0, import_react32.useRef)(null);
|
|
89741
89911
|
(0, import_react32.useEffect)(() => {
|
|
@@ -89743,7 +89913,7 @@ function useExpandAnimation(targetHeight, active, durationMs = 180) {
|
|
|
89743
89913
|
clearInterval(timerRef.current);
|
|
89744
89914
|
timerRef.current = null;
|
|
89745
89915
|
}
|
|
89746
|
-
if (!
|
|
89916
|
+
if (!active2 || targetHeight <= 0) {
|
|
89747
89917
|
setVisibleLines(0);
|
|
89748
89918
|
return;
|
|
89749
89919
|
}
|
|
@@ -89766,10 +89936,10 @@ function useExpandAnimation(targetHeight, active, durationMs = 180) {
|
|
|
89766
89936
|
timerRef.current = null;
|
|
89767
89937
|
}
|
|
89768
89938
|
};
|
|
89769
|
-
}, [
|
|
89939
|
+
}, [active2, targetHeight, durationMs]);
|
|
89770
89940
|
return {
|
|
89771
|
-
visibleLines:
|
|
89772
|
-
isAnimating:
|
|
89941
|
+
visibleLines: active2 ? visibleLines : 0,
|
|
89942
|
+
isAnimating: active2 && visibleLines > 0 && visibleLines < targetHeight
|
|
89773
89943
|
};
|
|
89774
89944
|
}
|
|
89775
89945
|
var import_react32;
|
|
@@ -90882,7 +91052,7 @@ var init_App2 = __esm({
|
|
|
90882
91052
|
(0, import_react35.useEffect)(() => {
|
|
90883
91053
|
prevPhaseRef.current = state.phase;
|
|
90884
91054
|
}, [state.phase]);
|
|
90885
|
-
const
|
|
91055
|
+
const leaveAltScreen2 = (0, import_react35.useCallback)(() => {
|
|
90886
91056
|
if (altScreenActiveRef.current && process.stdout.isTTY) {
|
|
90887
91057
|
process.stdout.write("\x1B[?1049l");
|
|
90888
91058
|
altScreenActiveRef.current = false;
|
|
@@ -90900,15 +91070,15 @@ var init_App2 = __esm({
|
|
|
90900
91070
|
process.exitCode = 0;
|
|
90901
91071
|
}
|
|
90902
91072
|
}
|
|
90903
|
-
|
|
91073
|
+
leaveAltScreen2();
|
|
90904
91074
|
exit();
|
|
90905
|
-
}, [state, config3, exit,
|
|
91075
|
+
}, [state, config3, exit, leaveAltScreen2]);
|
|
90906
91076
|
const exitWithMessage = (0, import_react35.useCallback)((message, exitCode) => {
|
|
90907
91077
|
process.exitCode = exitCode;
|
|
90908
|
-
|
|
91078
|
+
leaveAltScreen2();
|
|
90909
91079
|
process.stderr.write(message);
|
|
90910
91080
|
return setTimeout(() => exit(), 0);
|
|
90911
|
-
}, [exit,
|
|
91081
|
+
}, [exit, leaveAltScreen2]);
|
|
90912
91082
|
(0, import_react35.useEffect)(() => {
|
|
90913
91083
|
if (state.phase === "empty") {
|
|
90914
91084
|
const timer = exitWithMessage(`${state.message}
|
|
@@ -90936,7 +91106,7 @@ var init_App2 = __esm({
|
|
|
90936
91106
|
if (state.phase === "discovering" || state.phase === "scanning") {
|
|
90937
91107
|
if (input === "q" || key.escape) {
|
|
90938
91108
|
process.exitCode = 0;
|
|
90939
|
-
|
|
91109
|
+
leaveAltScreen2();
|
|
90940
91110
|
exit();
|
|
90941
91111
|
}
|
|
90942
91112
|
}
|
|
@@ -90953,7 +91123,7 @@ var init_App2 = __esm({
|
|
|
90953
91123
|
onConfirm: scanSelectedProjects,
|
|
90954
91124
|
onCancel: () => {
|
|
90955
91125
|
process.exitCode = 0;
|
|
90956
|
-
|
|
91126
|
+
leaveAltScreen2();
|
|
90957
91127
|
exit();
|
|
90958
91128
|
},
|
|
90959
91129
|
userStatus
|
|
@@ -91859,6 +92029,7 @@ init_telemetry();
|
|
|
91859
92029
|
init_config();
|
|
91860
92030
|
init_npm_wrapper();
|
|
91861
92031
|
init_update_check();
|
|
92032
|
+
init_alt_screen();
|
|
91862
92033
|
var CLI_VERSION = getVersion();
|
|
91863
92034
|
initTelemetry(CLI_VERSION);
|
|
91864
92035
|
function closestCommand(input, commands) {
|
|
@@ -91879,9 +92050,14 @@ function closestCommand(input, commands) {
|
|
|
91879
92050
|
return bestDist <= 3 ? best : null;
|
|
91880
92051
|
}
|
|
91881
92052
|
process.on("SIGINT", () => {
|
|
92053
|
+
leaveAltScreen();
|
|
91882
92054
|
process.stderr.write("\n");
|
|
91883
92055
|
process.exit(130);
|
|
91884
92056
|
});
|
|
92057
|
+
process.on("SIGTERM", () => {
|
|
92058
|
+
leaveAltScreen();
|
|
92059
|
+
process.exit(143);
|
|
92060
|
+
});
|
|
91885
92061
|
var isInteractive = process.stdout.isTTY === true && !process.env.CI && !process.env.NO_COLOR;
|
|
91886
92062
|
async function main() {
|
|
91887
92063
|
const rawCommand = process.argv[2];
|
|
@@ -91913,10 +92089,15 @@ async function main() {
|
|
|
91913
92089
|
const { render: render3 } = await init_build2().then(() => build_exports);
|
|
91914
92090
|
const React22 = await Promise.resolve().then(() => __toESM(require_react()));
|
|
91915
92091
|
const { InitApp: InitApp2 } = await init_InitApp().then(() => InitApp_exports);
|
|
91916
|
-
|
|
91917
|
-
|
|
91918
|
-
|
|
91919
|
-
|
|
92092
|
+
enterAltScreen();
|
|
92093
|
+
try {
|
|
92094
|
+
const { waitUntilExit } = render3(
|
|
92095
|
+
React22.createElement(InitApp2, { firstRun: true, returning: true })
|
|
92096
|
+
);
|
|
92097
|
+
await waitUntilExit();
|
|
92098
|
+
} finally {
|
|
92099
|
+
leaveAltScreen();
|
|
92100
|
+
}
|
|
91920
92101
|
try {
|
|
91921
92102
|
const { markFirstRunComplete: markFirstRunComplete2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
|
|
91922
92103
|
markFirstRunComplete2();
|