@westbayberry/dg 2.0.8 → 2.0.11

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 (50) 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/launcher/install-preflight.js +81 -12
  20. package/dist/launcher/output-redaction.js +5 -3
  21. package/dist/launcher/preflight-prompt.js +31 -12
  22. package/dist/launcher/run.js +87 -8
  23. package/dist/proxy/ca.js +69 -29
  24. package/dist/proxy/enforcement.js +41 -3
  25. package/dist/proxy/worker.js +21 -9
  26. package/dist/runtime/first-run.js +33 -2
  27. package/dist/runtime/nudges.js +9 -2
  28. package/dist/scan/analyze-worker.js +18 -8
  29. package/dist/scan/collect.js +45 -32
  30. package/dist/scan/command.js +80 -40
  31. package/dist/scan/discovery.js +75 -7
  32. package/dist/scan/render.js +22 -6
  33. package/dist/scan/scanner-report.js +89 -12
  34. package/dist/scan/staged.js +69 -7
  35. package/dist/scan-ui/LegacyApp.js +10 -48
  36. package/dist/scan-ui/components/InteractiveResultsView.js +171 -111
  37. package/dist/scan-ui/components/ProjectSelector.js +3 -3
  38. package/dist/scan-ui/components/ScoreHeader.js +8 -4
  39. package/dist/scan-ui/hooks/useScan.js +74 -27
  40. package/dist/scan-ui/launch.js +21 -4
  41. package/dist/service/state.js +15 -4
  42. package/dist/service/trust-store.js +23 -2
  43. package/dist/setup/git-hook.js +28 -17
  44. package/dist/setup/plan.js +302 -18
  45. package/dist/state/cleanup-registry.js +65 -8
  46. package/dist/state/locks.js +95 -9
  47. package/dist/state/sessions.js +66 -2
  48. package/dist/verify/package-check.js +22 -3
  49. package/dist/verify/preflight.js +328 -170
  50. package/package.json +1 -1
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useEffect, useLayoutEffect, useCallback, useRef } from "react";
2
+ import { useEffect, useCallback } from "react";
3
3
  import { Box, Text, useApp, useInput } from "ink";
4
- import { getStoredApiKey } from "./shims.js";
5
4
  import { useScan } from "./hooks/useScan.js";
6
5
  import { Spinner } from "./components/Spinner.js";
7
6
  import { ProgressBar } from "./components/ProgressBar.js";
@@ -11,56 +10,21 @@ import { ProjectSelector } from "./components/ProjectSelector.js";
11
10
  import { SetupBanner } from "./components/SetupBanner.js";
12
11
  import { useTerminalSize } from "./hooks/useTerminalSize.js";
13
12
  import { scanExitCode } from "./shims.js";
14
- import { enterTui, leaveTui, showCursor } from "./alt-screen.js";
13
+ import { leaveTui, showCursor, tuiIsActive } from "./alt-screen.js";
15
14
  import { formatResetDate } from "../install-ui/block-render.js";
