reposizer 0.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/LICENSE +21 -0
- package/README.md +116 -0
- package/dist/bin/reposizer.js +44 -0
- package/dist/src/commands/repo.js +108 -0
- package/dist/src/services/github.js +77 -0
- package/dist/src/utils/git.js +34 -0
- package/dist/src/utils/size.js +22 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# reposizer
|
|
2
|
+
|
|
3
|
+
> Fast CLI to inspect GitHub repository sizes.
|
|
4
|
+
|
|
5
|
+
Check repo size before you clone. Analyze large codebases instantly.
|
|
6
|
+
|
|
7
|
+
## Demo
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx reposizer torvalds/linux
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
Repository: torvalds/linux
|
|
15
|
+
Size: 4.82 GB
|
|
16
|
+
Stars: 190k
|
|
17
|
+
Language: C
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Features
|
|
21
|
+
|
|
22
|
+
- ⚡ Instant repository size lookup
|
|
23
|
+
- 🔐 Supports private repositories via `GITHUB_TOKEN`
|
|
24
|
+
- 📦 Works with `npx` (no global install required)
|
|
25
|
+
- 🧩 JSON output for scripts and CI tooling
|
|
26
|
+
- 🏢 Organization repository scanning
|
|
27
|
+
- 🔎 Current repository auto-detection (via git remote)
|
|
28
|
+
- 📚 Multi-repository lookup in one command
|
|
29
|
+
- 📊 Directory analysis (planned)
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
### Option 1: no install (recommended)
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx reposizer owner/repo
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Option 2: global install
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install -g reposizer
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### Check repository size
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
reposizer openai/gym
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Check multiple repositories
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
reposizer openai/gym vercel/next.js torvalds/linux
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Detect current repository automatically
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
reposizer
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Scan an organization
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
reposizer org openai
|
|
69
|
+
reposizer org openai --limit 50 --json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### JSON output
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
reposizer openai/gym --json
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Private repository access
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
export GITHUB_TOKEN=your_token
|
|
82
|
+
reposizer your-org/private-repo
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Example JSON Output
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"repository": "openai/gym",
|
|
90
|
+
"size_mb": 92.15,
|
|
91
|
+
"stars": 31000,
|
|
92
|
+
"language": "Python"
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Roadmap
|
|
97
|
+
|
|
98
|
+
- [x] Organization scanning
|
|
99
|
+
- [x] Current repository auto-detection
|
|
100
|
+
- [x] Multi-repository support
|
|
101
|
+
- [ ] Directory size analysis
|
|
102
|
+
- [ ] CI/CD threshold mode
|
|
103
|
+
- [ ] Repository growth tracking
|
|
104
|
+
|
|
105
|
+
## Why
|
|
106
|
+
|
|
107
|
+
Cloning a massive repository blindly is painful. Reposizer helps you inspect before you pull.
|
|
108
|
+
|
|
109
|
+
## Security Notes
|
|
110
|
+
|
|
111
|
+
- `GITHUB_TOKEN` is optional and used only for request authorization.
|
|
112
|
+
- Tokens are never printed to output or written to disk.
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT - see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const commander_1 = require("commander");
|
|
5
|
+
const repo_1 = require("../src/commands/repo");
|
|
6
|
+
const program = new commander_1.Command();
|
|
7
|
+
program
|
|
8
|
+
.name("reposizer")
|
|
9
|
+
.description("Fast CLI to inspect GitHub repository sizes");
|
|
10
|
+
program
|
|
11
|
+
.argument("[repositories...]", "One or more repositories in owner/repo format")
|
|
12
|
+
.option("--json", "Return machine-readable JSON output")
|
|
13
|
+
.action(async (repositories = [], options) => {
|
|
14
|
+
try {
|
|
15
|
+
await (0, repo_1.runRepositoriesCommand)(repositories, Boolean(options.json));
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
const message = error instanceof Error ? error.message : "Unexpected error occurred";
|
|
19
|
+
console.error(`Error: ${message}`);
|
|
20
|
+
process.exitCode = 1;
|
|
21
|
+
}
|
|
22
|
+
})
|
|
23
|
+
.addHelpText("after", "\nExamples:\n reposizer openai/gym\n reposizer openai/gym vercel/next.js\n reposizer --json");
|
|
24
|
+
program
|
|
25
|
+
.command("org")
|
|
26
|
+
.description("Scan repositories in a GitHub organization")
|
|
27
|
+
.argument("<organization>", "GitHub organization name")
|
|
28
|
+
.option("--limit <number>", "Maximum repositories to scan (1-100)", "30")
|
|
29
|
+
.option("--json", "Return machine-readable JSON output")
|
|
30
|
+
.action(async (organization, options) => {
|
|
31
|
+
try {
|
|
32
|
+
const limit = Number.parseInt(options.limit, 10);
|
|
33
|
+
if (!Number.isFinite(limit) || limit < 1 || limit > 100) {
|
|
34
|
+
throw new Error("Invalid --limit value. Use a number between 1 and 100.");
|
|
35
|
+
}
|
|
36
|
+
await (0, repo_1.runOrganizationCommand)(organization, Boolean(options.json), limit);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : "Unexpected error occurred";
|
|
40
|
+
console.error(`Error: ${message}`);
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
program.parseAsync(process.argv);
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runRepoCommand = runRepoCommand;
|
|
4
|
+
exports.runRepositoriesCommand = runRepositoriesCommand;
|
|
5
|
+
exports.runOrganizationCommand = runOrganizationCommand;
|
|
6
|
+
const github_1 = require("../services/github");
|
|
7
|
+
const git_1 = require("../utils/git");
|
|
8
|
+
const size_1 = require("../utils/size");
|
|
9
|
+
function parseRepository(input) {
|
|
10
|
+
const trimmed = input.trim();
|
|
11
|
+
const match = /^([^/\s]+)\/([^/\s]+)$/.exec(trimmed);
|
|
12
|
+
if (!match) {
|
|
13
|
+
throw new Error("Invalid repository format. Use owner/repo.");
|
|
14
|
+
}
|
|
15
|
+
return { owner: match[1], repo: match[2] };
|
|
16
|
+
}
|
|
17
|
+
async function runRepoCommand(repositoryInput, jsonOutput) {
|
|
18
|
+
const { owner, repo } = parseRepository(repositoryInput);
|
|
19
|
+
const metadata = await (0, github_1.fetchRepositoryMetadata)(owner, repo);
|
|
20
|
+
if (jsonOutput) {
|
|
21
|
+
const payload = {
|
|
22
|
+
repository: metadata.fullName,
|
|
23
|
+
size_mb: (0, size_1.kbToMbRounded)(metadata.sizeKb),
|
|
24
|
+
stars: metadata.stargazersCount,
|
|
25
|
+
language: metadata.language ?? "Unknown"
|
|
26
|
+
};
|
|
27
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(`Repository: ${metadata.fullName}`);
|
|
31
|
+
console.log(`Size: ${(0, size_1.formatSizeFromKb)(metadata.sizeKb)}`);
|
|
32
|
+
console.log(`Stars: ${(0, size_1.formatStars)(metadata.stargazersCount)}`);
|
|
33
|
+
console.log(`Language: ${metadata.language ?? "Unknown"}`);
|
|
34
|
+
}
|
|
35
|
+
function truncate(value, maxWidth) {
|
|
36
|
+
if (value.length <= maxWidth) {
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
if (maxWidth <= 1) {
|
|
40
|
+
return value.slice(0, maxWidth);
|
|
41
|
+
}
|
|
42
|
+
return `${value.slice(0, maxWidth - 1)}…`;
|
|
43
|
+
}
|
|
44
|
+
function renderOrgTable(rows) {
|
|
45
|
+
const headers = ["Repository", "Size", "Stars", "Language"];
|
|
46
|
+
const repositoryWidth = Math.min(48, Math.max(headers[0].length, ...rows.map((row) => truncate(row.repository, 48).length)));
|
|
47
|
+
const sizeWidth = Math.max(headers[1].length, ...rows.map((row) => (0, size_1.formatSizeFromKb)(row.size_mb * 1024).length));
|
|
48
|
+
const starsWidth = Math.max(headers[2].length, ...rows.map((row) => (0, size_1.formatStars)(row.stars).length));
|
|
49
|
+
const languageWidth = Math.max(headers[3].length, ...rows.map((row) => row.language.length));
|
|
50
|
+
const border = `+-${"-".repeat(repositoryWidth)}-+-${"-".repeat(sizeWidth)}-+-${"-".repeat(starsWidth)}-+-${"-".repeat(languageWidth)}-+`;
|
|
51
|
+
const headerRow = `| ${headers[0].padEnd(repositoryWidth)} | ${headers[1].padEnd(sizeWidth)} | ${headers[2].padEnd(starsWidth)} | ${headers[3].padEnd(languageWidth)} |`;
|
|
52
|
+
const bodyRows = rows.map((row) => {
|
|
53
|
+
const repository = truncate(row.repository, repositoryWidth).padEnd(repositoryWidth);
|
|
54
|
+
const size = (0, size_1.formatSizeFromKb)(row.size_mb * 1024).padEnd(sizeWidth);
|
|
55
|
+
const stars = (0, size_1.formatStars)(row.stars).padEnd(starsWidth);
|
|
56
|
+
const language = row.language.padEnd(languageWidth);
|
|
57
|
+
return `| ${repository} | ${size} | ${stars} | ${language} |`;
|
|
58
|
+
});
|
|
59
|
+
return [border, headerRow, border, ...bodyRows, border].join("\n");
|
|
60
|
+
}
|
|
61
|
+
function buildPayload(repositoryInput, metadata) {
|
|
62
|
+
return {
|
|
63
|
+
repository: metadata.fullName || repositoryInput,
|
|
64
|
+
size_mb: (0, size_1.kbToMbRounded)(metadata.sizeKb),
|
|
65
|
+
stars: metadata.stargazersCount,
|
|
66
|
+
language: metadata.language ?? "Unknown"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
async function runRepositoriesCommand(repositoryInputs, jsonOutput) {
|
|
70
|
+
const effectiveInputs = repositoryInputs.length > 0
|
|
71
|
+
? repositoryInputs
|
|
72
|
+
: [(0, git_1.detectCurrentRepositoryFromGitRemote)()];
|
|
73
|
+
const results = await Promise.all(effectiveInputs.map(async (input) => {
|
|
74
|
+
const { owner, repo } = parseRepository(input);
|
|
75
|
+
const metadata = await (0, github_1.fetchRepositoryMetadata)(owner, repo);
|
|
76
|
+
return buildPayload(input, metadata);
|
|
77
|
+
}));
|
|
78
|
+
if (jsonOutput) {
|
|
79
|
+
console.log(JSON.stringify(results.length === 1 ? results[0] : results, null, 2));
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const result of results) {
|
|
83
|
+
console.log(`Repository: ${result.repository}`);
|
|
84
|
+
console.log(`Size: ${(0, size_1.formatSizeFromKb)(result.size_mb * 1024)}`);
|
|
85
|
+
console.log(`Stars: ${(0, size_1.formatStars)(result.stars)}`);
|
|
86
|
+
console.log(`Language: ${result.language}`);
|
|
87
|
+
console.log("");
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function runOrganizationCommand(organization, jsonOutput, limit) {
|
|
91
|
+
const repositories = await (0, github_1.fetchOrganizationRepositories)(organization, limit);
|
|
92
|
+
const payload = repositories
|
|
93
|
+
.map((repo) => ({
|
|
94
|
+
repository: repo.fullName,
|
|
95
|
+
size_mb: (0, size_1.kbToMbRounded)(repo.sizeKb),
|
|
96
|
+
stars: repo.stargazersCount,
|
|
97
|
+
language: repo.language ?? "Unknown"
|
|
98
|
+
}))
|
|
99
|
+
.sort((a, b) => b.size_mb - a.size_mb);
|
|
100
|
+
if (jsonOutput) {
|
|
101
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
console.log(`Organization: ${organization}`);
|
|
105
|
+
console.log(`Repositories scanned: ${payload.length}`);
|
|
106
|
+
console.log("");
|
|
107
|
+
console.log(renderOrgTable(payload));
|
|
108
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchRepositoryMetadata = fetchRepositoryMetadata;
|
|
4
|
+
exports.fetchOrganizationRepositories = fetchOrganizationRepositories;
|
|
5
|
+
function createHeaders(token) {
|
|
6
|
+
const headers = {
|
|
7
|
+
Accept: "application/vnd.github+json",
|
|
8
|
+
"User-Agent": "reposizer-cli"
|
|
9
|
+
};
|
|
10
|
+
if (token) {
|
|
11
|
+
headers.Authorization = `Bearer ${token}`;
|
|
12
|
+
}
|
|
13
|
+
return headers;
|
|
14
|
+
}
|
|
15
|
+
function getErrorMessage(status) {
|
|
16
|
+
if (status === 404) {
|
|
17
|
+
return "Repository not found. Check the owner/repo value.";
|
|
18
|
+
}
|
|
19
|
+
if (status === 401 || status === 403) {
|
|
20
|
+
return "GitHub API access denied. Verify GITHUB_TOKEN or rate limits.";
|
|
21
|
+
}
|
|
22
|
+
return `GitHub API returned status ${status}.`;
|
|
23
|
+
}
|
|
24
|
+
async function fetchRepositoryMetadata(owner, repo, token = process.env.GITHUB_TOKEN) {
|
|
25
|
+
const endpoint = `https://api.github.com/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`;
|
|
26
|
+
let response;
|
|
27
|
+
try {
|
|
28
|
+
response = await fetch(endpoint, {
|
|
29
|
+
method: "GET",
|
|
30
|
+
headers: createHeaders(token),
|
|
31
|
+
signal: AbortSignal.timeout(5000)
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
throw new Error("Unable to reach GitHub API. Check your network and try again.");
|
|
36
|
+
}
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
throw new Error(getErrorMessage(response.status));
|
|
39
|
+
}
|
|
40
|
+
const data = (await response.json());
|
|
41
|
+
return {
|
|
42
|
+
fullName: data.full_name,
|
|
43
|
+
sizeKb: data.size,
|
|
44
|
+
stargazersCount: data.stargazers_count,
|
|
45
|
+
language: data.language
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function fetchOrganizationRepositories(org, limit = 30, token = process.env.GITHUB_TOKEN) {
|
|
49
|
+
const safeLimit = Math.max(1, Math.min(limit, 100));
|
|
50
|
+
const endpoint = `https://api.github.com/orgs/${encodeURIComponent(org)}/repos?per_page=${safeLimit}&sort=updated&direction=desc`;
|
|
51
|
+
let response;
|
|
52
|
+
try {
|
|
53
|
+
response = await fetch(endpoint, {
|
|
54
|
+
method: "GET",
|
|
55
|
+
headers: createHeaders(token),
|
|
56
|
+
signal: AbortSignal.timeout(7000)
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
throw new Error("Unable to reach GitHub API. Check your network and try again.");
|
|
61
|
+
}
|
|
62
|
+
if (!response.ok) {
|
|
63
|
+
if (response.status === 404) {
|
|
64
|
+
throw new Error("Organization not found.");
|
|
65
|
+
}
|
|
66
|
+
throw new Error(getErrorMessage(response.status));
|
|
67
|
+
}
|
|
68
|
+
const data = (await response.json());
|
|
69
|
+
return data
|
|
70
|
+
.filter((repo) => !repo.archived && !repo.disabled)
|
|
71
|
+
.map((repo) => ({
|
|
72
|
+
fullName: repo.full_name,
|
|
73
|
+
sizeKb: repo.size,
|
|
74
|
+
stargazersCount: repo.stargazers_count,
|
|
75
|
+
language: repo.language
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.detectCurrentRepositoryFromGitRemote = detectCurrentRepositoryFromGitRemote;
|
|
4
|
+
const node_child_process_1 = require("node:child_process");
|
|
5
|
+
function parseRemoteToOwnerRepo(remoteUrl) {
|
|
6
|
+
const normalized = remoteUrl.trim().replace(/\.git$/, "");
|
|
7
|
+
const sshMatch = /^git@github\.com:([^/]+)\/([^/]+)$/.exec(normalized);
|
|
8
|
+
if (sshMatch) {
|
|
9
|
+
return `${sshMatch[1]}/${sshMatch[2]}`;
|
|
10
|
+
}
|
|
11
|
+
const httpsMatch = /^https:\/\/github\.com\/([^/]+)\/([^/]+)$/.exec(normalized);
|
|
12
|
+
if (httpsMatch) {
|
|
13
|
+
return `${httpsMatch[1]}/${httpsMatch[2]}`;
|
|
14
|
+
}
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
function detectCurrentRepositoryFromGitRemote() {
|
|
18
|
+
let remoteUrl = "";
|
|
19
|
+
try {
|
|
20
|
+
remoteUrl = (0, node_child_process_1.execFileSync)("git", ["remote", "get-url", "origin"], {
|
|
21
|
+
encoding: "utf8",
|
|
22
|
+
timeout: 2000,
|
|
23
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
24
|
+
}).trim();
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new Error("No repository argument provided and no git origin remote was detected.");
|
|
28
|
+
}
|
|
29
|
+
const ownerRepo = parseRemoteToOwnerRepo(remoteUrl);
|
|
30
|
+
if (!ownerRepo) {
|
|
31
|
+
throw new Error("Unable to parse git remote. Expected a GitHub origin remote URL.");
|
|
32
|
+
}
|
|
33
|
+
return ownerRepo;
|
|
34
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatSizeFromKb = formatSizeFromKb;
|
|
4
|
+
exports.kbToMbRounded = kbToMbRounded;
|
|
5
|
+
exports.formatStars = formatStars;
|
|
6
|
+
function formatSizeFromKb(sizeKb) {
|
|
7
|
+
const sizeMb = sizeKb / 1024;
|
|
8
|
+
if (sizeMb < 1024) {
|
|
9
|
+
return `${sizeMb.toFixed(2)} MB`;
|
|
10
|
+
}
|
|
11
|
+
const sizeGb = sizeMb / 1024;
|
|
12
|
+
return `${sizeGb.toFixed(2)} GB`;
|
|
13
|
+
}
|
|
14
|
+
function kbToMbRounded(sizeKb) {
|
|
15
|
+
return Number((sizeKb / 1024).toFixed(2));
|
|
16
|
+
}
|
|
17
|
+
function formatStars(value) {
|
|
18
|
+
if (value >= 1000) {
|
|
19
|
+
return `${Math.round((value / 1000) * 10) / 10}k`;
|
|
20
|
+
}
|
|
21
|
+
return String(value);
|
|
22
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "reposizer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fast CLI to inspect GitHub repository sizes",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Hanif",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"bin": {
|
|
9
|
+
"reposizer": "dist/bin/reposizer.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18"
|
|
18
|
+
},
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -p tsconfig.json",
|
|
21
|
+
"dev": "tsx bin/reposizer.ts",
|
|
22
|
+
"check": "tsc --noEmit -p tsconfig.json"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"cli",
|
|
26
|
+
"github",
|
|
27
|
+
"repository",
|
|
28
|
+
"size",
|
|
29
|
+
"typescript"
|
|
30
|
+
],
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"commander": "^12.1.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/node": "^22.13.10",
|
|
36
|
+
"tsx": "^4.19.3",
|
|
37
|
+
"typescript": "^5.8.2"
|
|
38
|
+
},
|
|
39
|
+
"main": "index.js",
|
|
40
|
+
"directories": {
|
|
41
|
+
"doc": "docs"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "git+https://github.com/Hanif-adedotun/reposizer.git"
|
|
46
|
+
},
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/Hanif-adedotun/reposizer/issues"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/Hanif-adedotun/reposizer#readme"
|
|
51
|
+
}
|