@ajaykumarnpm/talea 0.6.0 → 0.7.0

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/CHANGELOG.md CHANGED
@@ -4,6 +4,11 @@ All notable changes to this project are recorded here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the versions follow
5
5
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.7.0] - 2026-09-22
8
+
9
+ ### Added
10
+ - a bare repo name narrows sync, clone, status, list and tree
11
+
7
12
  ## [0.6.0] - 2026-09-22
8
13
 
9
14
  ### Breaking
package/README.md CHANGED
@@ -180,7 +180,9 @@ Treat the id like a bookmark you would not paste into a public channel.
180
180
  | `talea upgrade` | update the CLI itself (also `talea update`) |
181
181
 
182
182
  Every one of them takes `-g <group>` and `-r <repo>` to narrow the run, and
183
- `--help` for its own examples.
183
+ `--help` for its own examples. For `sync`, `clone`, `status`, `list` and `tree`
184
+ a bare name means the same as `-r`, so `talea sync eklavya` syncs that one repo.
185
+ A command that takes no names refuses a stray word instead of ignoring it.
184
186
 
185
187
  ---
186
188
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ajaykumarnpm/talea",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "One folder structure for every machine. Clone, adopt and sync your GitHub repos from a manifest you own.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74,7 +74,7 @@ skipped, and saying so up front is better than reporting it afterwards.
74
74
  talea sync # clone what is missing, fast-forward what is there
75
75
  talea clone # clone only — never fetches or merges
76
76
  talea sync -g NonStop # one group
77
- talea sync -r eklavya # one repo
77
+ talea sync eklavya # one repo — same as -r eklavya
78
78
  ```
79
79
 
80
80
  `sync` is safe to run unattended. It fast-forwards **the branch you are on** and
@@ -162,8 +162,11 @@ cloned — `talea init` or `talea select` after it is what fills the tree.
162
162
  ## Narrowing any run
163
163
 
164
164
  Every command takes `-g <group>` and `-r <repo>`, both repeatable, and `--help`
165
- for its own examples. An unknown group or repo name **exits non-zero** rather
166
- than quietly doing nothing, so a typo is loud.
165
+ for its own examples. For `sync`, `clone`, `status`, `list` and `tree` a bare
166
+ name is the same as `-r`. `adopt` is the exception: it refuses a bare name,
167
+ because `-r` there lifts the name-only guard and must be typed on purpose. An
168
+ unknown group or repo name **exits non-zero** rather than quietly doing nothing,
169
+ so a typo is loud.
167
170
 
168
171
  ## Rules
169
172
 
package/src/cli.js CHANGED
@@ -66,6 +66,24 @@ const ALIASES = {
66
66
  'self-update': 'upgrade',
67
67
  };
68
68
 
69
+ // Bare words after these commands are repo names: `talea sync PiDom` is
70
+ // `talea sync -r PiDom`. Dropping them instead ran the command over every repo
71
+ // on the machine, which is a typo guard failing in the worst direction.
72
+ const TAKES_REPOS = new Set(['sync', 'clone', 'status', 'list', 'tree']);
73
+
74
+ // These read their own positionals. Everything else takes none, and a stray
75
+ // word stops the run. `adopt` is left out on purpose: an explicit -r there lifts
76
+ // the name-only guard, and a bare word must not do that by accident.
77
+ const TAKES_WORDS = new Set(['init', 'select', 'add', 'rm', 'manifest', 'exec', 'skill', 'where']);
78
+
79
+ /** Fold a command's bare words into -r, pass them through, or refuse them. */
80
+ export function routeWords(key, words, repo) {
81
+ if (!words.length || TAKES_WORDS.has(key)) return { repo, words };
82
+ if (TAKES_REPOS.has(key)) return { repo: [...(repo ?? []), ...words], words: [] };
83
+ const hint = key === 'adopt' ? `\n To name a repo: talea adopt -r ${words.join(',')}` : '';
84
+ return { error: `\`${key}\` takes no arguments, got ${words.map((w) => `"${w}"`).join(' ')}.${hint}` };
85
+ }
86
+
69
87
  const OPTIONS = {
70
88
  group: { type: 'string', short: 'g', multiple: true },
71
89
  repo: { type: 'string', short: 'r', multiple: true },
@@ -203,6 +221,12 @@ export async function main(argv) {
203
221
  }
204
222
  }
205
223
 
