Skip to content

Commit b05d71e

Browse files
authored
feat: add todo, size, and env commands (#1)
* feat: add todo, size, and env commands * chore: update description with new commands
1 parent 5d9d02d commit b05d71e

2 files changed

Lines changed: 83 additions & 2 deletions

File tree

index.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,81 @@ const commands = {
101101
}
102102
},
103103

104+
105+
todo: {
106+
desc: 'Scan for TODO/FIXME/HACK comments',
107+
run: (dir = '.') => {
108+
const results = [];
109+
const scan = (d) => {
110+
fs.readdirSync(d).forEach(f => {
111+
const p = path.join(d, f);
112+
if (f.startsWith('.') || f === 'node_modules') return;
113+
if (fs.statSync(p).isDirectory()) scan(p);
114+
else if (/\.(js|ts|py|go|rs|c|h|java|rb|md)$/.test(f)) {
115+
const lines = fs.readFileSync(p, 'utf8').split('\n');
116+
lines.forEach((line, i) => {
117+
if (/TODO|FIXME|HACK|XXX/.test(line)) {
118+
results.push(` ${p}:${i+1} ${line.trim()}`);
119+
}
120+
});
121+
}
122+
});
123+
};
124+
scan(dir);
125+
if (results.length === 0) {
126+
console.log('✅ No TODOs found. Grug impressed.');
127+
} else {
128+
console.log(`📋 Found ${results.length} TODO(s):\n`);
129+
results.forEach(r => console.log(r));
130+
}
131+
}
132+
},
133+
134+
size: {
135+
desc: 'Find largest files in project',
136+
run: (dir = '.', limit = 10) => {
137+
const files = [];
138+
const scan = (d) => {
139+
fs.readdirSync(d).forEach(f => {
140+
const p = path.join(d, f);
141+
if (f.startsWith('.') || f === 'node_modules') return;
142+
const stat = fs.statSync(p);
143+
if (stat.isDirectory()) scan(p);
144+
else files.push({ path: p, size: stat.size });
145+
});
146+
};
147+
scan(dir);
148+
files.sort((a, b) => b.size - a.size);
149+
const fmt = (b) => b > 1024*1024 ? `${(b/1024/1024).toFixed(1)}MB` : b > 1024 ? `${(b/1024).toFixed(1)}KB` : `${b}B`;
150+
console.log(`📦 Largest ${Math.min(limit, files.length)} files:\n`);
151+
files.slice(0, parseInt(limit)).forEach(f => {
152+
const flag = f.size > 500*1024 ? ' ⚠️' : '';
153+
console.log(` ${fmt(f.size).padEnd(8)} ${f.path}${flag}`);
154+
});
155+
}
156+
},
157+
158+
env: {
159+
desc: 'List .env keys (no values shown)',
160+
run: (file = '.env') => {
161+
if (!fs.existsSync(file)) {
162+
console.log(`❌ ${file} not found`);
163+
return;
164+
}
165+
const lines = fs.readFileSync(file, 'utf8').split('\n');
166+
const keys = lines
167+
.filter(l => l.trim() && !l.startsWith('#') && l.includes('='))
168+
.map(l => l.split('=')[0].trim());
169+
if (keys.length === 0) {
170+
console.log('📭 No keys found');
171+
return;
172+
}
173+
console.log(`🔑 ${file} keys (${keys.length}):\n`);
174+
keys.forEach(k => console.log(` ${k}`));
175+
console.log('\n🔒 Values hidden. Grug protect secrets.');
176+
}
177+
},
178+
104179
help: {
105180
desc: 'Show this help',
106181
run: () => {

package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
{
22
"name": "grug-cli",
33
"version": "1.0.0",
4-
"description": "🪨 Zero-dependency developer toolkit following grug-brained principles",
4+
"description": "Zero-dependency developer toolkit \u2014 init, loc, deps, clean, ship, todo, size, env",
55
"main": "index.ts",
66
"bin": {
77
"grug-cli": "./index.ts"
88
},
99
"type": "module",
10-
"keywords": ["cli", "developer-tools", "bun", "grug", "zero-dependencies"],
10+
"keywords": [
11+
"cli",
12+
"developer-tools",
13+
"bun",
14+
"grug",
15+
"zero-dependencies"
16+
],
1117
"author": "grug-group420",
1218
"license": "MIT",
1319
"repository": {

0 commit comments

Comments
 (0)