globox 1.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ ## v3.0.0 (Upcoming)
4
+
5
+ ### New Features
6
+
7
+ - `globox scan` — discover all Node.js projects on your machine and show which package manager each uses
8
+ - Per-project `node_modules` disk usage breakdown
9
+ - System-wide view of your entire Node.js footprint across all projects
10
+ - Dashboard view for scan results with sortable project list
11
+
12
+ ---
13
+
14
+ ## v2.0.0 (Upcoming)
15
+
16
+ ### New Features
17
+
18
+ - `globox rm` — interactive multi-select to uninstall global packages from any manager
19
+ - Dashboard delete button per row with confirmation dialog
20
+ - `globox update` — interactive update of outdated global packages
21
+ - `globox sync` — migrate global packages from one manager to another
22
+
23
+ ---
24
+
25
+ ## v1.0.0 (2026.2.17)
26
+
27
+ ### Features
28
+
29
+ - List all globally installed packages across npm, pnpm, and yarn with a single command
30
+ - Auto-detect which package managers are installed (skip missing ones gracefully)
31
+ - Group packages by manager (npm first, then pnpm, then yarn)
32
+ - `--size` / `-s` — show disk size of each package
33
+ - `--sort <field>` — sort by `name` (default) or `size`
34
+ - `--outdated` / `-o` — check which packages have newer versions available
35
+ - `--doctor` — detect duplicate packages installed across multiple managers
36
+ - `--export <path>` / `-e` — export package list to JSON or CSV
37
+ - `--dashboard` / `-d` — launch an interactive web dashboard in the browser
38
+ - `--json` / `-j` — output raw JSON for scripting and piping
39
+ - `--manager <names>` / `-m` — filter by specific package managers
40
+
41
+ ### Dashboard
42
+
43
+ - Search and filter packages in real-time
44
+ - Filter by package manager with toggle buttons
45
+ - Sortable columns (Package, Size, Manager) with click-to-sort
46
+ - "Check for updates" button with lazy fetch (no upfront latency)
47
+ - Pre-load outdated data with `globox -d -o`
48
+ - Stats cards showing total packages, total disk size, and per-manager counts
49
+ - Dark theme, responsive design
50
+ - Auto-opens in browser, shuts down cleanly on Ctrl+C
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # globox
2
+
3
+ One command to list all globally installed npm, pnpm, and yarn packages — with an optional dashboard.
4
+
5
+ ```diff
6
+ - npm list -g --depth=0
7
+ - pnpm list -g
8
+ - yarn global list
9
+ + globox
10
+ ```
11
+
12
+ ## Quick Start
13
+
14
+ ```bash
15
+ # Install
16
+ npm install -g globox
17
+
18
+ # List all global packages
19
+ globox
20
+
21
+ # Open the interactive dashboard
22
+ globox -d
23
+ ```
24
+
25
+ That's it. globox auto-detects which package managers you have and aggregates everything into one view.
26
+
27
+ ## Why
28
+
29
+ Managing global packages across multiple package managers is painful:
30
+
31
+ - **Three different commands** — `npm list -g`, `pnpm list -g`, `yarn global list` each with different output formats
32
+ - **No unified view** — impossible to see everything at a glance without running commands one by one
33
+ - **Hidden disk usage** — global packages silently eat gigabytes with no easy way to see which ones are the biggest
34
+ - **Duplicates go unnoticed** — the same package installed in both npm and pnpm wastes space and causes confusion
35
+ - **Outdated packages pile up** — no single command checks for updates across all managers
36
+ - **No export or backup** — switching machines means manually remembering what you had installed
37
+
38
+ globox fixes all of this with one command that works across npm, pnpm, and yarn.
39
+
40
+ ## Usage
41
+
42
+ ```bash
43
+ # List everything (grouped by manager)
44
+ globox
45
+
46
+ # Show disk sizes
47
+ globox -s
48
+
49
+ # Sort by size (biggest first)
50
+ globox --sort size
51
+
52
+ # Filter to one manager
53
+ globox -m pnpm
54
+
55
+ # Check for outdated packages
56
+ globox --outdated
57
+
58
+ # Find duplicates across managers
59
+ globox --doctor
60
+
61
+ # Export to file
62
+ globox --export globals.json
63
+ globox --export globals.csv
64
+
65
+ # JSON output (great for piping)
66
+ globox --json
67
+
68
+ # Open the web dashboard
69
+ globox -d
70
+
71
+ # Dashboard with pre-loaded outdated info
72
+ globox -d -o
73
+ ```
74
+
75
+ ## Dashboard
76
+
77
+ Run `globox -d` to launch a temporary web dashboard:
78
+
79
+ - Search and filter packages in real-time
80
+ - Click column headers to sort by Package, Size, or Manager
81
+ - Filter by package manager with toggle buttons
82
+ - "Check for updates" button to see outdated packages
83
+ - Stats at a glance — total packages, total disk size, per-manager counts
84
+ - Auto-opens in your browser, shuts down on Ctrl+C
85
+
86
+ ## How It Works
87
+
88
+ 1. **Detect** — globox checks which package managers are installed (npm, pnpm, yarn)
89
+ 2. **Scan** — runs each manager's list command in parallel and parses the output
90
+ 3. **Display** — aggregates results into a formatted table, JSON, or interactive dashboard
91
+
92
+ Managers that aren't installed are silently skipped. Yarn Berry (v2+) is handled gracefully since `yarn global` was removed.
93
+
94
+ ## Commands
95
+
96
+ ```bash
97
+ globox # List all global packages
98
+ globox -d, --dashboard # Open interactive web dashboard
99
+ globox -m, --manager <names> # Filter by manager (comma-separated: npm,pnpm,yarn)
100
+ globox -s, --size # Show disk size of each package
101
+ globox --sort <field> # Sort by: name (default) or size
102
+ globox -o, --outdated # Show outdated packages with latest versions
103
+ globox --doctor # Detect duplicates across managers
104
+ globox -e, --export <path> # Export to JSON or CSV file
105
+ globox -j, --json # Output as JSON
106
+ globox --no-color # Disable colored output
107
+ globox -v, --version # Print version
108
+ globox -h, --help # Show help
109
+ ```
110
+
111
+ Flags can be combined:
112
+
113
+ ```bash
114
+ globox -s -m npm # npm packages with sizes
115
+ globox --sort size -m pnpm # pnpm packages sorted by size
116
+ globox -d -o # dashboard with pre-loaded outdated info
117
+ globox --json --sort size # JSON output sorted by size
118
+ ```
119
+
120
+ ## Supported Package Managers
121
+
122
+ | Manager | Detection | Global List | Notes |
123
+ | --- | --- | --- | --- |
124
+ | **npm** | `npm --version` | `npm list -g --json` | Full support |
125
+ | **pnpm** | `pnpm --version` | `pnpm list -g --json` | Full support |
126
+ | **yarn** | `yarn --version` | `yarn global list` | v1 (Classic) only — Yarn Berry removed `yarn global` |
127
+
128
+ Managers that aren't installed are silently skipped.
129
+
130
+ ## Requirements
131
+
132
+ - Node.js >= 18
133
+
134
+ ## License
135
+
136
+ MIT
package/bin/globox.js ADDED
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import chalk from "chalk";
5
+ import ora from "ora";
6
+ import {
7
+ detectManagers,
8
+ listAllPackages,
9
+ printTable,
10
+ printOutdatedTable,
11
+ checkOutdated,
12
+ findDuplicates,
13
+ printDuplicates,
14
+ exportPackages,
15
+ enrichWithSizes,
16
+ startDashboard,
17
+ } from "../src/index.js";
18
+
19
+ const program = new Command();
20
+
21
+ program
22
+ .name("globox")
23
+ .description(
24
+ "One command to list all globally installed npm, pnpm, and yarn packages."
25
+ )
26
+ .version("1.0.0", "-v, --version")
27
+ .option("-d, --dashboard", "Open an interactive dashboard in the browser")
28
+ .option(
29
+ "-m, --manager <managers>",
30
+ "Filter by package manager (comma-separated: npm,pnpm,yarn)"
31
+ )
32
+ .option("-j, --json", "Output as JSON")
33
+ .option("-o, --outdated", "Show only outdated packages")
34
+ .option("--doctor", "Detect duplicate packages across managers")
35
+ .option("-e, --export <path>", "Export package list to a JSON or CSV file")
36
+ .option("-s, --size", "Show disk size of each package")
37
+ .option("--sort <field>", "Sort by: name (default) or size", "name")
38
+ .option("--no-color", "Disable colored output")
39
+ .showHelpAfterError(true)
40
+ .allowExcessArguments(false);
41
+
42
+ program.on("command:*", ([cmd]) => {
43
+ console.error(chalk.red(`\n Unknown command: ${cmd}\n`));
44
+ console.error(` Run ${chalk.bold("globox --help")} to see available options.\n`);
45
+ process.exit(1);
46
+ });
47
+
48
+ program.parse();
49
+
50
+ const opts = program.opts();
51
+
52
+ async function fetchOutdated(pkgs) {
53
+ const spinner = ora("Checking for updates...").start();
54
+ const enriched = await checkOutdated(pkgs, {
55
+ onProgress: (done, total) => {
56
+ spinner.text = `Checking for updates... (${done}/${total})`;
57
+ },
58
+ });
59
+ spinner.succeed("Version check complete");
60
+ return enriched;
61
+ }
62
+
63
+ async function main() {
64
+ const filter = opts.manager
65
+ ? opts.manager.split(",").map((m) => m.trim().toLowerCase())
66
+ : null;
67
+
68
+ // Detect managers
69
+ const detectSpinner = ora("Detecting package managers...").start();
70
+ const managers = await detectManagers(filter);
71
+
72
+ if (managers.length === 0) {
73
+ detectSpinner.fail("No package managers found.");
74
+ if (filter) {
75
+ console.log(
76
+ chalk.yellow(
77
+ `\n None of the specified managers (${filter.join(", ")}) are installed.\n`
78
+ )
79
+ );
80
+ }
81
+ process.exit(1);
82
+ }
83
+
84
+ detectSpinner.succeed(
85
+ `Found ${managers.map((m) => `${chalk.bold(m.name)} v${m.version}`).join(", ")}`
86
+ );
87
+
88
+ // List packages
89
+ const listSpinner = ora("Scanning global packages...").start();
90
+ const packages = await listAllPackages(managers);
91
+ listSpinner.succeed(`Found ${chalk.bold(packages.length)} global packages`);
92
+
93
+ if (packages.length === 0) {
94
+ console.log(
95
+ chalk.yellow("\n No globally installed packages found.\n")
96
+ );
97
+ process.exit(0);
98
+ }
99
+
100
+ // Enrich with disk sizes if requested, dashboard, or sorting by size
101
+ const needsSize = opts.size || opts.dashboard || opts.sort === "size";
102
+ let pkgs = packages;
103
+ if (needsSize) {
104
+ const sizeSpinner = ora("Calculating package sizes...").start();
105
+ pkgs = await enrichWithSizes(packages, {
106
+ onProgress: (done, total) => {
107
+ sizeSpinner.text = `Calculating package sizes... (${done}/${total})`;
108
+ },
109
+ });
110
+ sizeSpinner.succeed("Size calculation complete");
111
+ }
112
+
113
+ // Apply sort
114
+ if (opts.sort === "size") {
115
+ pkgs = [...pkgs].sort((a, b) => (b.size || 0) - (a.size || 0));
116
+ }
117
+
118
+ // JSON output
119
+ if (opts.json) {
120
+ console.log(JSON.stringify(pkgs, null, 2));
121
+ return;
122
+ }
123
+
124
+ // Dashboard
125
+ if (opts.dashboard) {
126
+ const dashPkgs = opts.outdated ? await fetchOutdated(pkgs) : pkgs;
127
+ await startDashboard(dashPkgs, managers, { outdated: opts.outdated });
128
+ return;
129
+ }
130
+
131
+ // Doctor mode
132
+ if (opts.doctor) {
133
+ const duplicates = findDuplicates(pkgs);
134
+ printDuplicates(duplicates);
135
+ return;
136
+ }
137
+
138
+ // Outdated mode
139
+ if (opts.outdated) {
140
+ printOutdatedTable(await fetchOutdated(pkgs));
141
+ return;
142
+ }
143
+
144
+ // Export
145
+ if (opts.export) {
146
+ await exportPackages(pkgs, opts.export);
147
+ return;
148
+ }
149
+
150
+ // Default: print table
151
+ printTable(pkgs, { showSize: opts.size || opts.sort === "size" });
152
+ }
153
+
154
+ main().catch((err) => {
155
+ console.error(chalk.red(`\n Error: ${err.message}\n`));
156
+ process.exit(1);
157
+ });
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "globox",
3
+ "version": "1.0.1",
4
+ "description": "One command to list all globally installed npm, pnpm, and yarn packages — with an optional dashboard.",
5
+ "type": "module",
6
+ "bin": {
7
+ "globox": "./bin/globox.js"
8
+ },
9
+ "main": "./src/index.js",
10
+ "scripts": {
11
+ "start": "node bin/globox.js",
12
+ "test": "node bin/globox.js"
13
+ },
14
+ "keywords": [
15
+ "cli",
16
+ "npm",
17
+ "pnpm",
18
+ "yarn",
19
+ "global",
20
+ "packages",
21
+ "dashboard",
22
+ "list",
23
+ "package-manager"
24
+ ],
25
+ "author": "",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "chalk": "^5.4.1",
29
+ "cli-table3": "^0.6.5",
30
+ "commander": "^13.1.0",
31
+ "execa": "^9.5.2",
32
+ "open": "^10.1.0",
33
+ "ora": "^8.2.0"
34
+ },
35
+ "engines": {
36
+ "node": ">=18.0.0"
37
+ }
38
+ }
@@ -0,0 +1 @@
1
+ export const MANAGER_ORDER = { npm: 0, pnpm: 1, yarn: 2 };
@@ -0,0 +1,87 @@
1
+ import { createServer } from "node:http";
2
+ import { readFile } from "node:fs/promises";
3
+ import { fileURLToPath } from "node:url";
4
+ import { dirname, join } from "node:path";
5
+ import open from "open";
6
+ import chalk from "chalk";
7
+ import { checkOutdated } from "../outdated.js";
8
+ import { MANAGER_ORDER } from "../constants.js";
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = dirname(__filename);
12
+
13
+ /**
14
+ * Start a temporary dashboard server and open it in the browser.
15
+ * Returns a cleanup function to shut down the server.
16
+ */
17
+ export async function startDashboard(packages, managers, { outdated = false } = {}) {
18
+ const templatePath = join(__dirname, "template.html");
19
+ let html = await readFile(templatePath, "utf-8");
20
+
21
+ const payload = JSON.stringify({
22
+ packages,
23
+ managers: managers.map((m) => ({ name: m.name, version: m.version })),
24
+ managerOrder: MANAGER_ORDER,
25
+ generatedAt: new Date().toISOString(),
26
+ outdatedPreloaded: outdated,
27
+ });
28
+
29
+ html = html.replace("__GLOBOX_DATA__", payload);
30
+
31
+ let outdatedCache = null;
32
+
33
+ const server = createServer(async (req, res) => {
34
+ if (req.url === "/api/outdated") {
35
+ res.writeHead(200, {
36
+ "Content-Type": "application/json",
37
+ "Access-Control-Allow-Origin": "*",
38
+ });
39
+
40
+ try {
41
+ if (!outdatedCache) {
42
+ outdatedCache = await checkOutdated(packages);
43
+ }
44
+ res.end(JSON.stringify(outdatedCache));
45
+ } catch (err) {
46
+ res.end(JSON.stringify({ error: err.message }));
47
+ }
48
+ return;
49
+ }
50
+
51
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
52
+ res.end(html);
53
+ });
54
+
55
+ return new Promise((resolve) => {
56
+ server.listen(0, "127.0.0.1", async () => {
57
+ const { port } = server.address();
58
+ const url = `http://127.0.0.1:${port}`;
59
+
60
+ console.log(
61
+ chalk.cyan(
62
+ `\n Dashboard running at ${chalk.bold.underline(url)}`
63
+ )
64
+ );
65
+ console.log(chalk.gray(" Press Ctrl+C to stop and clean up\n"));
66
+
67
+ await open(url);
68
+
69
+ const cleanup = () => {
70
+ server.close();
71
+ console.log(chalk.gray("\n Dashboard stopped.\n"));
72
+ };
73
+
74
+ process.on("SIGINT", () => {
75
+ cleanup();
76
+ process.exit(0);
77
+ });
78
+
79
+ process.on("SIGTERM", () => {
80
+ cleanup();
81
+ process.exit(0);
82
+ });
83
+
84
+ resolve(cleanup);
85
+ });
86
+ });
87
+ }