@yabasha/gex 1.0.1 → 1.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.
package/dist/cli.cjs CHANGED
@@ -31,40 +31,60 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/cli.ts
32
32
  var cli_exports = {};
33
33
  __export(cli_exports, {
34
- run: () => run
34
+ run: () => run2
35
35
  });
36
36
  module.exports = __toCommonJS(cli_exports);
37
37
 
38
- // src/cli/commands.ts
38
+ // src/runtimes/node/commands.ts
39
39
  var import_node_path6 = __toESM(require("path"), 1);
40
40
  var import_commander = require("commander");
41
41
 
42
- // src/cli/install.ts
42
+ // src/shared/cli/install.ts
43
+ var INSTALL_COMMANDS = {
44
+ npm: {
45
+ global: ["i", "-g"],
46
+ local: ["i"],
47
+ dev: ["i", "-D"]
48
+ },
49
+ bun: {
50
+ global: ["add", "-g"],
51
+ local: ["add"],
52
+ dev: ["add", "-d"]
53
+ }
54
+ };
55
+ var MAX_BUFFER = 10 * 1024 * 1024;
56
+ function formatSpec(pkg) {
57
+ return pkg.version ? `${pkg.name}@${pkg.version}` : pkg.name;
58
+ }
43
59
  async function getExecFileAsync() {
44
60
  const { execFile } = await import("child_process");
45
61
  const { promisify } = await import("util");
46
62
  return promisify(execFile);
47
63
  }
48
- async function installFromReport(report, cwd) {
49
- const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean);
50
- const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
51
- const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
64
+ async function installFromReport(report, options) {
65
+ const opts = typeof options === "string" ? { cwd: options } : options;
66
+ const { cwd, packageManager = "npm" } = opts;
67
+ const globalPkgs = report.global_packages.map(formatSpec).filter(Boolean);
68
+ const localPkgs = report.local_dependencies.map(formatSpec).filter(Boolean);
69
+ const devPkgs = report.local_dev_dependencies.map(formatSpec).filter(Boolean);
52
70
  if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
53
71
  console.log("No packages to install from report.");
54
72
  return;
55
73
  }
56
74
  const execFileAsync = await getExecFileAsync();
