@yabasha/gex 0.3.1 → 0.3.3

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/README.md CHANGED
@@ -65,11 +65,15 @@ gex local --omit-dev -f json -o deps.json
65
65
  # Global packages
66
66
  gex global -f md -o global.md
67
67
 
68
- # Read a previous report (default prints names@versions; -i installs)
69
- # from default gex-report.json
68
+ # Read a previous report (JSON or Markdown)
69
+ # Default prints names@versions; add -i to install
70
+ # Positional path or -r/--report are accepted
71
+ # JSON
70
72
  gex read
71
- # or specify a file and install
72
73
  gex read -r path/to/report.json -i
74
+ # Markdown
75
+ gex read global.md
76
+ gex read global.md -i
73
77
  ```
74
78
 
75
79
  ## JSON schema (summary)
@@ -141,3 +145,26 @@ npm test
141
145
  npm run dev # watch + shows CLI help on success
142
146
  npm run lint
143
147
  ```
148
+
149
+ ## Contribute
150
+
151
+ We welcome contributions! A quick guide to getting productive:
152
+
153
+ - Setup
154
+ - Fork and clone this repo, then: `npm i`
155
+ - Dev loop: `npm run dev` (rebuilds and prints CLI help on successful build)
156
+ - One-off build: `npm run build`, then run: `node dist/cli.cjs --help`
157
+ - Test, lint, format
158
+ - Run tests: `npm test` (or `npm run test:watch`) — uses Vitest
159
+ - Lint: `npm run lint`; Format: `npm run format`
160
+ - Adding features/fixes
161
+ - Create a branch (e.g., `feat/read-reports`, `fix/option-parsing`)
162
+ - Make changes and add tests when reasonable
163
+ - If the change is user-facing, add a changeset: `npx changeset` (choose bump; write a summary)
164
+ - Open a PR (use `gh` CLI per workspace convention)
165
+ - Example: `gh pr create --fill` (ensure your branch is pushed)
166
+ - CI will run tests and build; the Release workflow will open a "Version Packages" PR for changesets
167
+ - Merge the "Version Packages" PR to publish to npm automatically
168
+ - Quick local verification
169
+ - Generate a report: `gex -f json -o gex-report.json`
170
+ - Read a report: `gex read` (JSON) or `gex read global.md` (Markdown); add `-i` to install
package/dist/cli.cjs CHANGED
@@ -34,23 +34,216 @@ __export(cli_exports, {
34
34
  run: () => run
35
35
  });
36
36
  module.exports = __toCommonJS(cli_exports);
37
- var import_promises2 = require("fs/promises");
38
- var import_node_path2 = __toESM(require("path"), 1);
39
- var import_node_url = require("url");
40
- var import_node_child_process2 = require("child_process");
41
- var import_node_util2 = require("util");
37
+
38
+ // src/cli/commands.ts
39
+ var import_node_path6 = __toESM(require("path"), 1);
42
40
  var import_commander = require("commander");
43
41
 
