@westbayberry/dg 2.0.7 → 2.0.10

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 (53) hide show
  1. package/README.md +17 -12
  2. package/dist/api/analyze.js +134 -34
  3. package/dist/audit-ui/export.js +3 -4
  4. package/dist/auth/device-login.js +13 -9
  5. package/dist/auth/store.js +43 -26
  6. package/dist/bin/dg.js +5 -0
  7. package/dist/commands/audit.js +14 -4
  8. package/dist/commands/config.js +3 -5
  9. package/dist/commands/doctor.js +3 -3
  10. package/dist/commands/explain.js +138 -6
  11. package/dist/commands/licenses.js +37 -24
  12. package/dist/commands/login.js +12 -3
  13. package/dist/commands/logout.js +15 -4
  14. package/dist/commands/scan.js +1 -1
  15. package/dist/commands/service.js +76 -24
  16. package/dist/commands/status.js +38 -4
  17. package/dist/commands/types.js +1 -0
  18. package/dist/config/settings.js +102 -22
  19. package/dist/install-ui/prompt.js +5 -2
  20. package/dist/launcher/install-preflight.js +158 -0
  21. package/dist/launcher/live-install.js +11 -2
  22. package/dist/launcher/output-redaction.js +5 -3
  23. package/dist/launcher/pip-report.js +18 -2
  24. package/dist/launcher/preflight-prompt.js +31 -12
  25. package/dist/launcher/run.js +87 -8
  26. package/dist/proxy/ca.js +69 -29
  27. package/dist/proxy/enforcement.js +41 -3
  28. package/dist/proxy/worker.js +21 -9
  29. package/dist/runtime/first-run.js +33 -2
  30. package/dist/runtime/nudges.js +9 -2
  31. package/dist/scan/analyze-worker.js +18 -8
  32. package/dist/scan/collect.js +35 -28
  33. package/dist/scan/command.js +80 -40
  34. package/dist/scan/discovery.js +9 -3
  35. package/dist/scan/render.js +22 -6
  36. package/dist/scan/scanner-report.js +89 -12
  37. package/dist/scan/staged.js +69 -7
  38. package/dist/scan-ui/LegacyApp.js +10 -48
  39. package/dist/scan-ui/components/InteractiveResultsView.js +171 -111
  40. package/dist/scan-ui/components/ProjectSelector.js +3 -3
  41. package/dist/scan-ui/components/ScoreHeader.js +8 -4
  42. package/dist/scan-ui/hooks/useScan.js +74 -27
  43. package/dist/scan-ui/launch.js +18 -4
  44. package/dist/service/state.js +15 -4
  45. package/dist/service/trust-store.js +23 -2
  46. package/dist/setup/git-hook.js +28 -17
  47. package/dist/setup/plan.js +302 -18
  48. package/dist/state/cleanup-registry.js +65 -8
  49. package/dist/state/locks.js +95 -9
  50. package/dist/state/sessions.js +66 -2
  51. package/dist/verify/package-check.js +22 -3
  52. package/dist/verify/preflight.js +328 -170
  53. package/package.json +1 -1
