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 +50 -0
- package/README.md +136 -0
- package/bin/globox.js +157 -0
- package/package.json +38 -0
- package/src/constants.js +1 -0
- package/src/dashboard/server.js +87 -0
- package/src/dashboard/template.html +617 -0
- package/src/detect.js +42 -0
- package/src/doctor.js +50 -0
- package/src/export.js +34 -0
- package/src/index.js +8 -0
- package/src/list.js +126 -0
- package/src/outdated.js +38 -0
- package/src/size.js +108 -0
- package/src/table.js +102 -0
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
|
+
}
|
package/src/constants.js
ADDED
|
@@ -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
|
+
}
|