224
+ const routed = routeWords(key, rest, values.repo?.length ? values.repo : undefined);
225
+ if (routed.error) {
226
+ fail(routed.error);
227
+ process.exit(1);
228
+ }
229
+
206
230
  const opts = {
207
231
  ...values,
208
232
  jobs,
@@ -216,10 +240,10 @@ export async function main(argv) {
216
240
  // selectRepos to flatten, but normalise "not passed" to undefined.
217
241
  group: values.group?.length ? values.group : undefined,
218
242
  from: values.from?.length ? values.from : undefined,
219
- repo: values.repo?.length ? values.repo : undefined,
243
+ repo: routed.repo,
220
244
  };
221
245
 
222
- await command.run(opts, key === 'exec' ? tail : rest);
246
+ await command.run(opts, key === 'exec' ? tail : routed.words);
223
247
 
224
248
  // After the real work, never before it, and never able to fail it.
225
249
  if (key !== 'upgrade') {
@@ -20,7 +20,7 @@ ${c.bold('talea clone')} — clone what is missing, and nothing else
20
20
 
21
21
  Options
22
22
  -g, --group <names> comma-separated groups
23
- -r, --repo <names> comma-separated repo names
23
+ -r, --repo <names> comma-separated repo names; a bare name works too
24
24
  --pick choose what this machine keeps before cloning
25
25
  --protocol <p> ssh (default) or https
26
26
  --from <path> also search here for existing checkouts (repeatable)
@@ -15,7 +15,7 @@ the catalogue's opinion — what a brand new machine would start with.
15
15
 
16
16
  Options
17
17
  -g, --group <names> comma-separated groups
18
- -r, --repo <names> comma-separated repo names
18
+ -r, --repo <names> comma-separated repo names; a bare name works too
19
19
  --all include archived and quiet repos (default: hidden)
20
20
  --groups show groups only
21
21
  --json emit JSON
@@ -22,7 +22,7 @@ Columns
22
22
 
23
23
  Options
24
24
  -g, --group <names> comma-separated groups
25
- -r, --repo <names> comma-separated repo names
25
+ -r, --repo <names> comma-separated repo names; a bare name works too
26
26
  --drift only repos on some other branch
27
27
  --missing only repos not cloned yet
28
28
  --all ignore this machine's selection
@@ -23,6 +23,7 @@ ${c.bold('talea sync')} — make this machine match the list
23
23
 
24
24
  ${c.dim('talea sync')} clone what is missing, fast-forward the rest
25
25
  ${c.dim('talea sync --pick')} change what this machine keeps, then sync
26
+ ${c.dim('talea sync eklavya')} only that repo (same as -r eklavya)
26
27
  ${c.dim('talea sync -g nonstopio')} only that owner
27
28
  ${c.dim('talea sync --no-clone')} fast-forward only, clone nothing
28
29
 
@@ -36,7 +37,7 @@ the workspace ${c.dim('talea init')} made, or asks which when this machine has s
36
37
 
37
38
  Options
38
39
  -g, --group <names> comma-separated groups
39
- -r, --repo <names> comma-separated repo names
40
+ -r, --repo <names> comma-separated repo names; a bare name works too
40
41
  --pick re-open the checklist before syncing
41
42
  --no-clone do not clone anything new
42
43
  --no-adopt do not look for checkouts to move into place
@@ -24,7 +24,7 @@ their docs come from the CLI — run \`talea sync\` to drop in any that are new.
24
24
 
25
25
  Options
26
26
  -g, --group <names> comma-separated groups
27
- -r, --repo <names> comma-separated repo names
27
+ -r, --repo <names> comma-separated repo names; a bare name works too
28
28
  --all the whole catalogue, not just what this machine keeps
29
29
  `;
30
30
 
package/src/git.js CHANGED
@@ -181,7 +181,11 @@ export async function currentBranch(dir) {
181
181
  const { code, stdout } = await git(['rev-parse', '--abbrev-ref', 'HEAD'], {
182
182
  cwd: dir,
183
183
  });
184
- return code === 0 ? stdout : null;
184
+ if (code === 0) return stdout;
185
+ // A repo with no commits yet has no HEAD to resolve, so rev-parse fails and
186
+ // the caller printed "null". symbolic-ref still knows the branch's name.
187
+ const born = await git(['symbolic-ref', '--short', 'HEAD'], { cwd: dir });
188
+ return born.code === 0 ? born.stdout : null;
185
189
  }
186
190
 
187
191
  /** True when the working tree has uncommitted changes (tracked or untracked). */