@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.mjs CHANGED
@@ -6,36 +6,56 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
6
6
  throw Error('Dynamic require of "' + x + '" is not supported');
7
7
  });
8
8
 
9
- // src/cli/commands.ts
9
+ // src/runtimes/node/commands.ts
10
10
  import path6 from "path";
11
11
  import { Command } from "commander";
12
12
 
13
- // src/cli/install.ts
13
+ // src/shared/cli/install.ts
14
+ var INSTALL_COMMANDS = {
15
+ npm: {
16
+ global: ["i", "-g"],
17
+ local: ["i"],
18
+ dev: ["i", "-D"]
19
+ },
20
+ bun: {
21
+ global: ["add", "-g"],
22
+ local: ["add"],
23
+ dev: ["add", "-d"]
24
+ }
25
+ };
26
+ var MAX_BUFFER = 10 * 1024 * 1024;
27
+ function formatSpec(pkg) {
28
+ return pkg.version ? `${pkg.name}@${pkg.version}` : pkg.name;
29
+ }
14
30
  async function getExecFileAsync() {
15
31
  const { execFile } = await import("child_process");
16
32
  const { promisify } = await import("util");
17
33
  return promisify(execFile);
18
34
  }
19
- async function installFromReport(report, cwd) {
20
- const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean);
21
- const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
22
- const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
35
+ async function installFromReport(report, options) {
36
+ const opts = typeof options === "string" ? { cwd: options } : options;
37
+ const { cwd, packageManager = "npm" } = opts;
38
+ const globalPkgs = report.global_packages.map(formatSpec).filter(Boolean);
39
+ const localPkgs = report.local_dependencies.map(formatSpec).filter(Boolean);
40
+ const devPkgs = report.local_dev_dependencies.map(formatSpec).filter(Boolean);
23
41
  if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
24
42
  console.log("No packages to install from report.");
25
43
  return;
26
44
  }
27
45
  const execFileAsync = await getExecFileAsync();
