forgemap 0.1.0 β 0.4.0-dev.41-29cc4d0
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 +135 -22
- package/dist/bin/forgemap.mjs +2503 -52
- package/dist/bin/forgemap.mjs.map +1 -1
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
#
|
|
3
|
+
# πΊοΈ forgemap
|
|
4
4
|
|
|
5
5
|
**One consistent local layout for every repo you clone β across every forge**
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/forgemap)
|
|
8
8
|
[](https://www.npmjs.com/package/forgemap)
|
|
9
9
|
[](https://github.com/TitusKirch/forgemap/actions/workflows/ci.yml)
|
|
10
|
+
[](https://codecov.io/gh/TitusKirch/forgemap)
|
|
10
11
|
[](https://www.npmjs.com/package/forgemap)
|
|
11
12
|
[](LICENSE)
|
|
12
13
|
|
|
@@ -19,15 +20,20 @@ $ forgemap clone kirchDev/laravel-pbac
|
|
|
19
20
|
β Cloned kirchDev/laravel-pbac β ~/projects/comGithub/kirchDev/laravel-pbac
|
|
20
21
|
```
|
|
21
22
|
|
|
22
|
-
That's it. Every repo lands at a predictable `<root>/<forge.dir>/<owner>/<repo>` path, and `forgemap
|
|
23
|
+
That's it. Every repo lands at a predictable `<root>/<forge.dir>/<owner>/<repo>` path, and `forgemap cd <slug>` jumps into any of them from anywhere β exact slug, fuzzy match, or interactive picker.
|
|
23
24
|
|
|
24
25
|
## β¨ Features
|
|
25
26
|
|
|
26
27
|
- **ποΈ Predictable layout** β every clone goes to `<root>/<forge.dir>/<owner>/<repo>`, configured once.
|
|
27
28
|
- **πͺ Flexible slug syntax** β `owner/repo`, `forge:owner/repo`, full HTTPS URLs, or SSH (`git@β¦:β¦`).
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
29
|
+
- **π Fuzzy search** β `forgemap search <term>` finds local repos by owner or repo name (powered by [Fuse.js](https://www.fusejs.io/)).
|
|
30
|
+
- **π€ Forge-aware** β `type: 'github'` shells out to `gh`; `type: 'git'` uses plain `git clone` with no extra dependencies.
|
|
31
|
+
- **π Mass sync + status** β `forgemap sync` fetches every clone in parallel, `forgemap status` shows branch / dirty / ahead / behind per repo.
|
|
32
|
+
- **π₯ Import existing trees** β `forgemap import <path>` adopts a folder already laid out as `<server>/<owner>/<repo>`, reconciles each repo against its git remote (spotting moved or deleted remotes), and derives a config.
|
|
33
|
+
- **π§Ή Safe cleanup** β `forgemap cleanup` deletes long-idle local clones, but only the ones that are clean, fully pushed, and still exist on their remote β so nothing unbacked-up is ever lost.
|
|
34
|
+
- **π‘οΈ Preflight validate** β `forgemap validate` checks the config schema and required CLIs before you discover a problem mid-clone.
|
|
35
|
+
- **π§° Typed config** β `forgemap.config.ts` with `defineForgeMapConfig()`, parent walk-up discovery, and a global fallback.
|
|
36
|
+
- **π Shell-friendly** β `forgemap shell-init --install` wires up real `forgemap cd <slug>` **and** tab-completion in one step.
|
|
31
37
|
|
|
32
38
|
## π¦ Installation
|
|
33
39
|
|
|
@@ -37,8 +43,15 @@ npm install -g forgemap
|
|
|
37
43
|
pnpm add -g forgemap
|
|
38
44
|
```
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
|
|
46
|
+
**Requirements**
|
|
47
|
+
|
|
48
|
+
- Node 24+
|
|
49
|
+
- `git` on `PATH`
|
|
50
|
+
- [`gh`](https://cli.github.com/) (GitHub CLI) β only when a `type: 'github'` forge is configured
|
|
51
|
+
|
|
52
|
+
Run `forgemap validate` after setup for an exact rundown of what's needed for your config.
|
|
53
|
+
|
|
54
|
+
Hacking on forgemap itself? See [CONTRIBUTING.md β Trying the CLI locally](CONTRIBUTING.md#trying-the-cli-locally) β covers `pnpm setup`, `pnpm link --global .` and the shell-wrapper source.
|
|
42
55
|
|
|
43
56
|
## π Quick start
|
|
44
57
|
|
|
@@ -47,20 +60,110 @@ pnpm add -g forgemap
|
|
|
47
60
|
cd ~/projects
|
|
48
61
|
forgemap config init
|
|
49
62
|
|
|
50
|
-
# 2.
|
|
63
|
+
# 2. Wire up the shell integration once β real `forgemap cd` + tab-completion.
|
|
64
|
+
forgemap shell-init --install # appends loaders to ~/.zshrc (or bashrc/fish)
|
|
65
|
+
source ~/.zshrc # re-source once, then it's automatic
|
|
66
|
+
# Prefer manual? eval "$(forgemap shell-init)" Β· fish: forgemap shell-init fish | source
|
|
67
|
+
|
|
68
|
+
# 3. Clone β any slug form works.
|
|
51
69
|
forgemap clone kirchDev/laravel-pbac
|
|
52
70
|
forgemap clone github:TitusKirch/forgemap
|
|
53
71
|
forgemap clone https://github.com/foo/bar
|
|
54
72
|
|
|
55
|
-
#
|
|
56
|
-
|
|
73
|
+
# 4. Jump into a repo from anywhere.
|
|
74
|
+
forgemap cd kirchDev/laravel-pbac # exact slug β direct cd
|
|
75
|
+
forgemap cd laravel # fuzzy single match β direct cd
|
|
76
|
+
forgemap cd kirch # multiple matches β interactive picker
|
|
77
|
+
forgemap cd # no arg β picker over every clone
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`forgemap cd` resolves the slug, walks/picks across your cloned repos,
|
|
81
|
+
and actually changes directory because the shell wrapper from
|
|
82
|
+
`shell-init` intercepts it before the binary runs. Every other
|
|
83
|
+
subcommand falls through to the real binary unchanged.
|
|
84
|
+
|
|
85
|
+
### Search and pick on demand
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
forgemap search forgemap # pretty tree (one line per match)
|
|
89
|
+
forgemap search forgemap | fzf # pipe-friendly path output
|
|
90
|
+
forgemap pick # interactive picker (consola prompt)
|
|
91
|
+
forgemap pick kirch # picker pre-filtered by fuzzy query
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Open the folder in the OS file manager
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
forgemap open kirchDev/laravel-pbac
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
- **WSL** β launches `explorer.exe` against `\\wsl$\<distro>\β¦`, Explorer opens the folder
|
|
101
|
+
- **macOS** β `open <path>` (Finder)
|
|
102
|
+
- **Linux** β `xdg-open <path>`
|
|
103
|
+
|
|
104
|
+
### Mass operations across every clone
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
forgemap sync # git fetch --all --prune, 4 in parallel
|
|
108
|
+
forgemap sync --pull # git pull --ff-only (skips dirty trees)
|
|
109
|
+
forgemap sync --forge work --query api # restrict scope
|
|
110
|
+
|
|
111
|
+
forgemap status # tree: branch / dirty / aheadβ / behindβ / last commit
|
|
112
|
+
forgemap status --format json # structured for jq + scripts
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
All tree output (`status`, `search`, `import`) groups as `forge β owner β repo`. Network operations (`sync`, `import`, `cleanup`) run with a hard timeout and non-interactive SSH, so an unreachable host can never wedge a run.
|
|
116
|
+
|
|
117
|
+
### Adopt an existing layout β `import`
|
|
118
|
+
|
|
119
|
+
Already have a folder full of repos laid out as `<server>/<owner>/<repo>`? Adopt it without re-cloning:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
forgemap import ~/projects # reconcile + derive/write forgemap.config.ts
|
|
123
|
+
forgemap import ~/projects --no-remote-check # offline: folder-vs-origin only (instant)
|
|
124
|
+
forgemap import ~/projects --fix # move folders / fix origin URLs to match the remote
|
|
125
|
+
forgemap import ~/projects --no-write-config # only report, don't touch the config
|
|
126
|
+
forgemap import ~/projects --format json
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
For each repo `import` compares the folder's `<owner>/<repo>` against the git `origin`, checks whether the remote still exists or was moved/renamed (GitHub via a batched `gh` GraphQL query, other forges via `git ls-remote`), and derives `root` + one forge per server directory. Read-only by default β `--fix` is the only thing that touches the filesystem.
|
|
130
|
+
|
|
131
|
+
### Reclaim disk β `cleanup`
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
forgemap cleanup # list deletable clones, then type "yes" to confirm
|
|
135
|
+
forgemap cleanup --dry-run # show candidates + why every other idle repo is kept
|
|
136
|
+
forgemap cleanup --days 540 # idle threshold in days (default 365)
|
|
137
|
+
forgemap cleanup --include-dirty --include-unpushed # also delete repos with local-only work (lost!)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
A repo is only deleted when it is idle for `--days`+ days (by last **local** commit), has a clean working tree, has nothing unpushed, **and** its remote still exists β so everything removed is provably backed up. Repos without a remote (or with a gone/unreachable one) are never touched; empty owner directories left behind are pruned automatically. Deletion needs an explicit typed `yes` (or `--yes`).
|
|
141
|
+
|
|
142
|
+
### Preflight your config
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
forgemap validate # pretty checklist with β / ! / β per check
|
|
146
|
+
forgemap validate --json | jq # machine-readable for pre-commit hooks
|
|
57
147
|
```
|
|
58
148
|
|
|
59
|
-
|
|
149
|
+
Validates the schema, required CLI tools (`git` always, `gh` when a `type: 'github'` forge is configured), `gh auth status`, and that the configured root exists.
|
|
150
|
+
|
|
151
|
+
### Shell integration & completion
|
|
60
152
|
|
|
61
153
|
```bash
|
|
62
|
-
|
|
63
|
-
|
|
154
|
+
forgemap shell-init --install # cd wrapper + completion β your rc file (idempotent)
|
|
155
|
+
forgemap completion --install # completion only, if you don't want the cd wrapper
|
|
156
|
+
forgemap shell-init # print the wrapper (manual: eval "$(β¦)")
|
|
157
|
+
forgemap completion bash # print the completion script for bash/zsh/fish
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
`--install` appends a marker-guarded block to the right rc file (`~/.zshrc`, `~/.bashrc`, or `~/.config/fish/config.fish`) β re-source it once and you're done. Tab-completion suggests every subcommand, and slugs for the commands that take one (`cd`, `clone`, `open`, β¦).
|
|
161
|
+
|
|
162
|
+
### Inspect the config
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
forgemap config init # write a starter forgemap.config.ts
|
|
166
|
+
forgemap config show # print the resolved config + which file it came from
|
|
64
167
|
```
|
|
65
168
|
|
|
66
169
|
## βοΈ Configuration
|
|
@@ -75,26 +178,33 @@ export default defineForgeMapConfig({
|
|
|
75
178
|
defaultForge: 'github',
|
|
76
179
|
forges: {
|
|
77
180
|
github: {
|
|
78
|
-
type: 'github',
|
|
181
|
+
type: 'github', // uses `gh repo clone`
|
|
79
182
|
host: 'github.com',
|
|
80
183
|
dir: 'comGithub'
|
|
81
184
|
},
|
|
82
185
|
work: {
|
|
83
|
-
type: '
|
|
186
|
+
type: 'git', // plain `git clone` β no gh needed
|
|
84
187
|
host: 'gitlab.acme.com',
|
|
85
|
-
dir: 'comGitlabAcme'
|
|
188
|
+
dir: 'comGitlabAcme',
|
|
189
|
+
protocol: 'ssh' // optional, ssh is the default
|
|
86
190
|
}
|
|
87
191
|
}
|
|
88
192
|
});
|
|
89
193
|
```
|
|
90
194
|
|
|
91
|
-
| Key
|
|
92
|
-
|
|
|
93
|
-
| `root`
|
|
94
|
-
| `defaultForge`
|
|
95
|
-
| `forges.<name
|
|
195
|
+
| Key | What it controls |
|
|
196
|
+
| :------------------- | :-------------------------------------------------------------------------------------------------------- |
|
|
197
|
+
| `root` | Base directory for all clones. Relative paths resolve against the config file's directory. |
|
|
198
|
+
| `defaultForge` | Forge alias used when a slug is just `owner/repo` (no host or forge prefix). |
|
|
199
|
+
| `forges.<name>.type` | `'github'` (shells out to `gh`) or `'git'` (plain `git clone`). `gitlab` / `gitea` / `codeberg` reserved. |
|
|
200
|
+
| `forges.<name>.host` | Hostname used to map full URLs and (for `git`) build the clone URL. |
|
|
201
|
+
| `forges.<name>.dir` | Subdirectory under `root` where this forge's clones live. |
|
|
202
|
+
| `forges.<name>.protocol` | `git`-type only. `'ssh'` (default) or `'https'`. Override per call with `--ssh` / `--https`. |
|
|
96
203
|
|
|
97
|
-
The config file is discovered by walking up from your current directory. Override with `--config <path>` or the `FORGEMAP_CONFIG` env var.
|
|
204
|
+
The config file is discovered by walking **up** from your current directory (so `forgemap cd` works from inside any clone, not just the root), then falling back to a global `$XDG_CONFIG_HOME/forgemap/forgemap.config.*` (i.e. `~/.config/forgemap/`) so commands work from anywhere. Override with `--config <path>` or the `FORGEMAP_CONFIG` env var.
|
|
205
|
+
|
|
206
|
+
> [!TIP]
|
|
207
|
+
> Already have a directory full of repos? Skip writing this by hand β `forgemap import <path>` derives `root` + `forges` from the existing layout.
|
|
98
208
|
|
|
99
209
|
## ποΈ Layout
|
|
100
210
|
|
|
@@ -134,8 +244,11 @@ pnpm install
|
|
|
134
244
|
pnpm test # vitest
|
|
135
245
|
pnpm typecheck # tsc --noEmit
|
|
136
246
|
pnpm check # lint + format
|
|
247
|
+
pnpm bench # microbench scanRepos / cache hit / cache rebuild
|
|
137
248
|
```
|
|
138
249
|
|
|
250
|
+
Tune the bench layout via env vars (`FORGEMAP_BENCH_FORGES`, `FORGEMAP_BENCH_OWNERS`, `FORGEMAP_BENCH_REPOS`, `FORGEMAP_BENCH_RUNS`).
|
|
251
|
+
|
|
139
252
|
## π€ Contributing
|
|
140
253
|
|
|
141
254
|
PRs welcome. Conventional Commits required (enforced via commitlint). Husky runs lint-staged on every commit.
|