forgemap 0.4.1 β†’ 0.5.0-dev-main.91-6fe192c

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
@@ -7,10 +7,11 @@
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)
11
10
  [![Node Version](https://img.shields.io/node/v/forgemap.svg?style=flat-square&color=8993be)](https://www.npmjs.com/package/forgemap)
12
11
  [![License: MIT](https://img.shields.io/npm/l/forgemap.svg?style=flat-square&color=10b981)](LICENSE)
13
12
 
13
+ ![forgemap demo](.github/assets/demo.gif)
14
+
14
15
  </div>
15
16
 
16
17
  ---
@@ -26,67 +27,67 @@ That's it. Every repo lands at a predictable `<root>/<forge.dir>/<owner>/<repo>`
26
27
 
27
28
  - **πŸ—‚οΈ Predictable layout** β€” every clone goes to `<root>/<forge.dir>/<owner>/<repo>`, configured once.
28
29
  - **πŸšͺ Flexible slug syntax** β€” `owner/repo`, `forge:owner/repo`, full HTTPS URLs, or SSH (`git@…:…`).
29
- - **πŸ” Fuzzy search** β€” `forgemap search <term>` finds local repos by owner or repo name (powered by [Fuse.js](https://www.fusejs.io/)).
30
+ - **πŸ” List & fuzzy search** β€” `forgemap list` shows every local repo, `forgemap list <term>` filters by owner or repo name (powered by [Fuse.js](https://www.fusejs.io/)); `cd`, `path` and `open` take the same fuzzy terms.
30
31
  - **πŸ€– 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
+ - **πŸ” Mass sync + status** β€” `forgemap sync` fetches every clone in parallel, `forgemap status` shows branch / dirty / ahead / behind per repo β€” narrow either to given owners or forges with a repeatable `--filter`.
32
33
  - **πŸ“₯ 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
+ - **🧹 Safe cleanup** β€” `forgemap cleanup` deletes long-idle clones, `forgemap delete <slug>` drops a single one β€” both only when it is clean, fully pushed, free of stashed work, and still on its remote, so nothing unbacked-up is ever lost.
34
35
  - **πŸ›‘οΈ Preflight validate** β€” `forgemap validate` checks the config schema and required CLIs before you discover a problem mid-clone.
35
36
  - **🧰 Typed config** β€” `forgemap.config.ts` with `defineForgeMapConfig()`, parent walk-up discovery, and a global fallback.
36
37
  - **πŸš€ Shell-friendly** β€” `forgemap shell-init --install` wires up real `forgemap cd <slug>` **and** tab-completion in one step.
37
38
 
38
- ## πŸ“¦ Installation
39
+ ## πŸ“¦ Install & run
40
+
41
+ > [!IMPORTANT]
42
+ > Needs **Node 24+** and **`git`** on `PATH`. [`gh`](https://cli.github.com/) (GitHub CLI) is only required when a `type: 'github'` forge is configured β€” run `forgemap validate` for an exact rundown of what your config needs.
39
43
 
40
44
  ```bash
41
- npm install -g forgemap
42
- # or
43
- pnpm add -g forgemap
44
- ```
45
+ npm install -g forgemap # or: pnpm add -g forgemap
45
46
 
46
- **Requirements**
47
+ cd ~/projects # the directory that should hold all your repos
48
+ forgemap config init # write a starter forgemap.config.ts
49
+ forgemap shell-init --install # cd wrapper + completion β†’ your rc file (idempotent)
50
+ source ~/.zshrc # re-source once, then it's automatic
47
51
 
48
- - Node 24+
49
- - `git` on `PATH`
50
- - [`gh`](https://cli.github.com/) (GitHub CLI) β€” only when a `type: 'github'` forge is configured
52
+ forgemap clone kirchDev/laravel-pbac # any slug form works: owner/repo, forge:owner/repo, URL, SSH
53
+ forgemap cd laravel # fuzzy match β†’ jump in; bare `forgemap cd` opens a picker
54
+ ```
51
55
 
52
- Run `forgemap validate` after setup for an exact rundown of what's needed for your config.
56
+ `forgemap cd` resolves the slug, walks/picks across your cloned repos, and actually changes directory because the shell wrapper from `shell-init` intercepts it before the binary runs. Every other subcommand falls through to the real binary unchanged. 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.
53
57
 
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.
58
+ <details>
59
+ <summary><strong>All commands</strong> β€” clone, cd, path, list, pick, open, sync/status, import, cleanup, delete, validate, shell-init, config</summary>
55
60
 
56
- ## πŸš€ Quick start
61
+ ### Clone & jump
57
62
 
58
63
  ```bash
59
- # 1. Pick a directory that should hold all your repos and drop a config there.
60
- cd ~/projects
61
- forgemap config init
62
-
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.
69
- forgemap clone kirchDev/laravel-pbac
64
+ forgemap clone kirchDev/laravel-pbac # default forge
70
65
  forgemap clone github:TitusKirch/forgemap
71
66
  forgemap clone https://github.com/foo/bar
72
67
 
73
- # 4. Jump into a repo from anywhere.
74
68
  forgemap cd kirchDev/laravel-pbac # exact slug β†’ direct cd
75
69
  forgemap cd laravel # fuzzy single match β†’ direct cd
76
70
  forgemap cd kirch # multiple matches β†’ interactive picker
77
71
  forgemap cd # no arg β†’ picker over every clone
78
72
  ```
79
73
 
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.
74
+ ### Print a path β€” `path`
84
75
 
85
- ### Search and pick on demand
76
+ ```bash
77
+ forgemap path kirchDev/laravel-pbac # β†’ ~/projects/comGithub/kirchDev/laravel-pbac
78
+ forgemap path laravel # fuzzy single match β†’ same path
79
+ cd "$(forgemap path laravel)" # the manual form of `forgemap cd`
80
+ code "$(forgemap path forgemap)" # feed any tool that takes a directory
81
+ ```
82
+
83
+ Prints where a repo lives β€” or *would* live, if it isn't cloned yet, which makes it useful for scripting a clone target. An exact `owner/repo` never touches the disk, so a strict slug always wins over a fuzzy match; ambiguous fuzzy terms error with the candidate list rather than guessing.
84
+
85
+ ### List, search and pick on demand
86
86
 
87
87
  ```bash
88
- forgemap search forgemap # pretty tree (one line per match)
89
- forgemap search forgemap | fzf # pipe-friendly path output
88
+ forgemap list # every repo as a pretty tree
89
+ forgemap list forgemap # pretty tree (one line per match)
90
+ forgemap list forgemap | fzf # pipe-friendly path output
90
91
  forgemap pick # interactive picker (consola prompt)
91
92
  forgemap pick kirch # picker pre-filtered by fuzzy query
92
93
  ```
@@ -94,7 +95,8 @@ forgemap pick kirch # picker pre-filtered by fuzzy query
94
95
  ### Open the folder in the OS file manager
95
96
 
96
97
  ```bash
97
- forgemap open kirchDev/laravel-pbac
98
+ forgemap open kirchDev/laravel-pbac # exact slug
99
+ forgemap open laravel # fuzzy single match β†’ same folder
98
100
  ```
99
101
 
100
102
  - **WSL** β†’ launches `explorer.exe` against `\\wsl$\<distro>\…`, Explorer opens the folder
@@ -110,9 +112,18 @@ forgemap sync --forge work --query api # restrict scope
110
112
 
111
113
  forgemap status # tree: branch / dirty / ahead↑ / behind↓ / last commit
112
114
  forgemap status --format json # structured for jq + scripts
115
+
116
+ # --filter keeps only matching owners/forges. Repeatable, OR-combined.
117
+ forgemap status --format json --filter kirchDev --filter TitusKirch
118
+
119
+ forgemap status --no-cache # rescan the disk instead of using the cached tree
113
120
  ```
114
121
 
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.
122
+ `--filter` works on `status`, `sync` and `list`. It matches an **owner** or a **forge name** exactly (case-insensitive) β€” unlike `--query`, which is fuzzy.
123
+
124
+ `status`, `sync` and `cleanup` read a cached repo tree so repeated runs stay fast. Pass `--no-cache` to skip it and walk the disk again β€” the cache refreshes on its own, so you only need this right after cloning or moving repos by hand.
125
+
126
+ All tree output (`status`, `list`, `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
127
 
117
128
  ### Adopt an existing layout β€” `import`
118
129
 
@@ -134,10 +145,22 @@ For each repo `import` compares the folder's `<owner>/<repo>` against the git `o
134
145
  forgemap cleanup # list deletable clones, then type "yes" to confirm
135
146
  forgemap cleanup --dry-run # show candidates + why every other idle repo is kept
136
147
  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!)
148
+ forgemap cleanup --include-dirty --include-unpushed --include-stashed # also delete repos with local-only work (lost!)
149
+ ```
150
+
151
+ A repo is only deleted when it is idle for `--days`+ days (by last **local** commit), has a clean working tree, has nothing unpushed, has no stashed work, **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`).
152
+
153
+ ### Drop one repo β€” `delete`
154
+
155
+ ```bash
156
+ forgemap delete kirchDev/laravel-pbac # gates, then type "yes" to confirm
157
+ forgemap delete github:foo/bar # forge-qualified slug or full URL
158
+ forgemap delete foo/bar --dry-run # report the gates; never prompt or delete
159
+ forgemap delete foo/bar --yes # non-interactive (scripts)
160
+ forgemap delete foo/bar --include-dirty --include-unpushed --include-stashed # delete local-only work too (lost!)
138
161
  ```
139
162
 
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`).
163
+ The targeted counterpart to `cleanup`: same safety gates, no staleness requirement β€” for the repo you are done with *today*. It runs the identical checks (clean tree, nothing unpushed, no stashed work, remote still exists) and prints the local-only work at stake, naming the branches that carry unpushed commits and the stash count rather than just saying "unpushed". A gone or unreachable remote is a **hard stop that no flag overrides** β€” that local copy may be the only one left. After deleting, the repo is evicted from the scan cache and emptied owner directories are pruned.
141
164
 
142
165
  ### Preflight your config
143
166
 
@@ -154,6 +177,7 @@ Validates the schema, required CLI tools (`git` always, `gh` when a `type: 'gith
154
177
  forgemap shell-init --install # cd wrapper + completion β†’ your rc file (idempotent)
155
178
  forgemap completion --install # completion only, if you don't want the cd wrapper
156
179
  forgemap shell-init # print the wrapper (manual: eval "$(…)")
180
+ forgemap shell-init fish | source # fish: source the wrapper directly
157
181
  forgemap completion bash # print the completion script for bash/zsh/fish
158
182
  ```
159
183
 
@@ -166,6 +190,8 @@ forgemap config init # write a starter forgemap.config.ts
166
190
  forgemap config show # print the resolved config + which file it came from
167
191
  ```
168
192
 
193
+ </details>
194
+
169
195
  ## βš™οΈ Configuration
170
196
 
171
197
  `forgemap config init` writes a `forgemap.config.ts` like this:
@@ -192,6 +218,14 @@ export default defineForgeMapConfig({
192
218
  });
193
219
  ```
194
220
 
221
+ The config is discovered by walking **up** from your current directory (so `forgemap cd` works from inside any clone), then falling back to `~/.config/forgemap/`. Override with `--config <path>` or the `FORGEMAP_CONFIG` env var.
222
+
223
+ > [!TIP]
224
+ > Already have a directory full of repos? Skip writing this by hand β€” `forgemap import <path>` derives `root` + `forges` from the existing layout.
225
+
226
+ <details>
227
+ <summary><strong>All configuration options</strong></summary>
228
+
195
229
  | Key | What it controls |
196
230
  | :------------------- | :-------------------------------------------------------------------------------------------------------- |
197
231
  | `root` | Base directory for all clones. Relative paths resolve against the config file's directory. |
@@ -203,10 +237,10 @@ export default defineForgeMapConfig({
203
237
 
204
238
  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
239
 
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.
240
+ </details>
208
241
 
209
- ## πŸ—‚οΈ Layout
242
+ <details>
243
+ <summary><strong>Repo layout &amp; slug syntax</strong></summary>
210
244
 
211
245
  ```
212
246
  <root>/
@@ -227,8 +261,6 @@ Example with the default config rooted at `~/projects`:
227
261
  └── forgemap/
228
262
  ```
229
263
 
230
- ## πŸšͺ Slug syntax
231
-
232
264
  | Form | Resolves to |
233
265
  | :---------------------------------- | :----------------------------------------------------- |
234
266
  | `kirchDev/laravel-pbac` | Default forge, `kirchDev/laravel-pbac`. |
@@ -237,7 +269,14 @@ Example with the default config rooted at `~/projects`:
237
269
  | `https://github.com/foo/bar.git` | Same, `.git` suffix stripped. |
238
270
  | `git@github.com:foo/bar.git` | SSH form, host matched against `forges[].host`. |
239
271
 
240
- ## πŸ§ͺ Testing
272
+ </details>
273
+
274
+ ## 🀝 Contributing
275
+
276
+ PRs welcome. Conventional Commits required (enforced via commitlint); Husky runs lint-staged on every commit. Run `pnpm check:fix` before pushing β€” CI will catch what husky missed.
277
+
278
+ <details>
279
+ <summary><strong>Dev scripts</strong></summary>
241
280
 
242
281
  ```bash
243
282
  pnpm install
@@ -249,12 +288,7 @@ pnpm bench # microbench scanRepos / cache hit / cache rebuild
249
288
 
250
289
  Tune the bench layout via env vars (`FORGEMAP_BENCH_FORGES`, `FORGEMAP_BENCH_OWNERS`, `FORGEMAP_BENCH_REPOS`, `FORGEMAP_BENCH_RUNS`).
251
290
 
252
- ## 🀝 Contributing
253
-
254
- PRs welcome. Conventional Commits required (enforced via commitlint). Husky runs lint-staged on every commit.
255
-
256
- > [!TIP]
257
- > Run `pnpm check:fix` before pushing β€” CI will catch what husky missed.
291
+ </details>
258
292
 
259
293
  ## πŸ›£οΈ Versioning
260
294