audit-trace 0.1.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.
Files changed (115) hide show
  1. package/README.md +101 -0
  2. package/dist/cli/ink/ReportTui.d.ts +8 -0
  3. package/dist/cli/ink/ReportTui.d.ts.map +1 -0
  4. package/dist/cli/ink/ReportTui.js +20 -0
  5. package/dist/cli/ink/ReportTui.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +150 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/core/audit-parser/normalize.d.ts +8 -0
  11. package/dist/core/audit-parser/normalize.d.ts.map +1 -0
  12. package/dist/core/audit-parser/normalize.js +107 -0
  13. package/dist/core/audit-parser/normalize.js.map +1 -0
  14. package/dist/core/audit-parser/run-audit.d.ts +9 -0
  15. package/dist/core/audit-parser/run-audit.d.ts.map +1 -0
  16. package/dist/core/audit-parser/run-audit.js +25 -0
  17. package/dist/core/audit-parser/run-audit.js.map +1 -0
  18. package/dist/core/graph-engine/load-lockfile.d.ts +20 -0
  19. package/dist/core/graph-engine/load-lockfile.d.ts.map +1 -0
  20. package/dist/core/graph-engine/load-lockfile.js +43 -0
  21. package/dist/core/graph-engine/load-lockfile.js.map +1 -0
  22. package/dist/core/graph-engine/npm-lock.d.ts +5 -0
  23. package/dist/core/graph-engine/npm-lock.d.ts.map +1 -0
  24. package/dist/core/graph-engine/npm-lock.js +159 -0
  25. package/dist/core/graph-engine/npm-lock.js.map +1 -0
  26. package/dist/core/graph-engine/pnpm-lock.d.ts +4 -0
  27. package/dist/core/graph-engine/pnpm-lock.d.ts.map +1 -0
  28. package/dist/core/graph-engine/pnpm-lock.js +152 -0
  29. package/dist/core/graph-engine/pnpm-lock.js.map +1 -0
  30. package/dist/core/graph-engine/traverse.d.ts +17 -0
  31. package/dist/core/graph-engine/traverse.d.ts.map +1 -0
  32. package/dist/core/graph-engine/traverse.js +125 -0
  33. package/dist/core/graph-engine/traverse.js.map +1 -0
  34. package/dist/core/graph-engine/yarn-lock.d.ts +4 -0
  35. package/dist/core/graph-engine/yarn-lock.d.ts.map +1 -0
  36. package/dist/core/graph-engine/yarn-lock.js +128 -0
  37. package/dist/core/graph-engine/yarn-lock.js.map +1 -0
  38. package/dist/core/models.d.ts +88 -0
  39. package/dist/core/models.d.ts.map +1 -0
  40. package/dist/core/models.js +9 -0
  41. package/dist/core/models.js.map +1 -0
  42. package/dist/core/ownership/tracer.d.ts +16 -0
  43. package/dist/core/ownership/tracer.d.ts.map +1 -0
  44. package/dist/core/ownership/tracer.js +65 -0
  45. package/dist/core/ownership/tracer.js.map +1 -0
  46. package/dist/core/remediation-engine/engine.d.ts +3 -0
  47. package/dist/core/remediation-engine/engine.d.ts.map +1 -0
  48. package/dist/core/remediation-engine/engine.js +42 -0
  49. package/dist/core/remediation-engine/engine.js.map +1 -0
  50. package/dist/core/risk-engine/scripts.d.ts +6 -0
  51. package/dist/core/risk-engine/scripts.d.ts.map +1 -0
  52. package/dist/core/risk-engine/scripts.js +19 -0
  53. package/dist/core/risk-engine/scripts.js.map +1 -0
  54. package/dist/core/risk-engine/workspace-risk.d.ts +2 -0
  55. package/dist/core/risk-engine/workspace-risk.d.ts.map +1 -0
  56. package/dist/core/risk-engine/workspace-risk.js +2 -0
  57. package/dist/core/risk-engine/workspace-risk.js.map +1 -0
  58. package/dist/core/workspace-engine/detect.d.ts +3 -0
  59. package/dist/core/workspace-engine/detect.d.ts.map +1 -0
  60. package/dist/core/workspace-engine/detect.js +53 -0
  61. package/dist/core/workspace-engine/detect.js.map +1 -0
  62. package/dist/index.d.ts +3 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +3 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/ink/ReportTui.d.ts +8 -0
  67. package/dist/ink/ReportTui.d.ts.map +1 -0
  68. package/dist/ink/ReportTui.js +20 -0
  69. package/dist/ink/ReportTui.js.map +1 -0
  70. package/dist/integrations/ci-mode/policy.d.ts +17 -0
  71. package/dist/integrations/ci-mode/policy.d.ts.map +1 -0
  72. package/dist/integrations/ci-mode/policy.js +71 -0
  73. package/dist/integrations/ci-mode/policy.js.map +1 -0
  74. package/dist/integrations/lockfile-diff/compare.d.ts +11 -0
  75. package/dist/integrations/lockfile-diff/compare.d.ts.map +1 -0
  76. package/dist/integrations/lockfile-diff/compare.js +44 -0
  77. package/dist/integrations/lockfile-diff/compare.js.map +1 -0
  78. package/dist/integrations/reachability/madge-check.d.ts +12 -0
  79. package/dist/integrations/reachability/madge-check.d.ts.map +1 -0
  80. package/dist/integrations/reachability/madge-check.js +41 -0
  81. package/dist/integrations/reachability/madge-check.js.map +1 -0
  82. package/dist/lib/analyze.d.ts +22 -0
  83. package/dist/lib/analyze.d.ts.map +1 -0
  84. package/dist/lib/analyze.js +107 -0
  85. package/dist/lib/analyze.js.map +1 -0
  86. package/dist/output/html-reporter.d.ts +4 -0
  87. package/dist/output/html-reporter.d.ts.map +1 -0
  88. package/dist/output/html-reporter.js +18 -0
  89. package/dist/output/html-reporter.js.map +1 -0
  90. package/dist/output/json-reporter.d.ts +5 -0
  91. package/dist/output/json-reporter.d.ts.map +1 -0
  92. package/dist/output/json-reporter.js +18 -0
  93. package/dist/output/json-reporter.js.map +1 -0
  94. package/dist/output/markdown-reporter.d.ts +4 -0
  95. package/dist/output/markdown-reporter.d.ts.map +1 -0
  96. package/dist/output/markdown-reporter.js +28 -0
  97. package/dist/output/markdown-reporter.js.map +1 -0
  98. package/dist/output/terminal-renderer.d.ts +8 -0
  99. package/dist/output/terminal-renderer.d.ts.map +1 -0
  100. package/dist/output/terminal-renderer.js +51 -0
  101. package/dist/output/terminal-renderer.js.map +1 -0
  102. package/dist/output/tree-format.d.ts +3 -0
  103. package/dist/output/tree-format.d.ts.map +1 -0
  104. package/dist/output/tree-format.js +12 -0
  105. package/dist/output/tree-format.js.map +1 -0
  106. package/dist/plugins/registry.d.ts +4 -0
  107. package/dist/plugins/registry.d.ts.map +1 -0
  108. package/dist/plugins/registry.js +8 -0
  109. package/dist/plugins/registry.js.map +1 -0
  110. package/dist/plugins/types.d.ts +10 -0
  111. package/dist/plugins/types.d.ts.map +1 -0
  112. package/dist/plugins/types.js +2 -0
  113. package/dist/plugins/types.js.map +1 -0
  114. package/examples/github-actions/ci.yml +34 -0
  115. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # audit-trace