75
+ const cmd = INSTALL_COMMANDS[packageManager];
76
+ const binary = packageManager === "bun" ? "bun" : "npm";
57
77
  if (globalPkgs.length > 0) {
58
78
  console.log(`Installing global: ${globalPkgs.join(" ")}`);
59
- await execFileAsync("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
79
+ await execFileAsync(binary, [...cmd.global, ...globalPkgs], { cwd, maxBuffer: MAX_BUFFER });
60
80
  }
61
81
  if (localPkgs.length > 0) {
62
82
  console.log(`Installing local deps: ${localPkgs.join(" ")}`);
63
- await execFileAsync("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
83
+ await execFileAsync(binary, [...cmd.local, ...localPkgs], { cwd, maxBuffer: MAX_BUFFER });
64
84
  }
65
85
  if (devPkgs.length > 0) {
66
86
  console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
67
- await execFileAsync("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
87
+ await execFileAsync(binary, [...cmd.dev, ...devPkgs], { cwd, maxBuffer: MAX_BUFFER });
68
88
  }
69
89
  }
70
90
  function printFromReport(report) {
@@ -95,10 +115,10 @@ function printFromReport(report) {
95
115
  console.log(lines.join("\n"));
96
116
  }
97
117
 
98
- // src/cli/output.ts
118
+ // src/shared/cli/output.ts
99
119
  var import_node_path = __toESM(require("path"), 1);
100
120
 
101
- // src/report/json.ts
121
+ // src/shared/report/json.ts
102
122
  function renderJson(report) {
103
123
  const r = {
104
124
  ...report,
@@ -111,7 +131,7 @@ function renderJson(report) {
111
131
  return JSON.stringify(r, null, 2);
112
132
  }
113
133
 
114
- // src/report/md.ts
134
+ // src/shared/report/md.ts
115
135
  function table(headers, rows) {
116
136
  const header = `| ${headers.join(" | ")} |`;
117
137
  const sep = `| ${headers.map(() => "---").join(" | ")} |`;
@@ -164,211 +184,9 @@ function renderMarkdown(report) {
164
184
  return lines.join("\n");
165
185
  }
166
186
 
167
- // src/report/html.ts
168
- function table2(headers, rows) {
169
- const headerHtml = `<tr>${headers.map((h) => `<th>${h}</th>`).join("")}</tr>`;
170
- const bodyHtml = rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join("")}</tr>`).join("");
171
- return `<table><thead>${headerHtml}</thead><tbody>${bodyHtml}</tbody></table>`;
172
- }
173
- function escapeHtml(text) {
174
- const htmlEntities = {
175
- "&": "&amp;",
176
- "<": "&lt;",
177
- ">": "&gt;",
178
- '"': "&quot;",
179
- "'": "&#39;"
180
- };
181
- return text.replace(/[&<>"']/g, (char) => htmlEntities[char]);
182
- }
183
- function renderHtml(report) {
184
- const hasProjectMeta = report.project_name || report.project_version || report.project_description || report.project_homepage || report.project_bugs;
185
- return `<!DOCTYPE html>
186
- <html lang="en">
187
- <head>
188
- <meta charset="UTF-8">
189
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
190
- <title>GEX Report - ${report.project_name || "Dependency Audit"}</title>
191
- <style>
192
- body {
193
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
194
- line-height: 1.6;
195
- color: #333;
196
- max-width: 1200px;
197
- margin: 0 auto;
198
- padding: 20px;
199
- background-color: #f5f5f5;
200
- }
201
- .container {
202
- background: white;
203
- border-radius: 8px;
204
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
205
- padding: 30px;
206
- }
207
- h1 {
208
- color: #2c3e50;
209
- border-bottom: 3px solid #3498db;
210
- padding-bottom: 10px;
211
- margin-top: 0;
212
- }
213
- h2 {
214
- color: #34495e;
215
- border-bottom: 2px solid #bdc3c7;
216
- padding-bottom: 8px;
217
- margin-top: 40px;
218
- margin-bottom: 20px;
219
- }
220
- .metadata {
221
- background: #ecf0f1;
222
- border-radius: 6px;
223
- padding: 20px;
224
- margin-bottom: 20px;
225
- }
226
- .metadata dl {
227
- margin: 0;
228
- }
229
- .metadata dt {
230
- font-weight: bold;
231
- color: #2c3e50;
232
- margin-top: 10px;
233
- }
234
- .metadata dt:first-child {
235
- margin-top: 0;
236
- }
237
- .metadata dd {
238
- margin: 5px 0 0 20px;
239
- color: #555;
240
- }
241
- .metadata dd a {
242
- color: #3498db;
243
- text-decoration: none;
244
- }
245
- .metadata dd a:hover {
246
- text-decoration: underline;
247
- }
248
- table {
249
- width: 100%;
250
- border-collapse: collapse;
251
- margin-bottom: 30px;
252
- background: white;
253
- border-radius: 6px;
254
- overflow: hidden;
255
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
256
- }
257
- th {
258
- background: #3498db;
259
- color: white;
260
- padding: 12px;
261
- text-align: left;
262
- font-weight: 600;
263
- }
264
- td {
265
- padding: 12px;
266
- border-bottom: 1px solid #ecf0f1;
267
- font-family: 'SFMono-Regular', Consolas, monospace;
268
- font-size: 14px;
269
- }
270
- tr:nth-child(even) {
271
- background: #f8f9fa;
272
- }
273
- tr:hover {
274
- background: #e8f4fd;
275
- }
276
- .footer {
277
- text-align: center;
278
- color: #7f8c8d;
279
- font-size: 14px;
280
- margin-top: 40px;
281
- padding-top: 20px;
282
- border-top: 1px solid #ecf0f1;
283
- }
284
- .footer strong {
285
- color: #2c3e50;
286
- }
287
- .no-data {
288
- text-align: center;
289
- color: #7f8c8d;
290
- font-style: italic;
291
- padding: 40px;
292
- }
293
- .timestamp {
294
- color: #95a5a6;
295
- font-size: 14px;
296
- margin-top: 10px;
297
- }
298
- </style>
299
- </head>
300
- <body>
301
- <div class="container">
302
- <h1>GEX Dependency Report</h1>
303
-
304
- ${hasProjectMeta ? `
305
- <section class="metadata">
306
- <h2>Project Information</h2>
307
- <dl>
308
- ${report.project_name ? `<dt>Project Name</dt><dd>${escapeHtml(report.project_name)}</dd>` : ""}
309
- ${report.project_version ? `<dt>Version</dt><dd>${escapeHtml(report.project_version)}</dd>` : ""}
310
- ${report.project_description ? `<dt>Description</dt><dd>${escapeHtml(report.project_description)}</dd>` : ""}
311
- ${report.project_homepage ? `<dt>Homepage</dt><dd><a href="${escapeHtml(report.project_homepage)}" target="_blank">${escapeHtml(report.project_homepage)}</a></dd>` : ""}
312
- ${report.project_bugs ? `<dt>Bugs</dt><dd><a href="${escapeHtml(report.project_bugs)}" target="_blank">${escapeHtml(report.project_bugs)}</a></dd>` : ""}
313
- <dt>Report Generated</dt><dd>${new Date(report.timestamp).toLocaleString()}</dd>
314
- </dl>
315
- </section>
316
- ` : ""}
317
-
318
- ${report.global_packages.length > 0 ? `
319
- <section>
320
- <h2>Global Packages <small>(${report.global_packages.length})</small></h2>
321
- ${table2(
322
- ["Name", "Version", "Path"],
323
- report.global_packages.map((p) => [
324
- escapeHtml(p.name),
325
- escapeHtml(p.version || ""),
326
- escapeHtml(p.resolved_path || "")
327
- ])
328
- )}
329
- </section>
330
- ` : '<section><h2>Global Packages</h2><div class="no-data">No global packages found</div></section>'}
331
-
332
- ${report.local_dependencies.length > 0 ? `
333
- <section>
334
- <h2>Local Dependencies <small>(${report.local_dependencies.length})</small></h2>
335
- ${table2(
336
- ["Name", "Version", "Path"],
337
- report.local_dependencies.map((p) => [
338
- escapeHtml(p.name),
339
- escapeHtml(p.version || ""),
340
- escapeHtml(p.resolved_path || "")
341
- ])
342
- )}
343
- </section>
344
- ` : '<section><h2>Local Dependencies</h2><div class="no-data">No local dependencies found</div></section>'}
345
-
346
- ${report.local_dev_dependencies.length > 0 ? `
347
- <section>
348
- <h2>Local Dev Dependencies <small>(${report.local_dev_dependencies.length})</small></h2>
349
- ${table2(
350
- ["Name", "Version", "Path"],
351
- report.local_dev_dependencies.map((p) => [
352
- escapeHtml(p.name),
353
- escapeHtml(p.version || ""),
354
- escapeHtml(p.resolved_path || "")
355
- ])
356
- )}
357
- </section>
358
- ` : '<section><h2>Local Dev Dependencies</h2><div class="no-data">No local dev dependencies found</div></section>'}
359
-
360
- <footer class="footer">
361
- <p>Generated by <strong>GEX v${escapeHtml(report.tool_version)}</strong> on ${new Date(report.timestamp).toLocaleString()}</p>
362
- <p>Report format version: ${escapeHtml(report.report_version)}</p>
363
- </footer>
364
- </div>
365
- </body>
366
- </html>`;
367
- }
368
-
369
- // src/cli/output.ts
187
+ // src/shared/cli/output.ts
370
188
  async function outputReport(report, format, outFile, markdownExtras) {
371
- const content = format === "json" ? renderJson(report) : format === "html" ? renderHtml({ ...report, ...markdownExtras || {} }) : renderMarkdown({ ...report, ...markdownExtras || {} });
189
+ const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
372
190
  if (outFile) {
373
191
  const outDir = import_node_path.default.dirname(outFile);
374
192
  const { mkdir, writeFile } = await import("fs/promises");
@@ -380,7 +198,7 @@ async function outputReport(report, format, outFile, markdownExtras) {
380
198
  }
381
199
  }
382
200
 
383
- // src/cli/parser.ts
201
+ // src/shared/cli/parser.ts
384
202
  var import_promises = require("fs/promises");
385
203
  var import_node_path2 = __toESM(require("path"), 1);
386
204
  function isMarkdownReportFile(filePath) {
@@ -429,60 +247,63 @@ async function loadReportFromFile(reportPath) {
429
247
  return JSON.parse(raw);
430
248
  }
431
249
 
432
- // src/cli/report.ts
433
- var import_promises4 = require("fs/promises");
434
- var import_node_path5 = __toESM(require("path"), 1);
435
-
436
- // src/npm.ts
437
- async function getExecFileAsync2() {
438
- const { execFile } = await import("child_process");
439
- const { promisify } = await import("util");
440
- return promisify(execFile);
441
- }
442
- async function npmLs(options = {}) {
443
- const args = ["ls", "--json"];
444
- if (options.global) args.push("--global");
445
- if (options.omitDev) args.push("--omit=dev");
446
- if (options.depth0) args.push("--depth=0");
250
+ // src/shared/cli/utils.ts
251
+ var import_node_fs = require("fs");
252
+ var import_promises2 = require("fs/promises");
253
+ var import_node_path3 = __toESM(require("path"), 1);
254
+ var import_node_url = require("url");
255
+ var import_meta = {};
256
+ function getPkgJsonPath() {
257
+ let startDir;
447
258
  try {
448
- const execFileAsync = await getExecFileAsync2();
449
- const { stdout } = await execFileAsync("npm", args, {
450
- cwd: options.cwd,
451
- maxBuffer: 10 * 1024 * 1024
452
- });
453
- if (stdout && stdout.trim()) return JSON.parse(stdout);
454
- return {};
455
- } catch (err) {
456
- const stdout = err?.stdout;
457
- if (typeof stdout === "string" && stdout.trim()) {
458
- try {
459
- return JSON.parse(stdout);
460
- } catch (parseErr) {
461
- if (process.env.DEBUG?.includes("gex")) {
462
- console.warn("npm ls stdout parse failed:", parseErr);
463
- }
464
- }
259
+ const __filename = (0, import_node_url.fileURLToPath)(import_meta.url);
260
+ startDir = import_node_path3.default.dirname(__filename);
261
+ } catch {
262
+ startDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
263
+ }
264
+ return findPackageJson(startDir);
265
+ }
266
+ function findPackageJson(startDir) {
267
+ let current = startDir;
268
+ const maxDepth = 6;
269
+ for (let i = 0; i < maxDepth; i++) {
270
+ const candidate = import_node_path3.default.resolve(current, "package.json");
271
+ if ((0, import_node_fs.existsSync)(candidate)) {
272
+ return candidate;
465
273
  }
466
- const stderr = err?.stderr;
467
- const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm ls failed";
468
- throw new Error(`npm ls failed: ${msg}`);
274
+ const parent = import_node_path3.default.dirname(current);
275
+ if (parent === current) break;
276
+ current = parent;
469
277
  }
278
+ return import_node_path3.default.resolve(process.cwd(), "package.json");
470
279
  }
471
- async function npmRootGlobal() {
280
+ async function getToolVersion() {
472
281
  try {
473
- const execFileAsync = await getExecFileAsync2();
474
- const { stdout } = await execFileAsync("npm", ["root", "-g"]);
475
- return stdout.trim();
476
- } catch (err) {
477
- const stderr = err?.stderr;
478
- const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm root -g failed";
479
- throw new Error(`npm root -g failed: ${msg}`);
282
+ const pkgPath = getPkgJsonPath();
283
+ const raw = await (0, import_promises2.readFile)(pkgPath, "utf8");
284
+ const pkg = JSON.parse(raw);
285
+ return pkg.version || "0.0.0";
286
+ } catch {
287
+ return "0.0.0";
480
288
  }
481
289
  }
290
+ var ASCII_BANNER = String.raw`
291
+ ________ __
292
+ / _____/ ____ _____/ |_ ____ ____
293
+ / \ ___ / _ \ / _ \ __\/ __ \ / \
294
+ \ \_\ ( <_> | <_> ) | \ ___/| | \
295
+ \______ /\____/ \____/|__| \___ >___| /
296
+ \/ \/ \/
297
+ GEX
298
+ `;
482
299
 
483
- // src/transform.ts
484
- var import_node_path3 = __toESM(require("path"), 1);
485
- var import_promises2 = require("fs/promises");
300
+ // src/runtimes/node/report.ts
301
+ var import_promises4 = require("fs/promises");
302
+ var import_node_path5 = __toESM(require("path"), 1);
303
+
304
+ // src/shared/transform.ts
305
+ var import_node_path4 = __toESM(require("path"), 1);
306
+ var import_promises3 = require("fs/promises");
486
307
  function toPkgArray(obj) {
487
308
  if (!obj) return [];
488
309
  return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
@@ -500,21 +321,30 @@ async function buildReportFromNpmTree(tree, opts) {
500
321
  if (opts.context === "local") {
501
322
  let pkgMeta = null;
502
323
  try {
503
- const pkgJsonPath = import_node_path3.default.join(opts.cwd || process.cwd(), "package.json");
504
- const raw = await (0, import_promises2.readFile)(pkgJsonPath, "utf8");
324
+ const pkgJsonPath = import_node_path4.default.join(opts.cwd || process.cwd(), "package.json");
325
+ const raw = await (0, import_promises3.readFile)(pkgJsonPath, "utf8");
505
326
  pkgMeta = JSON.parse(raw);
506
327
  } catch {
507
328
  }
508
329
  if (pkgMeta?.name) report.project_name = pkgMeta.name;
509
330
  if (pkgMeta?.version) report.project_version = pkgMeta.version;
510
331
  const depsObj = tree?.dependencies;
511
- const items = toPkgArray(depsObj);
512
- const devKeys = new Set(Object.keys(pkgMeta?.devDependencies || {}));
513
- for (const { name, node } of items) {
332
+ const devDepsObj = tree?.devDependencies;
333
+ const prodItems = toPkgArray(depsObj);
334
+ const treeDevItems = toPkgArray(devDepsObj);
335
+ if (treeDevItems.length > 0) {
336
+ for (const { name, node } of treeDevItems) {
337
+ const version = node && node.version || "";
338
+ const resolvedPath = node && node.path || import_node_path4.default.join(opts.cwd || process.cwd(), "node_modules", name);
339
+ report.local_dev_dependencies.push({ name, version, resolved_path: resolvedPath });
340
+ }
341
+ }
342
+ const devKeys = treeDevItems.length > 0 ? new Set(treeDevItems.map((entry) => entry.name)) : new Set(Object.keys(pkgMeta?.devDependencies || {}));
343
+ for (const { name, node } of prodItems) {
514
344
  const version = node && node.version || "";
515
- const resolvedPath = node && node.path || import_node_path3.default.join(opts.cwd || process.cwd(), "node_modules", name);
345
+ const resolvedPath = node && node.path || import_node_path4.default.join(opts.cwd || process.cwd(), "node_modules", name);
516
346
  const pkg = { name, version, resolved_path: resolvedPath };
517
- if (devKeys.has(name)) {
347
+ if (!treeDevItems.length && devKeys.has(name)) {
518
348
  report.local_dev_dependencies.push(pkg);
519
349
  } else {
520
350
  report.local_dependencies.push(pkg);
@@ -527,7 +357,7 @@ async function buildReportFromNpmTree(tree, opts) {
527
357
  const items = toPkgArray(depsObj);
528
358
  for (const { name, node } of items) {
529
359
  const version = node && node.version || "";
530
- const resolvedPath = node && node.path || import_node_path3.default.join(opts.globalRoot || "", name);
360
+ const resolvedPath = node && node.path || import_node_path4.default.join(opts.globalRoot || "", name);
531
361
  const pkg = { name, version, resolved_path: resolvedPath };
532
362
  report.global_packages.push(pkg);
533
363
  }
@@ -539,42 +369,54 @@ async function buildReportFromNpmTree(tree, opts) {
539
369
  return report;
540
370
  }
541
371
 
542
- // src/cli/utils.ts
543
- var import_promises3 = require("fs/promises");
544
- var import_node_path4 = __toESM(require("path"), 1);
545
- var import_node_url = require("url");
546
- var import_meta = {};
547
- function getPkgJsonPath() {
372
+ // src/runtimes/node/package-manager.ts
373
+ async function getExecFileAsync2() {
374
+ const { execFile } = await import("child_process");
375
+ const { promisify } = await import("util");
376
+ return promisify(execFile);
377
+ }
378
+ async function npmLs(options = {}) {
379
+ const args = ["ls", "--json"];
380
+ if (options.global) args.push("--global");
381
+ if (options.omitDev) args.push("--omit=dev");
382
+ if (options.depth0) args.push("--depth=0");
548
383
  try {
549
- const __filename = (0, import_node_url.fileURLToPath)(import_meta.url);
550
- const __dirnameLocal = import_node_path4.default.dirname(__filename);
551
- return import_node_path4.default.resolve(__dirnameLocal, "..", "..", "package.json");
552
- } catch {
553
- const dir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
554
- return import_node_path4.default.resolve(dir, "..", "package.json");
384
+ const execFileAsync = await getExecFileAsync2();
385
+ const { stdout } = await execFileAsync("npm", args, {
386
+ cwd: options.cwd,
387
+ maxBuffer: 10 * 1024 * 1024
388
+ });
389
+ if (stdout && stdout.trim()) return JSON.parse(stdout);
390
+ return {};
391
+ } catch (err) {
392
+ const stdout = err?.stdout;
393
+ if (typeof stdout === "string" && stdout.trim()) {
394
+ try {
395
+ return JSON.parse(stdout);
396
+ } catch (parseErr) {
397
+ if (process.env.DEBUG?.includes("gex")) {
398
+ console.warn("npm ls stdout parse failed:", parseErr);
399
+ }
400
+ }
401
+ }
402
+ const stderr = err?.stderr;
403
+ const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm ls failed";
404
+ throw new Error(`npm ls failed: ${msg}`);
555
405
  }
556
406
  }
557
- async function getToolVersion() {
407
+ async function npmRootGlobal() {
558
408
  try {
559
- const pkgPath = getPkgJsonPath();
560
- const raw = await (0, import_promises3.readFile)(pkgPath, "utf8");
561
- const pkg = JSON.parse(raw);
562
- return pkg.version || "0.0.0";
563
- } catch {
564
- return "0.0.0";
409
+ const execFileAsync = await getExecFileAsync2();
410
+ const { stdout } = await execFileAsync("npm", ["root", "-g"]);
411
+ return stdout.trim();
412
+ } catch (err) {
413
+ const stderr = err?.stderr;
414
+ const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm root -g failed";
415
+ throw new Error(`npm root -g failed: ${msg}`);
565
416
  }
566
417
  }
567
- var ASCII_BANNER = String.raw`
568
- ________ __
569
- / _____/ ____ _____/ |_ ____ ____
570
- / \ ___ / _ \ / _ \ __\/ __ \ / \
571
- \ \_\ ( <_> | <_> ) | \ ___/| | \
572
- \______ /\____/ \____/|__| \___ >___| /
573
- \/ \/ \/
574
- GEX
575
- `;
576
418
 
577
- // src/cli/report.ts
419
+ // src/runtimes/node/report.ts
578
420
  async function produceReport(ctx, options) {
579
421
  const toolVersion = await getToolVersion();
580
422
  const depth0 = !options.fullTree;
@@ -612,16 +454,12 @@ async function produceReport(ctx, options) {
612
454
  return { report, markdownExtras };
613
455
  }
614
456
 
615
- // src/cli/commands.ts
457
+ // src/runtimes/node/commands.ts
616
458
  function addCommonOptions(cmd, { allowOmitDev }) {
617
459
  cmd.option(
618
460
  "-f, --output-format <format>",
619
- "Output format: json, md, or html",
620
- (val) => {
621
- if (val === "md") return "md";
622
- if (val === "html") return "html";
623
- return "json";
624
- },
461
+ "Output format: md or json",
462
+ (val) => val === "md" ? "md" : "json",
625
463
  "json"
626
464
  ).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full npm ls tree (omit depth=0 default)", false);
627
465
  if (allowOmitDev) {
@@ -680,7 +518,7 @@ function createReadCommand(program) {
680
518
  printFromReport(parsed);
681
519
  }
682
520
  if (doInstall) {
683
- await installFromReport(parsed, process.cwd());
521
+ await installFromReport(parsed, { cwd: process.cwd(), packageManager: "npm" });
684
522
  }
685
523
  } catch (err) {
686
524
  const isMd = isMarkdownReportFile(reportPath);
@@ -702,7 +540,7 @@ ${ASCII_BANNER}`);
702
540
  return program;
703
541
  }
704
542
 
705
- // src/cli.ts
543
+ // src/runtimes/node/cli.ts
706
544
  var import_meta2 = {};
707
545
  async function run(argv = process.argv) {
708
546
  const program = await createProgram();
@@ -727,6 +565,31 @@ if (isMainModule) {
727
565
  process.exitCode = 1;
728
566
  });
729
567
  }
568
+
569
+ // src/cli.ts
570
+ var import_meta3 = {};
571
+ async function run2(argv = process.argv) {
572
+ return run(argv);
573
+ }
574
+ var isMainModule2 = (() => {
575
+ try {
576
+ if (typeof require !== "undefined" && typeof module !== "undefined") {
577
+ return require.main === module;
578
+ }
579
+ if (typeof import_meta3 !== "undefined") {
580
+ return import_meta3.url === `file://${process.argv[1]}`;
581
+ }
582
+ return false;
583
+ } catch {
584
+ return false;
585
+ }
586
+ })();
587
+ if (isMainModule2) {
588
+ run2().catch((error) => {
589
+ console.error("CLI error:", error);
590
+ process.exitCode = 1;
591
+ });
592
+ }
730
593
  // Annotate the CommonJS export names for ESM import in node:
731
594
  0 && (module.exports = {
732
595
  run