16
- export const App = ({ config, userStatus, scanUsage, setupIssues = [], initialView }) => {
15
+ export const App = ({ config, userStatus, scanUsage, setupIssues = [], initialView, updateAvailable }) => {
17
16
  const { state, scanSelectedProjects, restartSelection } = useScan(config);
18
17
  const { exit } = useApp();
19
18
  useTerminalSize();
20
- const prevPhaseRef = useRef(state.phase);
21
- const altScreenActiveRef = useRef(false);
22
- // Enter the alternate screen ONLY after we leave the discovering phase.
23
- // The spinner stays inline on the user's main terminal during discovery so
24
- // they see "Searching for dependencies..." in their normal scrollback rather
25
- // than a cleared screen. useLayoutEffect runs synchronously after React
26
- // commits the new tree but before Ink writes the next frame to stdout, so
27
- // post-discovery content lands directly in the alt buffer (avoiding the
28
- // "blank until keypress" diff-tracker mismatch documented in alt-screen.ts).
29
- useLayoutEffect(() => {
30
- if (state.phase === "discovering")
31
- return;
32
- if (!process.stdout.isTTY)
33
- return;
34
- if (altScreenActiveRef.current)
35
- return;
36
- enterTui();
37
- altScreenActiveRef.current = true;
38
- }, [state.phase]);
39
- // Cleanup on unmount: leave alt screen, restore cursor.
40
- useEffect(() => {
41
- return () => {
42
- if (altScreenActiveRef.current) {
43
- leaveTui();
44
- altScreenActiveRef.current = false;
45
- }
46
- else {
47
- showCursor();
48
- }
49
- };
50
- }, []);
51
- // Track phase transitions (Ink handles repainting automatically)
52
- useEffect(() => {
53
- prevPhaseRef.current = state.phase;
54
- }, [state.phase]);
55
19
  const leaveAltScreen = useCallback(() => {
56
- if (altScreenActiveRef.current) {
20
+ if (tuiIsActive()) {
57
21
  leaveTui();
58
- altScreenActiveRef.current = false;
59
22
  }
60
23
  else {
61
24
  showCursor();
62
25
  }
63
26
  }, []);
27
+ useEffect(() => () => leaveAltScreen(), [leaveAltScreen]);
64
28
  const handleResultsExit = useCallback(() => {
65
29
  if (state.phase === "results") {
66
30
  process.exitCode = scanExitCode(state.result.action, config.mode);
@@ -139,12 +103,7 @@ export const App = ({ config, userStatus, scanUsage, setupIssues = [], initialVi
139
103
  case "error":
140
104
  return _jsx(ErrorView, { error: state.error });
141
105
  case "free_cap_reached": {
142
- let hasKey = false;
143
- try {
144
- hasKey = !!getStoredApiKey();
145
- }
146
- catch { /* ignore — best-effort */ }
147
- return (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [hasKey ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", bold: true, children: "Your session expired." }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Run ", _jsx(Text, { color: "cyan", bold: true, children: "dg logout" }), " then ", _jsx(Text, { color: "cyan", bold: true, children: "dg login" }), " to re-authenticate."] })] })) : state.capReason === "prefix_cap" ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", bold: true, children: "Too many anonymous devices from your network this month." }), _jsxs(Text, { children: ["Sign in with ", _jsx(Text, { color: "cyan", bold: true, children: "dg login" }), " to keep scanning."] })] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Free monthly limit reached (", state.scansUsed.toLocaleString(), "/", state.maxScans.toLocaleString(), " packages)."] }), formatResetDate(state.resetsAt) ? _jsxs(Text, { dimColor: true, children: ["Resets ", formatResetDate(state.resetsAt), "."] }) : null, _jsxs(Text, { children: ["Upgrade to Pro with ", _jsx(Text, { color: "cyan", bold: true, children: "dg upgrade" }), " for 250k packages/month."] })] })), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "[q] quit" })] }));
106
+ return (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, children: [state.capReason === "prefix_cap" ? (_jsxs(_Fragment, { children: [_jsx(Text, { color: "yellow", bold: true, children: "Too many anonymous devices from your network this month." }), _jsxs(Text, { children: ["Sign in with ", _jsx(Text, { color: "cyan", bold: true, children: "dg login" }), " to keep scanning."] })] })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: "yellow", bold: true, children: ["Free monthly limit reached (", state.scansUsed.toLocaleString(), "/", state.maxScans.toLocaleString(), " packages)."] }), formatResetDate(state.resetsAt) ? _jsxs(Text, { dimColor: true, children: ["Resets ", formatResetDate(state.resetsAt), "."] }) : null, _jsxs(Text, { children: ["Upgrade to Pro at ", _jsx(Text, { color: "cyan", bold: true, children: "westbayberry.com/pricing" }), " for 250k packages/month."] })] })), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "[q] quit" })] }));
148
107
  }
149
108
  }
150
109
  })();
@@ -153,5 +112,8 @@ export const App = ({ config, userStatus, scanUsage, setupIssues = [], initialVi
153
112
  // actually needs to read.
154
113
  const showBanner = state.phase === "selecting" &&
155
114
  setupIssues.length > 0;
156
- return (_jsxs(Box, { flexDirection: "column", children: [showBanner ? _jsx(SetupBanner, { issues: setupIssues }) : null, content] }));
115
+ // Results fill the terminal height exactly; an extra line there overflows the alt screen.
116
+ const showUpdateLine = updateAvailable !== undefined &&
117
+ (state.phase === "selecting" || state.phase === "scanning");
118
+ return (_jsxs(Box, { flexDirection: "column", children: [showBanner ? _jsx(SetupBanner, { issues: setupIssues }) : null, content, showUpdateLine ? _jsx(Box, { paddingLeft: 1, children: _jsx(Text, { dimColor: true, children: updateAvailable }) }) : null] }));
157
119
  };