forgemap 0.1.0 β†’ 0.4.0-dev-main.43-1758b5e

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 CHANGED
@@ -1,12 +1,13 @@
1
1
  <div align="center">
2
2
 
3
- # 🧰 forgemap
3
+ # πŸ—ΊοΈ forgemap
4
4
 
5
5
  **One consistent local layout for every repo you clone β€” across every forge**
6
6
 
7
7
  [![npm Version](https://img.shields.io/npm/v/forgemap.svg?style=flat-square&color=4f46e5)](https://www.npmjs.com/package/forgemap)
8
8
  [![Downloads](https://img.shields.io/npm/dm/forgemap.svg?style=flat-square&color=4f46e5)](https://www.npmjs.com/package/forgemap)
9
9
  [![Tests](https://img.shields.io/github/actions/workflow/status/TitusKirch/forgemap/ci.yml?branch=main&style=flat-square&label=tests)](https://github.com/TitusKirch/forgemap/actions/workflows/ci.yml)
10
+ [![Coverage](https://img.shields.io/codecov/c/github/TitusKirch/forgemap?style=flat-square&color=10b981)](https://codecov.io/gh/TitusKirch/forgemap)
10
11
  [![Node Version](https://img.shields.io/node/v/forgemap.svg?style=flat-square&color=8993be)](https://www.npmjs.com/package/forgemap)
11
12
  [![License: MIT](https://img.shields.io/npm/l/forgemap.svg?style=flat-square&color=10b981)](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 path <slug>` gives you that path back for `cd "$(forgemap path …)"` from anywhere.
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
- - **πŸ€– Forge-aware** β€” uses `gh` for GitHub today; GitLab / Gitea / Codeberg adapters planned.
29
- - **🧰 Typed config** β€” `forgemap.config.ts` with `defineForgeMapConfig()` and walk-up discovery.
30
- - **πŸš€ Shell-friendly** β€” `forgemap path <slug>` is a pure resolver, perfect for `cd "$(…)"` aliases.
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
- > [!IMPORTANT]
41
- > `forgemap clone` shells out to the [GitHub CLI](https://cli.github.com/) (`gh`). Install it once and run `gh auth login` so cloning works against private repos.
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. Clone β€” any slug form works.
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
- # 3. Jump into a repo from anywhere.
56
- cd "$(forgemap path kirchDev/laravel-pbac)"
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
- Add a shell alias to make the jump even shorter:
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
- fcd() { cd "$(forgemap path "$1")"; }
63
- fcd kirchDev/laravel-pbac
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: 'gitlab',
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 | What it controls |
92
- | :------------- | :---------------------------------------------------------------------------------------------- |
93
- | `root` | Base directory for all clones. Relative paths resolve against the config file's directory. |
94
- | `defaultForge` | Forge alias used when a slug is just `owner/repo` (no host or forge prefix). |
95
- | `forges.<name>` | Map of forge aliases. Each entry has `type`, `host`, and `dir` (subdirectory under `root`). |
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.