forged-cli 0.8.0 → 0.8.2
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/README.md +16 -6
- package/bin/forged.js +2 -2
- package/package.json +2 -2
- package/src/commands/init.js +10 -2
- package/src/commands/readme.js +70 -63
package/README.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
> Your dev environment, forged.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/forged-cli)
|
|
6
|
+
[](https://www.npmjs.com/package/forged-cli)
|
|
7
|
+
[](https://github.com/bkness/forged-cli/actions/workflows/test.yml)
|
|
8
|
+
[](https://github.com/bkness/forged-cli)
|
|
9
9
|
|
|
10
10
|
**Forged** is a CLI toolkit for developers: a guided zsh setup, a dependency security scanner, a credential generator, and a README generator.
|
|
11
11
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
npm install -g forged-cli
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
Requires Node.js
|
|
22
|
+
Requires Node.js 20.12 or newer. Published from GitHub Actions with [npm provenance](https://docs.npmjs.com/generating-provenance-statements), so every release is traceable to the commit that built it.
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -48,7 +48,7 @@ forged readme
|
|
|
48
48
|
It's written for people new to the terminal. It shows the whole plan first, explains each step, and asks before doing it:
|
|
49
49
|
|
|
50
50
|
1. **Homebrew on your PATH.** If Homebrew is installed but `brew` isn't found (the installer's last step is easy to miss), adds its `shellenv` line to `~/.zprofile`
|
|
51
|
-
2. **Command-line tools.** Installs whichever of `git gh fzf eza bat fd zoxide starship` are missing, with Homebrew
|
|
51
|
+
2. **Command-line tools.** Installs whichever of `git gh fzf eza bat fd zoxide starship ripgrep jq` are missing, with Homebrew
|
|
52
52
|
3. **zinit**, the plugin manager, cloned to `~/.local/share/zinit`
|
|
53
53
|
4. **The dotfiles**, cloned to `~/dev/dotfiles`
|
|
54
54
|
5. **One line in `~/.zshrc`** that loads them. The file is backed up first, and nothing already in it is changed
|
|
@@ -63,6 +63,16 @@ Steps that are already done are skipped, so it's safe to run again after fixing
|
|
|
63
63
|
|
|
64
64
|
Needs macOS or Linux. Without Homebrew (on Linux, say), init lists the missing tools for you to install yourself and does the rest.
|
|
65
65
|
|
|
66
|
+
### After `forged init`
|
|
67
|
+
|
|
68
|
+
Three things init can't do for you:
|
|
69
|
+
|
|
70
|
+
1. **Log in to GitHub** for the Ctrl+G dashboard: `gh auth login`. Project boards also need `gh auth refresh -s project`
|
|
71
|
+
2. **Install a Nerd Font** so file icons show instead of boxes: `brew install --cask font-jetbrains-mono-nerd-font`, then choose "JetBrainsMono Nerd Font" in your terminal's font settings
|
|
72
|
+
3. **Linux only: make zsh your shell** with `chsh -s "$(which zsh)"`, then log out and back in. macOS already uses zsh
|
|
73
|
+
|
|
74
|
+
Then run `exec zsh` (or open a new tab) to load it.
|
|
75
|
+
|
|
66
76
|
---
|
|
67
77
|
|
|
68
78
|
## 🔍 Security Scanner
|
package/bin/forged.js
CHANGED
|
@@ -59,8 +59,8 @@ if (command === 'version') {
|
|
|
59
59
|
|
|
60
60
|
if (command === 'readme') {
|
|
61
61
|
const { readmeCommand } = await import('../src/commands/readme.js');
|
|
62
|
-
await readmeCommand(args[0] || 'README.md');
|
|
63
|
-
process.exit(0);
|
|
62
|
+
const written = await readmeCommand(args[0] || 'README.md');
|
|
63
|
+
process.exit(written === false ? 130 : 0); // 130 = cancelled with Ctrl+C
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
if (command === 'init') {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "forged-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "A complete dev environment toolkit — shell, workflows, and project scaffolding in one install.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"forged": "bin/forged.js"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
|
-
"node": ">=
|
|
28
|
+
"node": ">=20.12"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
31
|
"start": "node bin/forged.js",
|
package/src/commands/init.js
CHANGED
|
@@ -22,8 +22,14 @@ export const TOOLS = {
|
|
|
22
22
|
fd: 'a faster `find`',
|
|
23
23
|
zoxide: 'jump to folders you visit often (Ctrl+J)',
|
|
24
24
|
starship: 'the prompt',
|
|
25
|
+
rg: 'fast code search behind the code finder',
|
|
26
|
+
jq: 'reads JSON, for project settings',
|
|
25
27
|
};
|
|
26
28
|
|
|
29
|
+
// Package names that differ from the command they install
|
|
30
|
+
export const PACKAGES = { rg: 'ripgrep' };
|
|
31
|
+
export const packageFor = (tool) => PACKAGES[tool] ?? tool;
|
|
32
|
+
|
|
27
33
|
export const DOTFILES_REPO = 'https://github.com/bkness/dotfiles.git';
|
|
28
34
|
export const ZINIT_REPO = 'https://github.com/zdharma-continuum/zinit.git';
|
|
29
35
|
export const HOOK_MARKER = '# forged: load the Forged shell';
|
|
@@ -150,11 +156,11 @@ function apply(step, home, run) {
|
|
|
150
156
|
}
|
|
151
157
|
case 'tools': {
|
|
152
158
|
if (!step.brewAvailable) {
|
|
153
|
-
console.log(` ${yellow}Homebrew isn't installed, so install these yourself:${reset} ${bold}${step.missing.join(' ')}${reset}`);
|
|
159
|
+
console.log(` ${yellow}Homebrew isn't installed, so install these yourself:${reset} ${bold}${step.missing.map(packageFor).join(' ')}${reset}`);
|
|
154
160
|
console.log(` ${dim}On a Mac, get Homebrew from https://brew.sh and run forged init again. On Linux, use your package manager.${reset}`);
|
|
155
161
|
return 'manual';
|
|
156
162
|
}
|
|
157
|
-
return run(step.brew, ['install', ...step.missing]);
|
|
163
|
+
return run(step.brew, ['install', ...step.missing.map(packageFor)]);
|
|
158
164
|
}
|
|
159
165
|
case 'zinit':
|
|
160
166
|
return run('git', ['clone', '--depth', '1', ZINIT_REPO, step.dir]);
|
|
@@ -237,6 +243,8 @@ export async function initCommand(args, { home = homedir(), env = realEnv(home),
|
|
|
237
243
|
console.log(` ${green}${bold}All set.${reset} Next:`);
|
|
238
244
|
console.log(` ${bold}exec zsh${reset} load the new shell in this window`);
|
|
239
245
|
console.log(` ${bold}gh auth login${reset} connect GitHub, for the Ctrl+G dashboard`);
|
|
246
|
+
console.log(` ${bold}a Nerd Font${reset} for file icons: ${bold}brew install --cask font-jetbrains-mono-nerd-font${reset},`);
|
|
247
|
+
console.log(` then pick it in your terminal's font settings`);
|
|
240
248
|
console.log(` ${bold}Ctrl+P${reset} browse every command\n`);
|
|
241
249
|
return 0;
|
|
242
250
|
}
|
package/src/commands/readme.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
2
|
import { writeFile } from 'fs/promises';
|
|
3
3
|
import { resolve } from 'path';
|
|
4
4
|
import { detectProjectInfo } from '../utils/detectProject.js';
|
|
5
5
|
import { generateMarkdown } from '../utils/generateMarkdown.js';
|
|
6
6
|
|
|
7
|
-
const require = createRequire(import.meta.url);
|
|
8
|
-
const { prompt } = require('inquirer');
|
|
9
|
-
|
|
10
7
|
const green = '\x1b[32m';
|
|
11
8
|
const purple = '\x1b[35m';
|
|
12
9
|
const reset = '\x1b[0m';
|
|
@@ -18,65 +15,75 @@ export async function readmeCommand(outputPath = 'README.md') {
|
|
|
18
15
|
if (detected.github) console.log(` Detected GitHub user: ${detected.github}`);
|
|
19
16
|
console.log(' Press Enter to accept defaults.\n');
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
18
|
+
let answers;
|
|
19
|
+
try {
|
|
20
|
+
answers = await inquirer.prompt([
|
|
21
|
+
{
|
|
22
|
+
type: 'input',
|
|
23
|
+
name: 'title',
|
|
24
|
+
message: `${green}Project name:${reset}`,
|
|
25
|
+
default: detected.title,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
type: 'input',
|
|
29
|
+
name: 'description',
|
|
30
|
+
message: `${green}Short description:${reset}`,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'input',
|
|
34
|
+
name: 'toDo',
|
|
35
|
+
message: `${green}To-do items (leave blank to skip section):${reset}`,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
type: 'list',
|
|
39
|
+
name: 'license',
|
|
40
|
+
message: `${green}License:${reset}`,
|
|
41
|
+
choices: ['MIT', 'APACHE 2.0', 'GPL 3.0', 'BSD 3', 'None'],
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
type: 'input',
|
|
45
|
+
name: 'installation',
|
|
46
|
+
message: `${green}Install command:${reset}`,
|
|
47
|
+
default: detected.installCommand,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
type: 'input',
|
|
51
|
+
name: 'test',
|
|
52
|
+
message: `${green}Test command:${reset}`,
|
|
53
|
+
default: detected.testCommand,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
type: 'input',
|
|
57
|
+
name: 'usage',
|
|
58
|
+
message: `${green}Usage instructions:${reset}`,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
type: 'input',
|
|
62
|
+
name: 'contributing',
|
|
63
|
+
message: `${green}Contributing guidelines:${reset}`,
|
|
64
|
+
default: 'Fork the project and open a pull request with your changes',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: 'input',
|
|
68
|
+
name: 'github',
|
|
69
|
+
message: `${green}GitHub username:${reset}`,
|
|
70
|
+
default: detected.github,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
type: 'input',
|
|
74
|
+
name: 'email',
|
|
75
|
+
message: `${green}Email address:${reset}`,
|
|
76
|
+
default: detected.email,
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
// Ctrl+C makes Inquirer throw ExitPromptError; without this it crashed
|
|
81
|
+
if (err?.name === 'ExitPromptError') {
|
|
82
|
+
console.log(`\n${purple}Cancelled. Nothing was written.${reset}\n`);
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
throw err;
|
|
86
|
+
}
|
|
80
87
|
|
|
81
88
|
const markdown = generateMarkdown(answers);
|
|
82
89
|
await writeFile(resolve(outputPath), markdown, 'utf8');
|