2
+
3
+ `audit-trace` is a local-first CLI for **npm / pnpm / Yarn** projects. It combines **lockfile-aware dependency graphs** with **audit output** so you can see **which top-level dependencies introduce a vulnerable package**, short **remediation hints**, and **CI-friendly diagnostics** (structured `CiDiagnostic` codes for logs, job summaries, or PR comments).
4
+
5
+ ## Requirements
6
+
7
+ - Node.js **18+**
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install -g audit-trace
13
+ # or use npx
14
+ npx audit-trace report
15
+ ```
16
+
17
+ From source:
18
+
19
+ ```bash
20
+ git clone <repo>
21
+ cd audit-trace
22
+ npm install
23
+ npm run build
24
+ node dist/cli.js --help
25
+ ```
26
+
27
+ ## Quick start
28
+
29
+ ```bash
30
+ cd your-project
31
+ audit-trace report
32
+ audit-trace report --json
33
+ audit-trace report --ci --fail-on high --prod-only
34
+ ```
35
+
36
+ ### Interactive UI (Ink)
37
+
38
+ ```bash
39
+ audit-trace report --interactive
40
+ ```
41
+
42
+ Use **↑/↓** to browse findings, **q** to quit.
43
+
44
+ ## Commands
45
+
46
+ | Command | Description |
47
+ |--------|-------------|
48
+ | `report` (default) | Run package-manager audit + lockfile graph; print ownership paths & remediation hints |
49
+ | `why <pkg>` | Shortest path(s) from workspace root(s) to a package in the lockfile graph |
50
+ | `graph <pkg>` | Enumerate paths (capped) between roots and the package |
51
+ | `impact <pkg>` | Transitive consumers (reverse reachability in the graph) |
52
+ | `diff <before> <after>` | Compare two lockfiles (`--kind npm\|pnpm`) — added/removed package keys |
53
+
54
+ ## Flags (report)
55
+
56
+ - `--json` / `--markdown` / `--html` — output modes
57
+ - `--ci` — apply exit-code policy and print structured CI diagnostics to stderr
58
+ - `--ci-verbose` — more explanatory CI text
59
+ - `--fail-on <level>` — `critical` \| `high` \| `moderate` \| `low` \| `info` \| `none` (default: `high` in CI contexts; in local runs without `--ci`, exit code stays 0 unless `--ci` is passed)
60
+ - `--prod-only` — drop findings whose traced paths are dev-only (best-effort; requires dev flags in the lockfile)
61
+ - `--audit-file <path>` — parse audit JSON instead of invoking `npm|pnpm|yarn audit`
62
+ - `--pm npm\|pnpm\|yarn` — force audit runner
63
+ - `--entry <file>` — optional entry for **madge**-based reachability heuristic (tags titles)
64
+
65
+ ## CiDiagnostic codes
66
+
67
+ Stable codes emitted in JSON (`diagnostics[]`) and echoed in human CI summaries:
68
+
69
+ | Code | Meaning |
70
+ |------|---------|
71
+ | `NO_LOCKFILE` | No supported lockfile at project root — graph/ownership is degraded |
72
+ | `AUDIT_SOURCE_FALLBACK` | Audit subprocess failed or returned empty — verify tool versions |
73
+ | `FILTER_CONTEXT` | Some items excluded by `--prod-only` / future filters |
74
+ | `FAIL_HIGH_PROD` | High/critical findings matched the failure threshold |
75
+ | `FAIL_POLICY` | Generic policy failure (`--fail-on` and severity counts) |
76
+ | `GRAPH_BUILD_WARN` | Reserved for graph/parser warnings |
77
+
78
+ ## GitHub Actions
79
+
80
+ See [`examples/github-actions/ci.yml`](examples/github-actions/ci.yml) for a sample workflow posting JSON + human-readable sections.
81
+
82
+ ## Plugins (experimental)
83
+
84
+ Plugins can implement hooks such as `afterGraphBuilt`, `afterAuditNormalized`, `onCiDiagnostics`, and `formatReport`. Register via the internal `plugins/registry` API (local imports) — a config file loader can be added later.
85
+
86
+ ## Development
87
+
88
+ ```bash
89
+ npm test
90
+ npm run build
91
+ ```
92
+
93
+ ## Limitations
94
+
95
+ - **Yarn Berry** lockfiles and audits differ by release; classic `yarn.lock` + `yarn audit --json` are the primary targets.
96
+ - **Reachability** via `madge` is **heuristic** (static graph); dynamic `require` is not modeled.
97
+ - **Remediation** prefers `overrides` / `resolutions` when audit provides patched ranges; otherwise a manual upgrade path is suggested.
98
+
99
+ ## License
100
+
101
+ MIT
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ import type { AuditReport } from "../../core/models.js";
3
+ import type { OwnershipPath } from "../../core/ownership/tracer.js";
4
+ export declare function ReportTui(props: {
5
+ report: AuditReport;
6
+ ownership: OwnershipPath[];
7
+ }): React.ReactElement;
8
+ //# sourceMappingURL=ReportTui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportTui.d.ts","sourceRoot":"","sources":["../../../src/cli/ink/ReportTui.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAExC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAEpE,wBAAgB,SAAS,CAAC,KAAK,EAAE;IAC/B,MAAM,EAAE,WAAW,CAAC;IACpB,SAAS,EAAE,aAAa,EAAE,CAAC;CAC5B,GAAG,KAAK,CAAC,YAAY,CAwCrB"}
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { Box, Text, useInput } from "ink";
4
+ export function ReportTui(props) {
5
+ const [idx, setIdx] = useState(0);
6
+ useInput((input, key) => {
7
+ if (key.upArrow)
8
+ setIdx((i) => Math.max(0, i - 1));
9
+ if (key.downArrow)
10
+ setIdx((i) => Math.min(props.report.findings.length - 1, i + 1));
11
+ if (input === "q" || key.escape)
12
+ process.exit(0);
13
+ });
14
+ const f = props.report.findings[idx];
15
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, children: "audit-trace \u2014 interactive (\u2191/\u2193 navigate, q quit)" }), _jsx(Box, { marginTop: 1, children: _jsxs(Text, { dimColor: true, children: ["Finding ", idx + 1, "/", props.report.findings.length] }) }), f ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: f.severity === "critical" ? "red" : "yellow", children: ["[", f.severity, "] ", f.packageName] }), _jsx(Text, { children: f.title ?? f.id }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { bold: true, children: "Owners / paths sample" }), props.ownership
16
+ .filter((o) => o.packageName === f.packageName)
17
+ .slice(0, 5)
18
+ .map((o, i) => (_jsxs(Text, { children: ["via ", o.topLevelNames.join(", ") || "?", " \u2014 dev:", String(o.isDevDependency)] }, i)))] })] })) : (_jsx(Text, { children: "No findings." }))] }));
19
+ }
20
+ //# sourceMappingURL=ReportTui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReportTui.js","sourceRoot":"","sources":["../../../src/cli/ink/ReportTui.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAI1C,MAAM,UAAU,SAAS,CAAC,KAGzB;IACC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClC,QAAQ,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtB,IAAI,GAAG,CAAC,OAAO;YAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnD,IAAI,GAAG,CAAC,SAAS;YAAE,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACpF,IAAI,KAAK,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAErC,OAAO,CACL,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,OAAO,EAAE,CAAC,aACpC,KAAC,IAAI,IAAC,IAAI,sFAAwD,EAClE,KAAC,GAAG,IAAC,SAAS,EAAE,CAAC,YACf,MAAC,IAAI,IAAC,QAAQ,+BACH,GAAG,GAAG,CAAC,OAAG,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,IAC1C,GACH,EACL,CAAC,CAAC,CAAC,CAAC,CACH,MAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,SAAS,EAAE,CAAC,aACtC,MAAC,IAAI,IAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,kBACrD,CAAC,CAAC,QAAQ,QAAI,CAAC,CAAC,WAAW,IACxB,EACP,KAAC,IAAI,cAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,GAAQ,EAC9B,MAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,aACvC,KAAC,IAAI,IAAC,IAAI,4CAA6B,EACtC,KAAK,CAAC,SAAS;iCACb,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,WAAW,CAAC;iCAC9C,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;iCACX,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CACb,MAAC,IAAI,uBACE,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,kBAAS,MAAM,CAAC,CAAC,CAAC,eAAe,CAAC,KAD/D,CAAC,CAEL,CACR,CAAC,IACA,IACF,CACP,CAAC,CAAC,CAAC,CACF,KAAC,IAAI,+BAAoB,CAC1B,IACG,CACP,CAAC;AACJ,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from "commander";
3
+ import { resolve } from "node:path";
4
+ import { readFile } from "node:fs/promises";
5
+ import ora from "ora";
6
+ import { analyze } from "./lib/analyze.js";
7
+ import { renderPretty, printCiSummary } from "./output/terminal-renderer.js";
8
+ import { toJsonReport } from "./output/json-reporter.js";
9
+ import { toMarkdownReport } from "./output/markdown-reporter.js";
10
+ import { toHtmlReport } from "./output/html-reporter.js";
11
+ import { loadLockfileGraph } from "./core/graph-engine/load-lockfile.js";
12
+ import { buildIndexes, dfsAllPathsWithLimit, impactSet, shortestPathFromRoots, } from "./core/graph-engine/traverse.js";
13
+ import { diffLockfiles } from "./integrations/lockfile-diff/compare.js";
14
+ import React from "react";
15
+ import { render } from "ink";
16
+ import { ReportTui } from "./ink/ReportTui.js";
17
+ const program = new Command();
18
+ program
19
+ .name("audit-trace")
20
+ .description("Dependency vulnerability analysis with ownership tracing")
21
+ .version("0.1.0");
22
+ program
23
+ .command("report", { isDefault: true })
24
+ .description("Run audit and print ownership-aware report")
25
+ .option("-C, --cwd <dir>", "project root", process.cwd())
26
+ .option("--json", "machine-readable JSON")
27
+ .option("--markdown", "Markdown report")
28
+ .option("--html", "HTML report")
29
+ .option("--ci", "CI mode (exit codes + diagnostics)")
30
+ .option("--ci-verbose", "extra CI explanation on stderr")
31
+ .option("--fail-on <level>", "critical|high|moderate|low|info|none", "high")
32
+ .option("--prod-only", "filter devDependency paths when possible")
33
+ .option("--audit-file <path>", "read audit JSON instead of running pm audit")
34
+ .option("--pm <name>", "npm|pnpm|yarn")
35
+ .option("--entry <file>", "entry file for madge reachability heuristics")
36
+ .option("--assume-reachable", "skip strict reachability interpretation in policy")
37
+ .option("-i, --interactive", "interactive terminal UI (Ink)")
38
+ .action(async (opts) => {
39
+ const spin = ora("Analyzing…").start();
40
+ const { report, ownership, exitCode, workspace } = await analyze({
41
+ cwd: opts.cwd,
42
+ useAuditFile: opts.auditFile,
43
+ pm: opts.pm,
44
+ prodOnly: opts.prodOnly,
45
+ ci: opts.ci,
46
+ ciVerbose: opts.ciVerbose,
47
+ failOn: opts.failOn,
48
+ runtimeEntry: opts.entry,
49
+ assumeReachable: opts.assumeReachable,
50
+ });
51
+ spin.succeed("Done");
52
+ if (workspace.isMonorepo) {
53
+ process.stderr.write(`Monorepo markers: ${JSON.stringify(workspace.tools)}\n`);
54
+ }
55
+ if (opts.json) {
56
+ process.stdout.write(toJsonReport({ ...report, summary: { workspace: workspace.tools } }));
57
+ process.stdout.write("\n");
58
+ }
59
+ else if (opts.markdown) {
60
+ process.stdout.write(toMarkdownReport(report, ownership));
61
+ }
62
+ else if (opts.html) {
63
+ process.stdout.write(toHtmlReport(report, ownership));
64
+ }
65
+ else if (opts.interactive) {
66
+ render(React.createElement(ReportTui, { report, ownership }));
67
+ }
68
+ else {
69
+ process.stdout.write(renderPretty(report.findings, ownership, report.graph, {
70
+ ci: opts.ci,
71
+ verbose: opts.ciVerbose,
72
+ }));
73
+ process.stdout.write("\n");
74
+ if (opts.ci) {
75
+ process.stderr.write(printCiSummary(report.diagnostics, Boolean(opts.ciVerbose)) + "\n");
76
+ }
77
+ }
78
+ if (opts.ci)
79
+ process.exit(exitCode);
80
+ });
81
+ program
82
+ .command("why")
83
+ .argument("<pkg>", "package name")
84
+ .option("-C, --cwd <dir>", "project root", process.cwd())
85
+ .action(async (pkg, opts) => {
86
+ const { graph } = await loadLockfileGraph(resolve(opts.cwd));
87
+ if (!graph.nodes.size) {
88
+ process.stderr.write("No lockfile graph.\n");
89
+ process.exit(1);
90
+ }
91
+ const ids = graph.byPackageName.get(pkg) ?? [];
92
+ const idx = buildIndexes(graph);
93
+ for (const id of ids) {
94
+ const path = shortestPathFromRoots(graph, idx, id);
95
+ process.stdout.write((path ?? [id]).map((x) => graph.nodes.get(x)?.name ?? x).join(" → ") + "\n");
96
+ }
97
+ });
98
+ program
99
+ .command("graph")
100
+ .argument("<pkg>", "package name")
101
+ .option("-C, --cwd <dir>", "project root", process.cwd())
102
+ .option("--limit <n>", "max paths", "5")
103
+ .action(async (pkg, opts) => {
104
+ const { graph } = await loadLockfileGraph(resolve(opts.cwd));
105
+ const ids = graph.byPackageName.get(pkg) ?? [];
106
+ const idx = buildIndexes(graph);
107
+ const lim = Number(opts.limit) || 5;
108
+ for (const id of ids.slice(0, 3)) {
109
+ for (const root of graph.rootIds.slice(0, 2)) {
110
+ const paths = dfsAllPathsWithLimit(idx, root, id, lim, 40);
111
+ for (const p of paths) {
112
+ process.stdout.write(p.map((x) => graph.nodes.get(x)?.name ?? x).join(" → ") + "\n");
113
+ }
114
+ }
115
+ }
116
+ });
117
+ program
118
+ .command("impact")
119
+ .argument("<pkg>", "package name")
120
+ .option("-C, --cwd <dir>", "project root", process.cwd())
121
+ .action(async (pkg, opts) => {
122
+ const { graph } = await loadLockfileGraph(resolve(opts.cwd));
123
+ const ids = graph.byPackageName.get(pkg) ?? [];
124
+ const idx = buildIndexes(graph);
125
+ for (const id of ids.slice(0, 1)) {
126
+ const s = impactSet(idx, id);
127
+ for (const n of s) {
128
+ const node = graph.nodes.get(n);
129
+ if (node)
130
+ process.stdout.write(`${node.name}@${node.version}\n`);
131
+ }
132
+ }
133
+ });
134
+ program
135
+ .command("diff")
136
+ .argument("<before>", "path to previous lockfile")
137
+ .argument("<after>", "path to new lockfile")
138
+ .option("--kind <npm|pnpm>", "lockfile family", "npm")
139
+ .action(async (before, after, opts) => {
140
+ const a = await readFile(resolve(before), "utf8");
141
+ const b = await readFile(resolve(after), "utf8");
142
+ const kind = opts.kind === "pnpm" ? "pnpm" : "npm";
143
+ const d = diffLockfiles(a, b, kind);
144
+ process.stdout.write(JSON.stringify(d, null, 2) + "\n");
145
+ });
146
+ program.parseAsync(process.argv).catch((e) => {
147
+ console.error(e);
148
+ process.exit(1);
149
+ });
150
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { VulnerabilityFinding } from "../models.js";
2
+ /** npm audit --json (npm 7+) */
3
+ export declare function parseNpmAuditJson(raw: Record<string, unknown>): VulnerabilityFinding[];
4
+ /** pnpm audit --json is often compatible with npm audit shape; fallback parse */
5
+ export declare function parsePnpmAuditJson(raw: Record<string, unknown>): VulnerabilityFinding[];
6
+ /** yarn audit --json: one JSON object per line */
7
+ export declare function parseYarnAuditJsonLines(text: string): VulnerabilityFinding[];
8
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../../src/core/audit-parser/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAY,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAWnE,gCAAgC;AAChC,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,EAAE,CAyEtF;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,oBAAoB,EAAE,CAEvF;AAED,kDAAkD;AAClD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAwC5E"}
@@ -0,0 +1,107 @@
1
+ function sev(s) {
2
+ const x = (s ?? "low").toLowerCase();
3
+ if (x === "critical")
4
+ return "critical";
5
+ if (x === "high")
6
+ return "high";
7
+ if (x === "moderate" || x === "medium")
8
+ return "moderate";
9
+ if (x === "low")
10
+ return "low";
11
+ return "info";
12
+ }
13
+ /** npm audit --json (npm 7+) */
14
+ export function parseNpmAuditJson(raw) {
15
+ const out = [];
16
+ const vulns = raw.vulnerabilities;
17
+ if (vulns) {
18
+ for (const [name, v] of Object.entries(vulns)) {
19
+ const via = v.via;
20
+ const titles = [];
21
+ const urls = [];
22
+ if (Array.isArray(via)) {
23
+ for (const item of via) {
24
+ if (typeof item === "object" && item) {
25
+ if (item.title)
26
+ titles.push(String(item.title));
27
+ if (item.url)
28
+ urls.push(String(item.url));
29
+ }
30
+ }
31
+ }
32
+ const id = `${name}:${v.range ?? "*"}`;
33
+ out.push({
34
+ id,
35
+ packageName: v.name ?? name,
36
+ vulnerableRange: v.range,
37
+ severity: sev(v.severity),
38
+ title: titles[0],
39
+ url: urls[0],
40
+ nodePaths: v.nodes,
41
+ });
42
+ }
43
+ }
44
+ const advisories = raw.advisories;
45
+ if (advisories && out.length === 0) {
46
+ for (const [aid, a] of Object.entries(advisories)) {
47
+ out.push({
48
+ id: `adv:${aid}`,
49
+ packageName: a.module_name ?? "unknown",
50
+ vulnerableRange: a.vulnerable_versions,
51
+ patchedRange: a.patched_versions,
52
+ severity: sev(a.severity),
53
+ title: a.title,
54
+ url: a.url,
55
+ cveIds: a.cves,
56
+ });
57
+ }
58
+ }
59
+ return dedupe(out);
60
+ }
61
+ /** pnpm audit --json is often compatible with npm audit shape; fallback parse */
62
+ export function parsePnpmAuditJson(raw) {
63
+ return parseNpmAuditJson(raw);
64
+ }
65
+ /** yarn audit --json: one JSON object per line */
66
+ export function parseYarnAuditJsonLines(text) {
67
+ const out = [];
68
+ for (const line of text.split("\n")) {
69
+ const t = line.trim();
70
+ if (!t)
71
+ continue;
72
+ let row;
73
+ try {
74
+ row = JSON.parse(t);
75
+ }
76
+ catch {
77
+ continue;
78
+ }
79
+ const typ = row.type;
80
+ if (typ !== "auditAdvisory")
81
+ continue;
82
+ const data = row.data;
83
+ const a = data?.advisory;
84
+ if (!a?.module_name)
85
+ continue;
86
+ out.push({
87
+ id: `yarn:${a.module_name}:${a.vulnerable_versions ?? ""}`,
88
+ packageName: a.module_name,
89
+ vulnerableRange: a.vulnerable_versions,
90
+ patchedRange: a.patched_versions,
91
+ severity: sev(a.severity),
92
+ title: a.title,
93
+ url: a.url,
94
+ cveIds: a.cves,
95
+ });
96
+ }
97
+ return dedupe(out);
98
+ }
99
+ function dedupe(f) {
100
+ const m = new Map();
101
+ for (const x of f) {
102
+ if (!m.has(x.id))
103
+ m.set(x.id, x);
104
+ }
105
+ return [...m.values()];
106
+ }
107
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../../src/core/audit-parser/normalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare function runCmd(cmd: string, args: string[], cwd: string): Promise<{
2
+ code: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ }>;
6
+ export declare function runNpmAudit(cwd: string): Promise<string>;
7
+ export declare function runPnpmAudit(cwd: string): Promise<string>;
8
+ export declare function runYarnAudit(cwd: string): Promise<string>;
9
+ //# sourceMappingURL=run-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-audit.d.ts","sourceRoot":"","sources":["../../../src/core/audit-parser/run-audit.ts"],"names":[],"mappings":"AAEA,wBAAsB,MAAM,CAC1B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAU3D;AAED,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG9D;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/D;AAED,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/D"}
@@ -0,0 +1,25 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function runCmd(cmd, args, cwd) {
3
+ return new Promise((resolve) => {
4
+ const p = spawn(cmd, args, { cwd, shell: false, env: process.env });
5
+ let stdout = "";
6
+ let stderr = "";
7
+ p.stdout?.on("data", (d) => (stdout += String(d)));
8
+ p.stderr?.on("data", (d) => (stderr += String(d)));
9
+ p.on("close", (code) => resolve({ code: code ?? 0, stdout, stderr }));
10
+ p.on("error", () => resolve({ code: 127, stdout, stderr }));
11
+ });
12
+ }
13
+ export async function runNpmAudit(cwd) {
14
+ const r = await runCmd("npm", ["audit", "--json"], cwd);
15
+ return r.stdout || r.stderr;
16
+ }
17
+ export async function runPnpmAudit(cwd) {
18
+ const r = await runCmd("pnpm", ["audit", "--json"], cwd);
19
+ return r.stdout || r.stderr;
20
+ }
21
+ export async function runYarnAudit(cwd) {
22
+ const r = await runCmd("yarn", ["audit", "--json"], cwd);
23
+ return r.stdout || r.stderr;
24
+ }
25
+ //# sourceMappingURL=run-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-audit.js","sourceRoot":"","sources":["../../../src/core/audit-parser/run-audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,GAAW,EACX,IAAc,EACd,GAAW;IAEX,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;QACpE,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QACtE,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IACzD,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;AAC9B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAW;IAC5C,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,GAAG,CAAC,CAAC;IACzD,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;AAC9B,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { DependencyGraphSnapshot } from "../models.js";
2
+ export type DetectedLock = {
3
+ kind: "npm";
4
+ path: string;
5
+ } | {
6
+ kind: "pnpm";
7
+ path: string;
8
+ } | {
9
+ kind: "yarn";
10
+ path: string;
11
+ } | {
12
+ kind: "none";
13
+ path?: undefined;
14
+ };
15
+ export declare function detectLockfile(rootDir: string): Promise<DetectedLock>;
16
+ export declare function loadLockfileGraph(rootDir: string): Promise<{
17
+ graph: DependencyGraphSnapshot;
18
+ lock: DetectedLock;
19
+ }>;
20
+ //# sourceMappingURL=load-lockfile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-lockfile.d.ts","sourceRoot":"","sources":["../../../src/core/graph-engine/load-lockfile.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAK5D,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AAEvC,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAO3E;AAED,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,KAAK,EAAE,uBAAuB,CAAC;IAAC,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC,CAejE"}
@@ -0,0 +1,43 @@
1
+ import { readFile, readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { buildGraphFromPackageLock } from "./npm-lock.js";
4
+ import { buildGraphFromPnpmLock } from "./pnpm-lock.js";
5
+ import { buildGraphFromYarnLock } from "./yarn-lock.js";
6
+ export async function detectLockfile(rootDir) {
7
+ const entries = new Set(await readdir(rootDir).catch(() => []));
8
+ if (entries.has("pnpm-lock.yaml"))
9
+ return { kind: "pnpm", path: join(rootDir, "pnpm-lock.yaml") };
10
+ if (entries.has("yarn.lock"))
11
+ return { kind: "yarn", path: join(rootDir, "yarn.lock") };
12
+ if (entries.has("package-lock.json"))
13
+ return { kind: "npm", path: join(rootDir, "package-lock.json") };
14
+ return { kind: "none" };
15
+ }
16
+ export async function loadLockfileGraph(rootDir) {
17
+ const lock = await detectLockfile(rootDir);
18
+ if (lock.kind === "none") {
19
+ return { graph: empty(), lock };
20
+ }
21
+ const raw = await readFile(lock.path, "utf8");
22
+ let graph;
23
+ if (lock.kind === "npm") {
24
+ graph = buildGraphFromPackageLock(JSON.parse(raw), rootDir);
25
+ }
26
+ else if (lock.kind === "pnpm") {
27
+ graph = buildGraphFromPnpmLock(raw);
28
+ }
29
+ else {
30
+ graph = buildGraphFromYarnLock(raw);
31
+ }
32
+ return { graph, lock };
33
+ }
34
+ function empty() {
35
+ return {
36
+ nodes: new Map(),
37
+ edges: [],
38
+ rootIds: [],
39
+ lockfileKind: "unknown",
40
+ byPackageName: new Map(),
41
+ };
42
+ }
43
+ //# sourceMappingURL=load-lockfile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-lockfile.js","sourceRoot":"","sources":["../../../src/core/graph-engine/load-lockfile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAQxD,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAe;IAClD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAChE,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,gBAAgB,CAAC,EAAE,CAAC;IAClG,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,EAAE,CAAC;IACxF,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;QAClC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,mBAAmB,CAAC,EAAE,CAAC;IACnE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAe;IAEf,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAC3C,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACzB,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC;IAClC,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC9C,IAAI,KAA8B,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACxB,KAAK,GAAG,yBAAyB,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAA4B,EAAE,OAAO,CAAC,CAAC;IACzF,CAAC;SAAM,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAChC,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,SAAS,KAAK;IACZ,OAAO;QACL,KAAK,EAAE,IAAI,GAAG,EAAE;QAChB,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,SAAS;QACvB,aAAa,EAAE,IAAI,GAAG,EAAE;KACzB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { DependencyGraphSnapshot } from "../models.js";
2
+ /** Resolve child path for a dependency name from parent lock path (npm v2/v3 packages keys). */
3
+ export declare function resolveNpmPackagePath(packages: Record<string, unknown>, parentPath: string, depName: string): string | undefined;
4
+ export declare function buildGraphFromPackageLock(raw: Record<string, unknown>, _rootDir: string): DependencyGraphSnapshot;
5
+ //# sourceMappingURL=npm-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"npm-lock.d.ts","sourceRoot":"","sources":["../../../src/core/graph-engine/npm-lock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,uBAAuB,EAAkB,MAAM,cAAc,CAAC;AAM5F,gGAAgG;AAChG,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACjC,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,SAAS,CAuBpB;AAcD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,QAAQ,EAAE,MAAM,GACf,uBAAuB,CAsGzB"}