42
+ // src/cli/install.ts
43
+ async function getExecFileAsync() {
44
+ const { execFile } = await import("child_process");
45
+ const { promisify } = await import("util");
46
+ return promisify(execFile);
47
+ }
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);
52
+ if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
53
+ console.log("No packages to install from report.");
54
+ return;
55
+ }
56
+ const execFileAsync = await getExecFileAsync();
57
+ if (globalPkgs.length > 0) {
58
+ console.log(`Installing global: ${globalPkgs.join(" ")}`);
59
+ await execFileAsync("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
60
+ }
61
+ if (localPkgs.length > 0) {
62
+ console.log(`Installing local deps: ${localPkgs.join(" ")}`);
63
+ await execFileAsync("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
64
+ }
65
+ if (devPkgs.length > 0) {
66
+ console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
67
+ await execFileAsync("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
68
+ }
69
+ }
70
+ function printFromReport(report) {
71
+ const lines = [];
72
+ if (report.global_packages.length > 0) {
73
+ lines.push("Global Packages:");
74
+ for (const p of report.global_packages) {
75
+ lines.push(`- ${p.name}@${p.version}`);
76
+ }
77
+ }
78
+ if (report.local_dependencies.length > 0) {
79
+ if (lines.length) lines.push("");
80
+ lines.push("Local Dependencies:");
81
+ for (const p of report.local_dependencies) {
82
+ lines.push(`- ${p.name}@${p.version}`);
83
+ }
84
+ }
85
+ if (report.local_dev_dependencies.length > 0) {
86
+ if (lines.length) lines.push("");
87
+ lines.push("Local Dev Dependencies:");
88
+ for (const p of report.local_dev_dependencies) {
89
+ lines.push(`- ${p.name}@${p.version}`);
90
+ }
91
+ }
92
+ if (lines.length === 0) {
93
+ lines.push("(no packages found in report)");
94
+ }
95
+ console.log(lines.join("\n"));
96
+ }
97
+
98
+ // src/cli/output.ts
99
+ var import_node_path = __toESM(require("path"), 1);
100
+
101
+ // src/report/json.ts
102
+ function renderJson(report) {
103
+ const r = {
104
+ ...report,
105
+ global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),
106
+ local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),
107
+ local_dev_dependencies: [...report.local_dev_dependencies].sort(
108
+ (a, b) => a.name.localeCompare(b.name)
109
+ )
110
+ };
111
+ return JSON.stringify(r, null, 2);
112
+ }
113
+
114
+ // src/report/md.ts
115
+ function table(headers, rows) {
116
+ const header = `| ${headers.join(" | ")} |`;
117
+ const sep = `| ${headers.map(() => "---").join(" | ")} |`;
118
+ const body = rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
119
+ return [header, sep, body].filter(Boolean).join("\n");
120
+ }
121
+ function renderMarkdown(report) {
122
+ const lines = [];
123
+ lines.push("# GEX Report");
124
+ lines.push("");
125
+ if (report.project_name || report.project_version || report.project_description || report.project_homepage || report.project_bugs) {
126
+ lines.push("## Project Metadata");
127
+ if (report.project_name) lines.push(`- Name: ${report.project_name}`);
128
+ if (report.project_version) lines.push(`- Version: ${report.project_version}`);
129
+ if (report.project_description)
130
+ lines.push(`- Description: ${report.project_description}`);
131
+ if (report.project_homepage)
132
+ lines.push(`- Homepage: ${report.project_homepage}`);
133
+ if (report.project_bugs) lines.push(`- Bugs: ${report.project_bugs}`);
134
+ lines.push("");
135
+ }
136
+ if (report.global_packages.length > 0) {
137
+ lines.push("## Global Packages");
138
+ const rows = report.global_packages.map((p) => [p.name, p.version || "", p.resolved_path || ""]);
139
+ lines.push(table(["Name", "Version", "Path"], rows));
140
+ lines.push("");
141
+ }
142
+ if (report.local_dependencies.length > 0) {
143
+ lines.push("## Local Dependencies");
144
+ const rows = report.local_dependencies.map((p) => [
145
+ p.name,
146
+ p.version || "",
147
+ p.resolved_path || ""
148
+ ]);
149
+ lines.push(table(["Name", "Version", "Path"], rows));
150
+ lines.push("");
151
+ }
152
+ if (report.local_dev_dependencies.length > 0) {
153
+ lines.push("## Local Dev Dependencies");
154
+ const rows = report.local_dev_dependencies.map((p) => [
155
+ p.name,
156
+ p.version || "",
157
+ p.resolved_path || ""
158
+ ]);
159
+ lines.push(table(["Name", "Version", "Path"], rows));
160
+ lines.push("");
161
+ }
162
+ lines.push("---");
163
+ lines.push("_Generated by GEX_");
164
+ return lines.join("\n");
165
+ }
166
+
167
+ // src/cli/output.ts
168
+ async function outputReport(report, format, outFile, markdownExtras) {
169
+ const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
170
+ if (outFile) {
171
+ const outDir = import_node_path.default.dirname(outFile);
172
+ const { mkdir, writeFile } = await import("fs/promises");
173
+ await mkdir(outDir, { recursive: true });
174
+ await writeFile(outFile, content, "utf8");
175
+ console.log(`Wrote report to ${outFile}`);
176
+ } else {
177
+ console.log(content);
178
+ }
179
+ }
180
+
181
+ // src/cli/parser.ts
182
+ var import_promises = require("fs/promises");
183
+ var import_node_path2 = __toESM(require("path"), 1);
184
+ function isMarkdownReportFile(filePath) {
185
+ const ext = import_node_path2.default.extname(filePath).toLowerCase();
186
+ return ext === ".md" || ext === ".markdown";
187
+ }
188
+ function parseMarkdownPackagesTable(lines, startIndex) {
189
+ const rows = [];
190
+ if (!lines[startIndex] || !lines[startIndex].trim().startsWith("|")) return rows;
191
+ let i = startIndex + 2;
192
+ while (i < lines.length && lines[i].trim().startsWith("|")) {
193
+ const cols = lines[i].split("|").map((c) => c.trim()).filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1));
194
+ const [name = "", version = "", resolved_path = ""] = cols;
195
+ if (name) rows.push({ name, version, resolved_path });
196
+ i++;
197
+ }
198
+ return rows;
199
+ }
200
+ function parseMarkdownReport(md) {
201
+ const lines = md.split(/\r?\n/);
202
+ const findSection = (title) => lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase());
203
+ const parseSection = (idx) => {
204
+ if (idx < 0) return [];
205
+ let i = idx + 1;
206
+ while (i < lines.length && !lines[i].trim().startsWith("|")) i++;
207
+ return parseMarkdownPackagesTable(lines, i);
208
+ };
209
+ const global_packages = parseSection(findSection("Global Packages"));
210
+ const local_dependencies = parseSection(findSection("Local Dependencies"));
211
+ const local_dev_dependencies = parseSection(findSection("Local Dev Dependencies"));
212
+ const report = {
213
+ report_version: "1.0",
214
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
215
+ tool_version: "unknown",
216
+ global_packages,
217
+ local_dependencies,
218
+ local_dev_dependencies
219
+ };
220
+ return report;
221
+ }
222
+ async function loadReportFromFile(reportPath) {
223
+ const raw = await (0, import_promises.readFile)(reportPath, "utf8");
224
+ if (isMarkdownReportFile(reportPath) || raw.startsWith("# GEX Report")) {
225
+ return parseMarkdownReport(raw);
226
+ }
227
+ return JSON.parse(raw);
228
+ }
229
+
230
+ // src/cli/report.ts
231
+ var import_promises4 = require("fs/promises");
232
+ var import_node_path5 = __toESM(require("path"), 1);
233
+
44
234
  // src/npm.ts