@@ -1,7 +1,8 @@
1
- import { mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
1
+ import { mkdirSync, readdirSync, readFileSync, rmSync, statSync } from "node:fs";
2
2
  import { appendFile, mkdir, readdir, rm, stat } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { randomUUID } from "node:crypto";
5
+ import { isProcessAlive } from "./locks.js";
5
6
  import { readJsonFile, writeJsonFileAtomic } from "./store.js";
6
7
  export async function createSession(paths, id = randomUUID()) {
7
8
  assertSessionId(id);
@@ -136,6 +137,68 @@ export function findStaleSessionsSync(paths, options) {
136
137
  stale
137
138
  };
138
139
  }
140
+ export const DEAD_SESSION_TTL_MS = 24 * 60 * 60 * 1000;
141
+ const DEAD_SESSION_PRUNE_MAX = 16;
142
+ export function pruneDeadSessionsSync(paths, options = {}) {
143
+ const olderThanMs = options.olderThanMs ?? DEAD_SESSION_TTL_MS;
144
+ const maxRemovals = options.maxRemovals ?? DEAD_SESSION_PRUNE_MAX;
145
+ const now = options.now?.getTime() ?? Date.now();
146
+ let entries;
147
+ try {
148
+ entries = readdirSync(paths.sessionsDir, {
149
+ withFileTypes: true
150
+ });
151
+ }
152
+ catch {
153
+ return {
154
+ removed: []
155
+ };
156
+ }
157
+ const removed = [];
158
+ for (const entry of entries) {
159
+ if (removed.length >= maxRemovals) {
160
+ break;
161
+ }
162
+ if (!entry.isDirectory() || !isValidSessionId(entry.name)) {
163
+ continue;
164
+ }
165
+ const dir = join(paths.sessionsDir, entry.name);
166
+ let details;
167
+ try {
168
+ details = statSync(dir);
169
+ }
170
+ catch {
171
+ continue;
172
+ }
173
+ if (now - details.mtimeMs < olderThanMs || sessionWorkerAlive(dir)) {
174
+ continue;
175
+ }
176
+ try {
177
+ rmSync(dir, {
178
+ force: true,
179
+ recursive: true
180
+ });
181
+ removed.push(entry.name);
182
+ }
183
+ catch {
184
+ continue;
185
+ }
186
+ }
187
+ return {
188
+ removed
189
+ };
190
+ }
191
+ function sessionWorkerAlive(dir) {
192
+ let raw;
193
+ try {
194
+ raw = readFileSync(join(dir, "pid"), "utf8");
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ const pid = Number.parseInt(raw.trim(), 10);
200
+ return Number.isInteger(pid) && pid > 0 && isProcessAlive(pid);
201
+ }
139
202
  export function sweepStaleSessionsSync(paths, options) {
140
203
  const report = findStaleSessionsSync(paths, options);
141
204
  for (const id of report.stale) {
@@ -154,7 +217,8 @@ function sessionFiles(dir) {
154
217
  ca: join(dir, "ca.pem"),
155
218
  block: join(dir, "block.json"),
156
219
  hash: join(dir, "hash.json"),
157
- log: join(dir, "log.jsonl")
220
+ log: join(dir, "log.jsonl"),
221
+ pid: join(dir, "pid")
158
222
  };
159
223
  }
160
224
  function assertSessionId(id) {
@@ -3,7 +3,7 @@ import { resolve } from "node:path";
3
3
  import { analyzePackages, AnalyzeError } from "../api/analyze.js";
4
4
  import { createTheme } from "../presentation/theme.js";
5
5
  import { resolvePresentation } from "../presentation/mode.js";
6
- import { isSupportedLockfilePath } from "./preflight.js";
6
+ import { isRemotePackageSpec, isSupportedLockfilePath } from "./preflight.js";
7
7
  import { authStatus } from "../auth/store.js";
8
8
  import { EXIT_TOOL_ERROR, EXIT_UNAVAILABLE } from "../commands/types.js";
9
9
  const REGISTRIES = { npm: "npm", pypi: "pypi" };
@@ -16,6 +16,9 @@ function parseSpec(target) {
16
16
  const registry = target.slice(0, colon).toLowerCase();
17
17
  const ecosystem = REGISTRIES[registry];
18
18
  if (!ecosystem) {
19
+ if (registry === "cargo") {
20
+ return { error: `the cargo registry is not yet supported. ${DEEP_VERIFY_HINT}` };
21
+ }
19
22
  return { error: `unknown registry '${registry}'. ${DEEP_VERIFY_HINT}` };
20
23
  }
21
24
  const rest = target.slice(colon + 1).trim();
@@ -187,6 +190,7 @@ export async function maybeVerifyPackage(args) {
187
190
  let verbose = false;
188
191
  let sarif = false;
189
192
  let outputPath = null;
193
+ let outputFlagMissingPath;
190
194
  let target;
191
195
  let unknownFlag;
192
196
  for (let index = 0; index < rest.length; index += 1) {
@@ -204,8 +208,14 @@ export async function maybeVerifyPackage(args) {
204
208
  sarif = true;
205
209
  }
206
210
  else if (arg === "--output" || arg === "-o") {
207
- outputPath = rest[index + 1] ?? null;
208
- index += 1;
211
+ const next = rest[index + 1];
212
+ if (!next || next.startsWith("-")) {
213
+ outputFlagMissingPath = outputFlagMissingPath ?? arg;
214
+ }
215
+ else {
216
+ outputPath = next;
217
+ index += 1;
218
+ }
209
219
  }
210
220
  else if (arg.startsWith("-")) {
211
221
  unknownFlag = unknownFlag ?? arg;
@@ -220,6 +230,15 @@ export async function maybeVerifyPackage(args) {
220
230
  if (isSupportedLockfilePath(target) || existsSync(resolve(target))) {
221
231
  return { handled: false, result: noop };
222
232
  }
233
+ if (isRemotePackageSpec(target)) {
234
+ return { handled: false, result: noop };
235
+ }
236
+ if (outputFlagMissingPath) {
237
+ return {
238
+ handled: true,
239
+ result: { exitCode: 2, stdout: "", stderr: `dg verify: ${outputFlagMissingPath} requires a path. Run 'dg verify --help'.\n` }
240
+ };
241
+ }
223
242
  if (unknownFlag) {
224
243
  return {
225
244
  handled: true,