forged-cli 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/bin/forged.js CHANGED
@@ -12,6 +12,7 @@ const [,, command, ...args] = process.argv;
12
12
  const commands = {
13
13
  readme: 'Generate a README.md for the current project',
14
14
  scan: 'Audit dependencies for typosquats, bad scripts, and suspicious binaries',
15
+ gen: 'Generate passwords, secrets, PINs, and UUIDs',
15
16
  init: 'Scaffold a new dev environment',
16
17
  new: 'Create a new project with GitHub setup',
17
18
  install: 'Install Forged into an existing shell config',
@@ -42,6 +43,12 @@ if (command === 'readme') {
42
43
  process.exit(0);
43
44
  }
44
45
 
46
+ if (command === 'gen') {
47
+ const { genCommand } = await import('../src/commands/gen.js');
48
+ await genCommand(args);
49
+ process.exit(0);
50
+ }
51
+
45
52
  if (command === 'scan') {
46
53
  const { scanCommand } = await import('../src/commands/scan.js');
47
54
  const { resolve } = await import('path');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forged-cli",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
4
4
  "description": "A complete dev environment toolkit — shell, workflows, and project scaffolding in one install.",
5
5
  "keywords": [
6
6
  "cli",
@@ -12,13 +12,13 @@
12
12
  ],
13
13
  "author": "Brandon <DevBrandon@icloud.com> (https://github.com/bkness)",
14
14
  "license": "MIT",
15
- "homepage": "https://github.com/RevenueWebs/forged-cli#readme",
15
+ "homepage": "https://github.com/bkness/forged-cli#readme",
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+ssh://git@github.com/RevenueWebs/forged-cli.git"
18
+ "url": "git+ssh://git@github.com/bkness/forged-cli.git"
19
19
  },
20
20
  "bugs": {
21
- "url": "https://github.com/RevenueWebs/forged-cli/issues"
21
+ "url": "https://github.com/bkness/forged-cli/issues"
22
22
  },
23
23
  "type": "module",
24
24
  "bin": {
@@ -0,0 +1,102 @@
1
+ import { randomBytes, randomUUID } from 'crypto';
2
+
3
+ const green = '\x1b[32m';
4
+ const yellow = '\x1b[33m';
5
+ const red = '\x1b[31m';
6
+ const blue = '\x1b[34m';
7
+ const bold = '\x1b[1m';
8
+ const reset = '\x1b[0m';
9
+ const dim = '\x1b[2m';
10
+
11
+ const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
12
+ const LOWER = 'abcdefghijklmnopqrstuvwxyz';
13
+ const DIGITS = '0123456789';
14
+ const SYMBOLS = '!@#$%^&*()-_=+[]{}|;:,.<>?';
15
+ const SAFE = '-_';
16
+
17
+ function randomChar(charset) {
18
+ return charset[randomBytes(1)[0] % charset.length];
19
+ }
20
+
21
+ function generatePassword(length, safe = false) {
22
+ const symbols = safe ? SAFE : SYMBOLS;
23
+ const charset = UPPER + LOWER + DIGITS + symbols;
24
+ const required = [
25
+ randomChar(UPPER),
26
+ randomChar(LOWER),
27
+ randomChar(DIGITS),
28
+ randomChar(symbols),
29
+ ];
30
+ const rest = Array.from({ length: length - required.length }, () => randomChar(charset));
31
+ const all = [...required, ...rest];
32
+ for (let i = all.length - 1; i > 0; i--) {
33
+ const j = randomBytes(1)[0] % (i + 1);
34
+ [all[i], all[j]] = [all[j], all[i]];
35
+ }
36
+ return all.join('');
37
+ }
38
+
39
+ function colorize(password) {
40
+ return password.split('').map(char => {
41
+ if (/[0-9]/.test(char)) return `${yellow}${char}${reset}`;
42
+ if (/[^a-zA-Z0-9]/.test(char)) return `${red}${char}${reset}`;
43
+ return char;
44
+ }).join('');
45
+ }
46
+
47
+ function generatePin(length) {
48
+ return Array.from({ length }, () => randomBytes(1)[0] % 10).join('');
49
+ }
50
+
51
+ export async function genCommand(args) {
52
+ const sub = args[0];
53
+ const safe = args.includes('--safe') || args.includes('--ascii');
54
+ const lenArg = args.find(a => /^(-l=|--length=)/.test(a));
55
+ const length = lenArg ? parseInt(lenArg.split('=')[1]) : null;
56
+
57
+ if (!sub || sub === 'help') {
58
+ console.log(`
59
+ ${bold}forged gen${reset} — generate secure credentials
60
+
61
+ ${dim}Usage:${reset}
62
+ forged gen pass Secure password ${dim}(default 20 chars)${reset}
63
+ forged gen pass --safe ASCII-only, no symbols — safe for routers
64
+ forged gen secret 32-byte hex — JWT secrets, API keys
65
+ forged gen pin 6-digit numeric PIN
66
+ forged gen uuid UUID v4
67
+
68
+ ${dim}Options:${reset}
69
+ --length=N, -l=N Custom length (pass, pin)
70
+ --safe, --ascii Letters + numbers only
71
+ `);
72
+ return;
73
+ }
74
+
75
+ if (sub === 'pass') {
76
+ const len = length ?? 20;
77
+ if (len < 4) { console.log(` ${red}Length must be at least 4${reset}`); return; }
78
+ const pass = generatePassword(len, safe);
79
+ console.log(`\n ${bold}Password${reset} ${colorize(pass)}`);
80
+ if (safe) console.log(` ${dim}ASCII-safe — router/device friendly${reset}`);
81
+ console.log();
82
+ return;
83
+ }
84
+
85
+ if (sub === 'secret') {
86
+ console.log(`\n ${bold}Secret${reset} ${green}${randomBytes(32).toString('hex')}${reset}\n`);
87
+ return;
88
+ }
89
+
90
+ if (sub === 'pin') {
91
+ const len = length ?? 6;
92
+ console.log(`\n ${bold}PIN${reset} ${yellow}${generatePin(len)}${reset}\n`);
93
+ return;
94
+ }
95
+
96
+ if (sub === 'uuid') {
97
+ console.log(`\n ${bold}UUID${reset} ${blue}${randomUUID()}${reset}\n`);
98
+ return;
99
+ }
100
+
101
+ console.log(` ${red}Unknown:${reset} '${sub}' — run ${bold}forged gen help${reset}`);
102
+ }
@@ -15,6 +15,34 @@ export const TRUSTED_COMMUNITY = new Set([
15
15
  'ulisesgascon', 'formidablelabs',
16
16
  'blakeembrey', 'wesleytodd', 'danez', 'domenic', 'panva', 'joshuakgoldberg',
17
17
  'matteo.collina', 'rvagg',
18
+ // React-Bootstrap / @restart team
19
+ 'kytsang', 'monastic.panic',
20
+ // Chart.js core
21
+ 'etimberg',
22
+ // commander contributor
23
+ 'abetomo',
24
+ // isomorphic-fetch (Financial Times official org)
25
+ 'financial-times',
26
+ // webpack core team
27
+ 'evilebottnawi',
28
+ // mass transfer from shinnn — all legitimate
29
+ 'stevemao',
30
+ // TC39 delegate, took over ESLint packages from nzakas
31
+ 'michaelficarra',
32
+ // raf maintainer
33
+ 'cmtegner',
34
+ // known React developer, react-text-mask
35
+ 'browniefed',
36
+ // perfect-scrollbar current maintainer
37
+ 'mattonit',
38
+ // Mapbox internal npm account rotation
39
+ 'mapbox-npm-01', 'mapbox-npm-03',
40
+ // Prettier automated release bot (replaced fisker)
41
+ 'prettier-bot',
42
+ // Sequelize current maintainer (replaced sdepold, original creator)
43
+ 'wikirik',
44
+ // Meta/React Native core team (replaced zertosh on v8-compile-cache)
45
+ 'yungsters',
18
46
  ]);
19
47
 
20
48
  export function classifyPublisherChange(from, to) {