46
+ const cmd = INSTALL_COMMANDS[packageManager];
47
+ const binary = packageManager === "bun" ? "bun" : "npm";
28
48
  if (globalPkgs.length > 0) {
29
49
  console.log(`Installing global: ${globalPkgs.join(" ")}`);
30
- await execFileAsync("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
50
+ await execFileAsync(binary, [...cmd.global, ...globalPkgs], { cwd, maxBuffer: MAX_BUFFER });
31
51
  }
32
52
  if (localPkgs.length > 0) {
33
53
  console.log(`Installing local deps: ${localPkgs.join(" ")}`);
34
- await execFileAsync("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
54
+ await execFileAsync(binary, [...cmd.local, ...localPkgs], { cwd, maxBuffer: MAX_BUFFER });
35
55
  }
36
56
  if (devPkgs.length > 0) {
37
57
  console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
38
- await execFileAsync("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
58
+ await execFileAsync(binary, [...cmd.dev, ...devPkgs], { cwd, maxBuffer: MAX_BUFFER });
39
59
  }
40
60
  }
41
61
  function printFromReport(report) {
@@ -66,10 +86,10 @@ function printFromReport(report) {
66
86
  console.log(lines.join("\n"));
67
87
  }
68
88
 
69
- // src/cli/output.ts
89
+ // src/shared/cli/output.ts
70
90
  import path from "path";
71
91
 
72
- // src/report/json.ts
92
+ // src/shared/report/json.ts
73
93
  function renderJson(report) {
74
94
  const r = {
75
95
  ...report,
@@ -82,7 +102,7 @@ function renderJson(report) {
82
102
  return JSON.stringify(r, null, 2);
83
103
  }
84
104
 
85
- // src/report/md.ts
105
+ // src/shared/report/md.ts
86
106
  function table(headers, rows) {
87
107
  const header = `| ${headers.join(" | ")} |`;
88
108
  const sep = `| ${headers.map(() => "---").join(" | ")} |`;
@@ -135,211 +155,9 @@ function renderMarkdown(report) {
135
155
  return lines.join("\n");
136
156
  }
137
157
 
138
- // src/report/html.ts
139
- function table2(headers, rows) {
140
- const headerHtml = `<tr>${headers.map((h) => `<th>${h}</th>`).join("")}</tr>`;
141
- const bodyHtml = rows.map((row) => `<tr>${row.map((cell) => `<td>${cell}</td>`).join("")}</tr>`).join("");
142
- return `<table><thead>${headerHtml}</thead><tbody>${bodyHtml}</tbody></table>`;
143
- }
144
- function escapeHtml(text) {
145
- const htmlEntities = {
146
- "&": "&amp;",
147
- "<": "&lt;",
148
- ">": "&gt;",
149
- '"': "&quot;",
150
- "'": "&#39;"
151
- };
152
- return text.replace(/[&<>"']/g, (char) => htmlEntities[char]);
153
- }
154
- function renderHtml(report) {
155
- const hasProjectMeta = report.project_name || report.project_version || report.project_description || report.project_homepage || report.project_bugs;
156
- return `<!DOCTYPE html>
157
- <html lang="en">
158
- <head>
159
- <meta charset="UTF-8">
160
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
161
- <title>GEX Report - ${report.project_name || "Dependency Audit"}</title>
162
- <style>
163
- body {
164
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
165
- line-height: 1.6;
166
- color: #333;
167
- max-width: 1200px;
168
- margin: 0 auto;
169
- padding: 20px;
170
- background-color: #f5f5f5;
171
- }
172
- .container {
173
- background: white;
174
- border-radius: 8px;
175
- box-shadow: 0 2px 10px rgba(0,0,0,0.1);
176
- padding: 30px;
177
- }
178
- h1 {
179
- color: #2c3e50;
180
- border-bottom: 3px solid #3498db;
181
- padding-bottom: 10px;
182
- margin-top: 0;
183
- }
184
- h2 {
185
- color: #34495e;
186
- border-bottom: 2px solid #bdc3c7;
187
- padding-bottom: 8px;
188
- margin-top: 40px;
189
- margin-bottom: 20px;
190
- }
191
- .metadata {
192
- background: #ecf0f1;
193
- border-radius: 6px;
194
- padding: 20px;
195
- margin-bottom: 20px;
196
- }
197
- .metadata dl {
198
- margin: 0;
199
- }
200
- .metadata dt {
201
- font-weight: bold;
202
- color: #2c3e50;
203
- margin-top: 10px;
204
- }
205
- .metadata dt:first-child {
206
- margin-top: 0;
207
- }
208
- .metadata dd {
209
- margin: 5px 0 0 20px;
210
- color: #555;
211
- }
212
- .metadata dd a {
213
- color: #3498db;
214
- text-decoration: none;
215
- }
216
- .metadata dd a:hover {
217
- text-decoration: underline;
218
- }
219
- table {
220
- width: 100%;
221
- border-collapse: collapse;
222
- margin-bottom: 30px;
223
- background: white;
224
- border-radius: 6px;
225
- overflow: hidden;
226
- box-shadow: 0 1px 3px rgba(0,0,0,0.1);
227
- }
228
- th {
229
- background: #3498db;
230
- color: white;
231
- padding: 12px;
232
- text-align: left;
233
- font-weight: 600;
234
- }
235
- td {
236
- padding: 12px;
237
- border-bottom: 1px solid #ecf0f1;
238
- font-family: 'SFMono-Regular', Consolas, monospace;
239
- font-size: 14px;
240
- }
241
- tr:nth-child(even) {
242
- background: #f8f9fa;
243
- }
244
- tr:hover {
245
- background: #e8f4fd;
246
- }
247
- .footer {
248
- text-align: center;
249
- color: #7f8c8d;
250
- font-size: 14px;
251
- margin-top: 40px;
252
- padding-top: 20px;
253
- border-top: 1px solid #ecf0f1;
254
- }
255
- .footer strong {
256
- color: #2c3e50;
257
- }
258
- .no-data {
259
- text-align: center;
260
- color: #7f8c8d;
261
- font-style: italic;
262
- padding: 40px;
263
- }
264
- .timestamp {
265
- color: #95a5a6;
266
- font-size: 14px;
267
- margin-top: 10px;
268
- }
269
- </style>
270
- </head>
271
- <body>
272
- <div class="container">
273
- <h1>GEX Dependency Report</h1>
274
-
275
- ${hasProjectMeta ? `
276
- <section class="metadata">
277
- <h2>Project Information</h2>
278
- <dl>
279
- ${report.project_name ? `<dt>Project Name</dt><dd>${escapeHtml(report.project_name)}</dd>` : ""}
280
- ${report.project_version ? `<dt>Version</dt><dd>${escapeHtml(report.project_version)}</dd>` : ""}
281
- ${report.project_description ? `<dt>Description</dt><dd>${escapeHtml(report.project_description)}</dd>` : ""}
282
- ${report.project_homepage ? `<dt>Homepage</dt><dd><a href="${escapeHtml(report.project_homepage)}" target="_blank">${escapeHtml(report.project_homepage)}</a></dd>` : ""}
283
- ${report.project_bugs ? `<dt>Bugs</dt><dd><a href="${escapeHtml(report.project_bugs)}" target="_blank">${escapeHtml(report.project_bugs)}</a></dd>` : ""}
284
- <dt>Report Generated</dt><dd>${new Date(report.timestamp).toLocaleString()}</dd>
285
- </dl>
286
- </section>
287
- ` : ""}
288
-
289
- ${report.global_packages.length > 0 ? `
290
- <section>
291
- <h2>Global Packages <small>(${report.global_packages.length})</small></h2>
292
- ${table2(
293
- ["Name", "Version", "Path"],
294
- report.global_packages.map((p) => [
295
- escapeHtml(p.name),
296
- escapeHtml(p.version || ""),
297
- escapeHtml(p.resolved_path || "")
298
- ])
299
- )}
300
- </section>
301
- ` : '<section><h2>Global Packages</h2><div class="no-data">No global packages found</div></section>'}
302
-
303
- ${report.local_dependencies.length > 0 ? `
304
- <section>
305
- <h2>Local Dependencies <small>(${report.local_dependencies.length})</small></h2>
306
- ${table2(
307
- ["Name", "Version", "Path"],
308
- report.local_dependencies.map((p) => [
309
- escapeHtml(p.name),
310
- escapeHtml(p.version || ""),
311
- escapeHtml(p.resolved_path || "")
312
- ])
313
- )}
314
- </section>
315
- ` : '<section><h2>Local Dependencies</h2><div class="no-data">No local dependencies found</div></section>'}
316
-
317
- ${report.local_dev_dependencies.length > 0 ? `
318
- <section>
319
- <h2>Local Dev Dependencies <small>(${report.local_dev_dependencies.length})</small></h2>
320
- ${table2(
321
- ["Name", "Version", "Path"],
322
- report.local_dev_dependencies.map((p) => [
323
- escapeHtml(p.name),
324
- escapeHtml(p.version || ""),
325
- escapeHtml(p.resolved_path || "")
326
- ])
327
- )}
328
- </section>
329
- ` : '<section><h2>Local Dev Dependencies</h2><div class="no-data">No local dev dependencies found</div></section>'}
330
-
331
- <footer class="footer">
332
- <p>Generated by <strong>GEX v${escapeHtml(report.tool_version)}</strong> on ${new Date(report.timestamp).toLocaleString()}</p>
333
- <p>Report format version: ${escapeHtml(report.report_version)}</p>
334
- </footer>
335
- </div>
336
- </body>
337
- </html>`;
338
- }
339
-
340
- // src/cli/output.ts
158
+ // src/shared/cli/output.ts
341
159
  async function outputReport(report, format, outFile, markdownExtras) {
342
- const content = format === "json" ? renderJson(report) : format === "html" ? renderHtml({ ...report, ...markdownExtras || {} }) : renderMarkdown({ ...report, ...markdownExtras || {} });
160
+ const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
343
161
  if (outFile) {
344
162
  const outDir = path.dirname(outFile);
345
163
  const { mkdir, writeFile } = await import("fs/promises");
@@ -351,7 +169,7 @@ async function outputReport(report, format, outFile, markdownExtras) {
351
169
  }
352
170
  }
353
171
 
354
- // src/cli/parser.ts
172
+ // src/shared/cli/parser.ts
355
173
  import { readFile } from "fs/promises";
356
174
  import path2 from "path";
357
175
  function isMarkdownReportFile(filePath) {
@@ -400,60 +218,62 @@ async function loadReportFromFile(reportPath) {
400
218
  return JSON.parse(raw);
401
219
  }
402
220
 
403
- // src/cli/report.ts
404
- import { readFile as readFile4 } from "fs/promises";
405
- import path5 from "path";
406
-
407
- // src/npm.ts
408
- async function getExecFileAsync2() {
409
- const { execFile } = await import("child_process");
410
- const { promisify } = await import("util");
411
- return promisify(execFile);
412
- }
413
- async function npmLs(options = {}) {
414
- const args = ["ls", "--json"];
415
- if (options.global) args.push("--global");
416
- if (options.omitDev) args.push("--omit=dev");
417
- if (options.depth0) args.push("--depth=0");
221
+ // src/shared/cli/utils.ts
222
+ import { existsSync } from "fs";
223
+ import { readFile as readFile2 } from "fs/promises";
224
+ import path3 from "path";
225
+ import { fileURLToPath } from "url";
226
+ function getPkgJsonPath() {
227
+ let startDir;
418
228
  try {
419
- const execFileAsync = await getExecFileAsync2();
420
- const { stdout } = await execFileAsync("npm", args, {
421
- cwd: options.cwd,
422
- maxBuffer: 10 * 1024 * 1024
423
- });
424
- if (stdout && stdout.trim()) return JSON.parse(stdout);
425
- return {};
426
- } catch (err) {
427
- const stdout = err?.stdout;
428
- if (typeof stdout === "string" && stdout.trim()) {
429
- try {
430
- return JSON.parse(stdout);
431
- } catch (parseErr) {
432
- if (process.env.DEBUG?.includes("gex")) {
433
- console.warn("npm ls stdout parse failed:", parseErr);
434
- }
435
- }
229
+ const __filename = fileURLToPath(import.meta.url);
230
+ startDir = path3.dirname(__filename);
231
+ } catch {
232
+ startDir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
233
+ }
234
+ return findPackageJson(startDir);
235
+ }
236
+ function findPackageJson(startDir) {
237
+ let current = startDir;
238
+ const maxDepth = 6;
239
+ for (let i = 0; i < maxDepth; i++) {
240
+ const candidate = path3.resolve(current, "package.json");
241
+ if (existsSync(candidate)) {
242
+ return candidate;
436
243
  }
437
- const stderr = err?.stderr;
438
- const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm ls failed";
439
- throw new Error(`npm ls failed: ${msg}`);
244
+ const parent = path3.dirname(current);
245
+ if (parent === current) break;
246
+ current = parent;
440
247
  }
248
+ return path3.resolve(process.cwd(), "package.json");
441
249
  }
442
- async function npmRootGlobal() {
250
+ async function getToolVersion() {
443
251
  try {
444
- const execFileAsync = await getExecFileAsync2();
445
- const { stdout } = await execFileAsync("npm", ["root", "-g"]);
446
- return stdout.trim();
447
- } catch (err) {
448
- const stderr = err?.stderr;
449
- const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm root -g failed";
450
- throw new Error(`npm root -g failed: ${msg}`);
252
+ const pkgPath = getPkgJsonPath();
253
+ const raw = await readFile2(pkgPath, "utf8");
254
+ const pkg = JSON.parse(raw);
255
+ return pkg.version || "0.0.0";
256
+ } catch {
257
+ return "0.0.0";
451
258
  }
452
259
  }
260
+ var ASCII_BANNER = String.raw`
261
+ ________ __
262
+ / _____/ ____ _____/ |_ ____ ____
263
+ / \ ___ / _ \ / _ \ __\/ __ \ / \
264
+ \ \_\ ( <_> | <_> ) | \ ___/| | \
265
+ \______ /\____/ \____/|__| \___ >___| /
266
+ \/ \/ \/
267
+ GEX
268
+ `;
453
269
 
454
- // src/transform.ts
455
- import path3 from "path";
456
- import { readFile as readFile2 } from "fs/promises";
270
+ // src/runtimes/node/report.ts
271
+ import { readFile as readFile4 } from "fs/promises";
272
+ import path5 from "path";
273
+
274
+ // src/shared/transform.ts
275
+ import path4 from "path";
276
+ import { readFile as readFile3 } from "fs/promises";
457
277
  function toPkgArray(obj) {
458
278
  if (!obj) return [];
459
279
  return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
@@ -471,21 +291,30 @@ async function buildReportFromNpmTree(tree, opts) {
471
291
  if (opts.context === "local") {
472
292
  let pkgMeta = null;
473
293
  try {
474
- const pkgJsonPath = path3.join(opts.cwd || process.cwd(), "package.json");
475
- const raw = await readFile2(pkgJsonPath, "utf8");
294
+ const pkgJsonPath = path4.join(opts.cwd || process.cwd(), "package.json");
295
+ const raw = await readFile3(pkgJsonPath, "utf8");
476
296
  pkgMeta = JSON.parse(raw);
477
297
  } catch {
478
298
  }
479
299
  if (pkgMeta?.name) report.project_name = pkgMeta.name;
480
300
  if (pkgMeta?.version) report.project_version = pkgMeta.version;
481
301
  const depsObj = tree?.dependencies;
482
- const items = toPkgArray(depsObj);
483
- const devKeys = new Set(Object.keys(pkgMeta?.devDependencies || {}));
484
- for (const { name, node } of items) {
302
+ const devDepsObj = tree?.devDependencies;
303
+ const prodItems = toPkgArray(depsObj);
304
+ const treeDevItems = toPkgArray(devDepsObj);
305
+ if (treeDevItems.length > 0) {
306
+ for (const { name, node } of treeDevItems) {
307
+ const version = node && node.version || "";
308
+ const resolvedPath = node && node.path || path4.join(opts.cwd || process.cwd(), "node_modules", name);
309
+ report.local_dev_dependencies.push({ name, version, resolved_path: resolvedPath });
310
+ }
311
+ }
312
+ const devKeys = treeDevItems.length > 0 ? new Set(treeDevItems.map((entry) => entry.name)) : new Set(Object.keys(pkgMeta?.devDependencies || {}));
313
+ for (const { name, node } of prodItems) {
485
314
  const version = node && node.version || "";
486
- const resolvedPath = node && node.path || path3.join(opts.cwd || process.cwd(), "node_modules", name);
315
+ const resolvedPath = node && node.path || path4.join(opts.cwd || process.cwd(), "node_modules", name);
487
316
  const pkg = { name, version, resolved_path: resolvedPath };
488
- if (devKeys.has(name)) {
317
+ if (!treeDevItems.length && devKeys.has(name)) {
489
318
  report.local_dev_dependencies.push(pkg);
490
319
  } else {
491
320
  report.local_dependencies.push(pkg);
@@ -498,7 +327,7 @@ async function buildReportFromNpmTree(tree, opts) {
498
327
  const items = toPkgArray(depsObj);
499
328
  for (const { name, node } of items) {
500
329
  const version = node && node.version || "";
501
- const resolvedPath = node && node.path || path3.join(opts.globalRoot || "", name);
330
+ const resolvedPath = node && node.path || path4.join(opts.globalRoot || "", name);
502
331
  const pkg = { name, version, resolved_path: resolvedPath };
503
332
  report.global_packages.push(pkg);
504
333
  }
@@ -510,41 +339,54 @@ async function buildReportFromNpmTree(tree, opts) {
510
339
  return report;
511
340
  }
512
341
 
513
- // src/cli/utils.ts
514
- import { readFile as readFile3 } from "fs/promises";
515
- import path4 from "path";
516
- import { fileURLToPath } from "url";
517
- function getPkgJsonPath() {
342
+ // src/runtimes/node/package-manager.ts
343
+ async function getExecFileAsync2() {
344
+ const { execFile } = await import("child_process");
345
+ const { promisify } = await import("util");
346
+ return promisify(execFile);
347
+ }
348
+ async function npmLs(options = {}) {
349
+ const args = ["ls", "--json"];
350
+ if (options.global) args.push("--global");
351
+ if (options.omitDev) args.push("--omit=dev");
352
+ if (options.depth0) args.push("--depth=0");
518
353
  try {
519
- const __filename = fileURLToPath(import.meta.url);
520
- const __dirnameLocal = path4.dirname(__filename);
521
- return path4.resolve(__dirnameLocal, "..", "..", "package.json");
522
- } catch {
523
- const dir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
524
- return path4.resolve(dir, "..", "package.json");
354
+ const execFileAsync = await getExecFileAsync2();
355
+ const { stdout } = await execFileAsync("npm", args, {
356
+ cwd: options.cwd,
357
+ maxBuffer: 10 * 1024 * 1024
358
+ });
359
+ if (stdout && stdout.trim()) return JSON.parse(stdout);
360
+ return {};
361
+ } catch (err) {
362
+ const stdout = err?.stdout;
363
+ if (typeof stdout === "string" && stdout.trim()) {
364
+ try {
365
+ return JSON.parse(stdout);
366
+ } catch (parseErr) {
367
+ if (process.env.DEBUG?.includes("gex")) {
368
+ console.warn("npm ls stdout parse failed:", parseErr);
369
+ }
370
+ }
371
+ }
372
+ const stderr = err?.stderr;
373
+ const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm ls failed";
374
+ throw new Error(`npm ls failed: ${msg}`);
525
375
  }
526
376
  }
527
- async function getToolVersion() {
377
+ async function npmRootGlobal() {
528
378
  try {
529
- const pkgPath = getPkgJsonPath();
530
- const raw = await readFile3(pkgPath, "utf8");
531
- const pkg = JSON.parse(raw);
532
- return pkg.version || "0.0.0";
533
- } catch {
534
- return "0.0.0";
379
+ const execFileAsync = await getExecFileAsync2();
380
+ const { stdout } = await execFileAsync("npm", ["root", "-g"]);
381
+ return stdout.trim();
382
+ } catch (err) {
383
+ const stderr = err?.stderr;
384
+ const msg = typeof stderr === "string" && stderr.trim() || err?.message || "npm root -g failed";
385
+ throw new Error(`npm root -g failed: ${msg}`);
535
386
  }
536
387
  }
537
- var ASCII_BANNER = String.raw`
538
- ________ __
539
- / _____/ ____ _____/ |_ ____ ____
540
- / \ ___ / _ \ / _ \ __\/ __ \ / \
541
- \ \_\ ( <_> | <_> ) | \ ___/| | \
542
- \______ /\____/ \____/|__| \___ >___| /
543
- \/ \/ \/
544
- GEX
545
- `;
546
388
 
547
- // src/cli/report.ts
389
+ // src/runtimes/node/report.ts
548
390
  async function produceReport(ctx, options) {
549
391
  const toolVersion = await getToolVersion();
550
392
  const depth0 = !options.fullTree;
@@ -582,16 +424,12 @@ async function produceReport(ctx, options) {
582
424
  return { report, markdownExtras };
583
425
  }
584
426
 
585
- // src/cli/commands.ts
427
+ // src/runtimes/node/commands.ts
586
428
  function addCommonOptions(cmd, { allowOmitDev }) {
587
429
  cmd.option(
588
430
  "-f, --output-format <format>",
589
- "Output format: json, md, or html",
590
- (val) => {
591
- if (val === "md") return "md";
592
- if (val === "html") return "html";
593
- return "json";
594
- },
431
+ "Output format: md or json",
432
+ (val) => val === "md" ? "md" : "json",
595
433
  "json"
596
434
  ).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full npm ls tree (omit depth=0 default)", false);
597
435
  if (allowOmitDev) {
@@ -650,7 +488,7 @@ function createReadCommand(program) {
650
488
  printFromReport(parsed);
651
489
  }
652
490
  if (doInstall) {
653
- await installFromReport(parsed, process.cwd());
491
+ await installFromReport(parsed, { cwd: process.cwd(), packageManager: "npm" });
654
492
  }
655
493
  } catch (err) {
656
494
  const isMd = isMarkdownReportFile(reportPath);
@@ -672,7 +510,7 @@ ${ASCII_BANNER}`);
672
510
  return program;
673
511
  }
674
512
 
675
- // src/cli.ts
513
+ // src/runtimes/node/cli.ts
676
514
  async function run(argv = process.argv) {
677
515
  const program = await createProgram();
678
516
  await program.parseAsync(argv);
@@ -696,7 +534,31 @@ if (isMainModule) {
696
534
  process.exitCode = 1;
697
535
  });
698
536
  }
537
+
538
+ // src/cli.ts
539
+ async function run2(argv = process.argv) {
540
+ return run(argv);
541
+ }
542
+ var isMainModule2 = (() => {
543
+ try {
544
+ if (typeof __require !== "undefined" && typeof module !== "undefined") {
545
+ return __require.main === module;
546
+ }
547
+ if (typeof import.meta !== "undefined") {
548
+ return import.meta.url === `file://${process.argv[1]}`;
549
+ }
550
+ return false;
551
+ } catch {
552
+ return false;
553
+ }
554
+ })();
555
+ if (isMainModule2) {
556
+ run2().catch((error) => {
557
+ console.error("CLI error:", error);
558
+ process.exitCode = 1;
559
+ });
560
+ }
699
561
  export {
700
- run
562
+ run2 as run
701
563
  };
702
564
  //# sourceMappingURL=cli.mjs.map