45
- var import_node_child_process = require("child_process");
46
- var import_node_util = require("util");
47
- var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
235
+ async function getExecFileAsync2() {
236
+ const { execFile } = await import("child_process");
237
+ const { promisify } = await import("util");
238
+ return promisify(execFile);
239
+ }
48
240
  async function npmLs(options = {}) {
49
241
  const args = ["ls", "--json"];
50
242
  if (options.global) args.push("--global");
51
243
  if (options.omitDev) args.push("--omit=dev");
52
244
  if (options.depth0) args.push("--depth=0");
53
245
  try {
246
+ const execFileAsync = await getExecFileAsync2();
54
247
  const { stdout } = await execFileAsync("npm", args, {
55
248
  cwd: options.cwd,
56
249
  maxBuffer: 10 * 1024 * 1024
@@ -62,7 +255,10 @@ async function npmLs(options = {}) {
62
255
  if (typeof stdout === "string" && stdout.trim()) {
63
256
  try {
64
257
  return JSON.parse(stdout);
65
- } catch {
258
+ } catch (parseErr) {
259
+ if (process.env.DEBUG?.includes("gex")) {
260
+ console.warn("npm ls stdout parse failed:", parseErr);
261
+ }
66
262
  }
67
263
  }
68
264
  const stderr = err?.stderr;
@@ -72,6 +268,7 @@ async function npmLs(options = {}) {
72
268
  }
73
269
  async function npmRootGlobal() {
74
270
  try {
271
+ const execFileAsync = await getExecFileAsync2();
75
272
  const { stdout } = await execFileAsync("npm", ["root", "-g"]);
76
273
  return stdout.trim();
77
274
  } catch (err) {
@@ -82,8 +279,8 @@ async function npmRootGlobal() {
82
279
  }
83
280
 
84
281
  // src/transform.ts
85
- var import_node_path = __toESM(require("path"), 1);
86
- var import_promises = require("fs/promises");
282
+ var import_node_path3 = __toESM(require("path"), 1);
283
+ var import_promises2 = require("fs/promises");
87
284
  function toPkgArray(obj) {
88
285
  if (!obj) return [];
89
286
  return Object.keys(obj).map((name) => ({ name, node: obj[name] })).filter((p) => p && p.node);
@@ -101,8 +298,8 @@ async function buildReportFromNpmTree(tree, opts) {
101
298
  if (opts.context === "local") {
102
299
  let pkgMeta = null;
103
300
  try {
104
- const pkgJsonPath = import_node_path.default.join(opts.cwd || process.cwd(), "package.json");
105
- const raw = await (0, import_promises.readFile)(pkgJsonPath, "utf8");
301
+ const pkgJsonPath = import_node_path3.default.join(opts.cwd || process.cwd(), "package.json");
302
+ const raw = await (0, import_promises2.readFile)(pkgJsonPath, "utf8");
106
303
  pkgMeta = JSON.parse(raw);
107
304
  } catch {
108
305
  }
@@ -113,7 +310,7 @@ async function buildReportFromNpmTree(tree, opts) {
113
310
  const devKeys = new Set(Object.keys(pkgMeta?.devDependencies || {}));
114
311
  for (const { name, node } of items) {
115
312
  const version = node && node.version || "";
116
- const resolvedPath = node && node.path || import_node_path.default.join(opts.cwd || process.cwd(), "node_modules", name);
313
+ const resolvedPath = node && node.path || import_node_path3.default.join(opts.cwd || process.cwd(), "node_modules", name);
117
314
  const pkg = { name, version, resolved_path: resolvedPath };
118
315
  if (devKeys.has(name)) {
119
316
  report.local_dev_dependencies.push(pkg);
@@ -128,7 +325,7 @@ async function buildReportFromNpmTree(tree, opts) {
128
325
  const items = toPkgArray(depsObj);
129
326
  for (const { name, node } of items) {
130
327
  const version = node && node.version || "";
131
- const resolvedPath = node && node.path || import_node_path.default.join(opts.globalRoot || "", name);
328
+ const resolvedPath = node && node.path || import_node_path3.default.join(opts.globalRoot || "", name);
132
329
  const pkg = { name, version, resolved_path: resolvedPath };
133
330
  report.global_packages.push(pkg);
134
331
  }
@@ -140,104 +337,42 @@ async function buildReportFromNpmTree(tree, opts) {
140
337
  return report;
141
338
  }
142
339
 
143
- // src/report/json.ts
144
- function renderJson(report) {
145
- const r = {
146
- ...report,
147
- global_packages: [...report.global_packages].sort((a, b) => a.name.localeCompare(b.name)),
148
- local_dependencies: [...report.local_dependencies].sort((a, b) => a.name.localeCompare(b.name)),
149
- local_dev_dependencies: [...report.local_dev_dependencies].sort(
150
- (a, b) => a.name.localeCompare(b.name)
151
- )
152
- };
153
- return JSON.stringify(r, null, 2);
154
- }
155
-
156
- // src/report/md.ts
157
- function table(headers, rows) {
158
- const header = `| ${headers.join(" | ")} |`;
159
- const sep = `| ${headers.map(() => "---").join(" | ")} |`;
160
- const body = rows.map((r) => `| ${r.join(" | ")} |`).join("\n");
161
- return [header, sep, body].filter(Boolean).join("\n");
162
- }
163
- function renderMarkdown(report) {
164
- const lines = [];
165
- lines.push("# GEX Report");
166
- lines.push("");
167
- if (report.project_name || report.project_version) {
168
- lines.push("## Project Metadata");
169
- if (report.project_name) lines.push(`- Name: ${report.project_name}`);
170
- if (report.project_version) lines.push(`- Version: ${report.project_version}`);
171
- if (report.project_description)
172
- lines.push(`- Description: ${report.project_description}`);
173
- if (report.project_homepage)
174
- lines.push(`- Homepage: ${report.project_homepage}`);
175
- if (report.project_bugs) lines.push(`- Bugs: ${report.project_bugs}`);
176
- lines.push("");
177
- }
178
- if (report.global_packages.length > 0) {
179
- lines.push("## Global Packages");
180
- const rows = report.global_packages.map((p) => [p.name, p.version || "", p.resolved_path || ""]);
181
- lines.push(table(["Name", "Version", "Path"], rows));
182
- lines.push("");
183
- }
184
- if (report.local_dependencies.length > 0) {
185
- lines.push("## Local Dependencies");
186
- const rows = report.local_dependencies.map((p) => [
187
- p.name,
188
- p.version || "",
189
- p.resolved_path || ""
190
- ]);
191
- lines.push(table(["Name", "Version", "Path"], rows));
192
- lines.push("");
193
- }
194
- if (report.local_dev_dependencies.length > 0) {
195
- lines.push("## Local Dev Dependencies");
196
- const rows = report.local_dev_dependencies.map((p) => [
197
- p.name,
198
- p.version || "",
199
- p.resolved_path || ""
200
- ]);
201
- lines.push(table(["Name", "Version", "Path"], rows));
202
- lines.push("");
203
- }
204
- lines.push("---");
205
- lines.push("_Generated by GEX_");
206
- return lines.join("\n");
207
- }
208
-
209
- // src/cli.ts
340
+ // src/cli/utils.ts
341
+ var import_promises3 = require("fs/promises");
342
+ var import_node_path4 = __toESM(require("path"), 1);
343
+ var import_node_url = require("url");
210
344
  var import_meta = {};
211
345
  function getPkgJsonPath() {
212
346
  try {
213
347
  const __filename = (0, import_node_url.fileURLToPath)(import_meta.url);
214
- const __dirnameLocal = import_node_path2.default.dirname(__filename);
215
- return import_node_path2.default.resolve(__dirnameLocal, "..", "package.json");
348
+ const __dirnameLocal = import_node_path4.default.dirname(__filename);
349
+ return import_node_path4.default.resolve(__dirnameLocal, "..", "..", "package.json");
216
350
  } catch {
217
351
  const dir = typeof __dirname !== "undefined" ? __dirname : process.cwd();
218
- return import_node_path2.default.resolve(dir, "..", "package.json");
352
+ return import_node_path4.default.resolve(dir, "..", "package.json");
219
353
  }
220
354
  }
221
355
  async function getToolVersion() {
222
356
  try {
223
357
  const pkgPath = getPkgJsonPath();
224
- const raw = await (0, import_promises2.readFile)(pkgPath, "utf8");
358
+ const raw = await (0, import_promises3.readFile)(pkgPath, "utf8");
225
359
  const pkg = JSON.parse(raw);
226
360
  return pkg.version || "0.0.0";
227
361
  } catch {
228
362
  return "0.0.0";
229
363
  }
230
364
  }
231
- var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
232
365
  var ASCII_BANNER = String.raw`
233
366
  ________ __
234
- / _____/ ____ _____/ |_ ____ ____
367
+ / _____/ ____ _____/ |_ ____ ____
235
368
  / \ ___ / _ \ / _ \ __\/ __ \ / \
236
369
  \ \_\ ( <_> | <_> ) | \ ___/| | \
237
370
  \______ /\____/ \____/|__| \___ >___| /
238
- \/ \/ \/
371
+ \/ \/ \/
239
372
  GEX
240
373
  `;
374
+
375
+ // src/cli/report.ts
241
376
  async function produceReport(ctx, options) {
242
377
  const toolVersion = await getToolVersion();
243
378
  const depth0 = !options.fullTree;
@@ -253,7 +388,7 @@ async function produceReport(ctx, options) {
253
388
  let project_bugs;
254
389
  if (ctx === "local") {
255
390
  try {
256
- const pkgRaw = await (0, import_promises2.readFile)(import_node_path2.default.join(cwd, "package.json"), "utf8");
391
+ const pkgRaw = await (0, import_promises4.readFile)(import_node_path5.default.join(cwd, "package.json"), "utf8");
257
392
  const pkg = JSON.parse(pkgRaw);
258
393
  project_description = pkg.description;
259
394
  project_homepage = pkg.homepage;
@@ -274,126 +409,21 @@ async function produceReport(ctx, options) {
274
409
  const markdownExtras = { project_description, project_homepage, project_bugs };
275
410
  return { report, markdownExtras };
276
411
  }
277
- function printFromReport(report) {
278
- const lines = [];
279
- if (report.global_packages.length > 0) {
280
- lines.push("Global Packages:");
281
- for (const p of report.global_packages) {
282
- lines.push(`- ${p.name}@${p.version}`);
283
- }
284
- }
285
- if (report.local_dependencies.length > 0) {
286
- if (lines.length) lines.push("");
287
- lines.push("Local Dependencies:");
288
- for (const p of report.local_dependencies) {
289
- lines.push(`- ${p.name}@${p.version}`);
290
- }
291
- }
292
- if (report.local_dev_dependencies.length > 0) {
293
- if (lines.length) lines.push("");
294
- lines.push("Local Dev Dependencies:");
295
- for (const p of report.local_dev_dependencies) {
296
- lines.push(`- ${p.name}@${p.version}`);
297
- }
298
- }
299
- if (lines.length === 0) {
300
- lines.push("(no packages found in report)");
301
- }
302
- console.log(lines.join("\n"));
303
- }
304
- async function installFromReport(report, cwd) {
305
- const globalPkgs = report.global_packages.map((p) => `${p.name}@${p.version}`).filter(Boolean);
306
- const localPkgs = report.local_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
307
- const devPkgs = report.local_dev_dependencies.map((p) => `${p.name}@${p.version}`).filter(Boolean);
308
- if (globalPkgs.length === 0 && localPkgs.length === 0 && devPkgs.length === 0) {
309
- console.log("No packages to install from report.");
310
- return;
311
- }
312
- if (globalPkgs.length > 0) {
313
- console.log(`Installing global: ${globalPkgs.join(" ")}`);
314
- await execFileAsync2("npm", ["i", "-g", ...globalPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
315
- }
316
- if (localPkgs.length > 0) {
317
- console.log(`Installing local deps: ${localPkgs.join(" ")}`);
318
- await execFileAsync2("npm", ["i", ...localPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
319
- }
320
- if (devPkgs.length > 0) {
321
- console.log(`Installing local devDeps: ${devPkgs.join(" ")}`);
322
- await execFileAsync2("npm", ["i", "-D", ...devPkgs], { cwd, maxBuffer: 10 * 1024 * 1024 });
323
- }
324
- }
325
- async function outputReport(report, format, outFile, markdownExtras) {
326
- const content = format === "json" ? renderJson(report) : renderMarkdown({ ...report, ...markdownExtras || {} });
327
- if (outFile) {
328
- const outDir = import_node_path2.default.dirname(outFile);
329
- await (await import("fs/promises")).mkdir(outDir, { recursive: true });
330
- await (await import("fs/promises")).writeFile(outFile, content, "utf8");
331
- console.log(`Wrote report to ${outFile}`);
332
- } else {
333
- console.log(content);
334
- }
335
- }
336
- function isMarkdownReportFile(filePath) {
337
- const ext = import_node_path2.default.extname(filePath).toLowerCase();
338
- return ext === ".md" || ext === ".markdown";
339
- }
340
- function parseMarkdownPackagesTable(lines, startIndex) {
341
- const rows = [];
342
- if (!lines[startIndex] || !lines[startIndex].trim().startsWith("|")) return rows;
343
- let i = startIndex + 2;
344
- while (i < lines.length && lines[i].trim().startsWith("|")) {
345
- const cols = lines[i].split("|").map((c) => c.trim()).filter((_, idx, arr) => !(idx === 0 || idx === arr.length - 1));
346
- const [name = "", version = "", resolved_path = ""] = cols;
347
- if (name) rows.push({ name, version, resolved_path });
348
- i++;
349
- }
350
- return rows;
351
- }
352
- function parseMarkdownReport(md) {
353
- const lines = md.split(/\r?\n/);
354
- const findSection = (title) => lines.findIndex((l) => l.trim().toLowerCase() === `## ${title}`.toLowerCase());
355
- const parseSection = (idx) => {
356
- if (idx < 0) return [];
357
- let i = idx + 1;
358
- while (i < lines.length && !lines[i].trim().startsWith("|")) i++;
359
- return parseMarkdownPackagesTable(lines, i);
360
- };
361
- const global_packages = parseSection(findSection("Global Packages"));
362
- const local_dependencies = parseSection(findSection("Local Dependencies"));
363
- const local_dev_dependencies = parseSection(findSection("Local Dev Dependencies"));
364
- const report = {
365
- report_version: "1.0",
366
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
367
- tool_version: "unknown",
368
- global_packages,
369
- local_dependencies,
370
- local_dev_dependencies
371
- };
372
- return report;
373
- }
374
- async function loadReportFromFile(reportPath) {
375
- const raw = await (0, import_promises2.readFile)(reportPath, "utf8");
376
- if (isMarkdownReportFile(reportPath) || raw.startsWith("# GEX Report")) {
377
- return parseMarkdownReport(raw);
412
+
413
+ // src/cli/commands.ts
414
+ function addCommonOptions(cmd, { allowOmitDev }) {
415
+ cmd.option(
416
+ "-f, --output-format <format>",
417
+ "Output format: md or json",
418
+ (val) => val === "md" ? "md" : "json",
419
+ "json"
420
+ ).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full npm ls tree (omit depth=0 default)", false);
421
+ if (allowOmitDev) {
422
+ cmd.option("--omit-dev", "Exclude devDependencies (local only)", false);
378
423
  }
379
- return JSON.parse(raw);
424
+ return cmd;
380
425
  }
381
- async function run(argv = process.argv) {
382
- const program = new import_commander.Command().name("gex").description("GEX: Dependency auditing and documentation for Node.js (local and global).").version(await getToolVersion());
383
- program.addHelpText("beforeAll", `
384
- ${ASCII_BANNER}`);
385
- const addCommonOptions = (cmd, { allowOmitDev }) => {
386
- cmd.option(
387
- "-f, --output-format <format>",
388
- "Output format: md or json",
389
- (val) => val === "md" ? "md" : "json",
390
- "json"
391
- ).option("-o, --out-file <path>", "Write report to file").option("--full-tree", "Include full npm ls tree (omit depth=0 default)", false);
392
- if (allowOmitDev) {
393
- cmd.option("--omit-dev", "Exclude devDependencies (local only)", false);
394
- }
395
- return cmd;
396
- };
426
+ function createLocalCommand(program) {
397
427
  const localCmd = program.command("local", { isDefault: true }).description("Generate a report for the current project's dependencies");
398
428
  addCommonOptions(localCmd, { allowOmitDev: true });
399
429
  localCmd.action(async (opts) => {
@@ -413,6 +443,9 @@ ${ASCII_BANNER}`);
413
443
  });
414
444
  await outputReport(report, outputFormat, finalOutFile, markdownExtras);
415
445
  });
446
+ return localCmd;
447
+ }
448
+ function createGlobalCommand(program) {
416
449
  const globalCmd = program.command("global").description("Generate a report of globally installed packages");
417
450
  addCommonOptions(globalCmd, { allowOmitDev: false });
418
451
  globalCmd.action(async (opts) => {
@@ -430,12 +463,15 @@ ${ASCII_BANNER}`);
430
463
  });
431
464
  await outputReport(report, outputFormat, finalOutFile, markdownExtras);
432
465
  });
466
+ return globalCmd;
467
+ }
468
+ function createReadCommand(program) {
433
469
  const readCmd = program.command("read").description(
434
470
  "Read a previously generated report (JSON or Markdown) and either print package names or install them"
435
471
  ).argument("[report]", "Path to report file (JSON or Markdown)", "gex-report.json").option("-r, --report <path>", "Path to report file (JSON or Markdown)").option("-p, --print", "Print package names/versions from the report (default)", false).option("-i, --install", "Install packages from the report", false);
436
472
  readCmd.action(async (reportArg, opts) => {
437
473
  const chosen = opts.report || reportArg || "gex-report.json";
438
- const reportPath = import_node_path2.default.resolve(process.cwd(), chosen);
474
+ const reportPath = import_node_path6.default.resolve(process.cwd(), chosen);
439
475
  try {
440
476
  const parsed = await loadReportFromFile(reportPath);
441
477
  const doInstall = Boolean(opts.install);
@@ -454,12 +490,42 @@ ${ASCII_BANNER}`);
454
490
  process.exitCode = 1;
455
491
  }
456
492
  });
493
+ return readCmd;
494
+ }
495
+ async function createProgram() {
496
+ const program = new import_commander.Command().name("gex").description("GEX: Dependency auditing and documentation for Node.js (local and global).").version(await getToolVersion());
497
+ program.addHelpText("beforeAll", `
498
+ ${ASCII_BANNER}`);
499
+ createLocalCommand(program);
500
+ createGlobalCommand(program);
501
+ createReadCommand(program);
502
+ return program;
503
+ }
504
+
505
+ // src/cli.ts
506
+ var import_meta2 = {};
507
+ async function run(argv = process.argv) {
508
+ const program = await createProgram();
457
509
  await program.parseAsync(argv);
458
510
  }
459
- var isCjsMain = typeof require !== "undefined" && require.main === module;
460
- var isEsmMain = typeof import_meta !== "undefined" && import_meta.url === `file://${process.argv[1]}`;
461
- if (isCjsMain || isEsmMain) {
462
- run();
511
+ var isMainModule = (() => {
512
+ try {
513
+ if (typeof require !== "undefined" && typeof module !== "undefined") {
514
+ return require.main === module;
515
+ }
516
+ if (typeof import_meta2 !== "undefined") {
517
+ return import_meta2.url === `file://${process.argv[1]}`;
518
+ }
519
+ return false;
520
+ } catch {
521
+ return false;
522
+ }
523
+ })();
524
+ if (isMainModule) {
525
+ run().catch((error) => {
526
+ console.error("CLI error:", error);
527
+ process.exitCode = 1;
528
+ });
463
529
  }
464
530
  // Annotate the CommonJS export names for ESM import in node:
465
531
  0 && (module.exports = {