forgemap 0.4.1-dev.75-4776601 โ†’ 0.4.1-dev.76-3afc526

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
@@ -27,11 +27,11 @@ That's it. Every repo lands at a predictable `<root>/<forge.dir>/<owner>/<repo>`
27
27
 
28
28
  - **๐Ÿ—‚๏ธ Predictable layout** โ€” every clone goes to `<root>/<forge.dir>/<owner>/<repo>`, configured once.
29
29
  - **๐Ÿšช Flexible slug syntax** โ€” `owner/repo`, `forge:owner/repo`, full HTTPS URLs, or SSH (`git@โ€ฆ:โ€ฆ`).
30
- - **๐Ÿ” Fuzzy search** โ€” `forgemap search <term>` finds local repos by owner or repo name (powered by [Fuse.js](https://www.fusejs.io/)).
30
+ - **๐Ÿ” Fuzzy search** โ€” `forgemap search <term>` finds local repos by owner or repo name (powered by [Fuse.js](https://www.fusejs.io/)); `cd`, `path` and `open` take the same fuzzy terms.
31
31
  - **๐Ÿค– Forge-aware** โ€” `type: 'github'` shells out to `gh`; `type: 'git'` uses plain `git clone` with no extra dependencies.
32
- - **๐Ÿ” 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`.
33
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.
34
- - **๐Ÿงน 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.
35
35
  - **๐Ÿ›ก๏ธ Preflight validate** โ€” `forgemap validate` checks the config schema and required CLIs before you discover a problem mid-clone.
36
36
  - **๐Ÿงฐ Typed config** โ€” `forgemap.config.ts` with `defineForgeMapConfig()`, parent walk-up discovery, and a global fallback.
37
37
  - **๐Ÿš€ Shell-friendly** โ€” `forgemap shell-init --install` wires up real `forgemap cd <slug>` **and** tab-completion in one step.
@@ -56,7 +56,7 @@ forgemap cd laravel # fuzzy match โ†’ jump in; bare `forgem
56
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.
57
57
 
58
58
  <details>
59
- <summary><strong>All commands</strong> โ€” clone, cd, search, open, sync/status, import, cleanup, delete, validate, shell-init, config</summary>
59
+ <summary><strong>All commands</strong> โ€” clone, cd, path, search, pick, open, sync/status, import, cleanup, delete, validate, shell-init, config</summary>
60
60
 
61
61
  ### Clone & jump
62
62
 
@@ -71,6 +71,17 @@ forgemap cd kirch # multiple matches โ†’ interactive pick
71
71
  forgemap cd # no arg โ†’ picker over every clone
72
72
  ```
73
73
 
74
+ ### Print a path โ€” `path`
75
+
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
+
74
85
  ### Search and pick on demand
75
86
 
76
87
  ```bash
@@ -103,10 +114,14 @@ forgemap status --format json # structured for jq + scripts
103
114
 
104
115
  # --filter keeps only matching owners/forges. Repeatable, OR-combined.
105
116
  forgemap status --format json --filter kirchDev --filter TitusKirch
117
+
118
+ forgemap status --no-cache # rescan the disk instead of using the cached tree
106
119
  ```
107
120
 
108
121
  `--filter` works on `status`, `sync` and `search`. It matches an **owner** or a **forge name** exactly (case-insensitive) โ€” unlike `--query`, which is fuzzy.
109
122
 
123
+ `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.
124
+
110
125
  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.
111
126
 
112
127
  ### Adopt an existing layout โ€” `import`
@@ -949,10 +949,11 @@ const cleanupCommand = defineCommand({
949
949
  description: "Also delete repos with stashed work (that stash is lost)",
950
950
  default: false
951
951
  },
952
- "no-cache": {
952
+ cache: {
953
953
  type: "boolean",
954
- description: "Skip the scanned-repos cache",
955
- default: false
954
+ description: "Use the scanned-repos cache",
955
+ negativeDescription: "Skip the scanned-repos cache",
956
+ default: true
956
957
  },
957
958
  config: {
958
959
  type: "string",
@@ -971,7 +972,7 @@ const cleanupCommand = defineCommand({
971
972
  let repos = await scanReposCached({
972
973
  config: loaded.config,
973
974
  configDir,
974
- useCache: !args["no-cache"]
975
+ useCache: args.cache
975
976
  });
976
977
  if (args.forge) repos = repos.filter((r) => r.forgeName === args.forge);
977
978
  const cutoffUnix = Math.floor(Date.now() / 1e3) - days * DAY_SECONDS;
@@ -2809,10 +2810,11 @@ const statusCommand = defineCommand({
2809
2810
  type: "string",
2810
2811
  description: "Fuzzy filter against <owner>/<repo>"
2811
2812
  },
2812
- "no-cache": {
2813
+ cache: {
2813
2814
  type: "boolean",
2814
- description: "Skip the scanned-repos cache",
2815
- default: false
2815
+ description: "Use the scanned-repos cache",
2816
+ negativeDescription: "Skip the scanned-repos cache",
2817
+ default: true
2816
2818
  },
2817
2819
  config: {
2818
2820
  type: "string",
@@ -2832,7 +2834,7 @@ const statusCommand = defineCommand({
2832
2834
  let repos = await scanReposCached({
2833
2835
  config: loaded.config,
2834
2836
  configDir,
2835
- useCache: !args["no-cache"]
2837
+ useCache: args.cache
2836
2838
  });
2837
2839
  if (args.forge) {
2838
2840
  repos = repos.filter((r) => r.forgeName === args.forge);
@@ -2924,10 +2926,11 @@ const syncCommand = defineCommand({
2924
2926
  type: "string",
2925
2927
  description: "Fuzzy filter against <owner>/<repo>"
2926
2928
  },
2927
- "no-cache": {
2929
+ cache: {
2928
2930
  type: "boolean",
2929
- description: "Skip the scanned-repos cache",
2930
- default: false
2931
+ description: "Use the scanned-repos cache",
2932
+ negativeDescription: "Skip the scanned-repos cache",
2933
+ default: true
2931
2934
  },
2932
2935
  config: {
2933
2936
  type: "string",
@@ -2940,7 +2943,7 @@ const syncCommand = defineCommand({
2940
2943
  let repos = await scanReposCached({
2941
2944
  config: loaded.config,
2942
2945
  configDir,
2943
- useCache: !args["no-cache"]
2946
+ useCache: args.cache
2944
2947
  });
2945
2948
  if (args.forge) {
2946
2949
  repos = repos.filter((r) => r.forgeName === args.forge);