@kaisers-io/refs 0.13.1 → 0.14.1

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
@@ -5,6 +5,100 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.14.1] - 2026-09-13
9
+
10
+ ### Fixed
11
+
12
+ - **A symlink with no package behind it no longer makes the scan unreliable.** A symlinked
13
+ directory can never be walked — `readdir` uses lstat semantics — so one that could have held a
14
+ package was reported as an uninspected candidate, and a single one of those turns the
15
+ unregistered-package pass off for the whole ref. `withastro/astro` carries two fixture links
16
+ whose targets hold markdown and JSON and no manifest at any depth: its scan reported two
17
+ obstacles and stood discovery down permanently, over directories where there was nothing to
18
+ find.
19
+
20
+ The question is now answered by LOOKING rather than by reasoning about the pattern: is there a
21
+ `package.json` anywhere below the link's target? If there is not, no pattern selects a package
22
+ there and the link hid nothing from anyone. If there is one — at any depth — it is reported
23
+ exactly as before. The search spends the scan's own budget and reports the obstacle when it runs
24
+ out, because an unfinished look is not a look.
25
+
26
+ An earlier attempt tried to prove instead that the target's own path selects whatever the link
27
+ path selects. It cannot be proven from the pattern's shape: a pattern selecting by position, an
28
+ exclusion naming the target or one of its descendants, a pattern matching the alias but not the
29
+ real path, and a link pointing at the base all break it in different ways. Each of those five
30
+ keeps being reported.
31
+
32
+ ## [0.14.0] - 2026-09-13
33
+
34
+ ### Upgrading
35
+
36
+ **A repository declaring a workspace pattern like `packages/**` now reports every member behind
37
+ it.** Those patterns were refused outright, which also stood the unregistered-package pass down for
38
+ the whole ref — so a ref that reported nothing for months may suddenly name hundreds of packages.
39
+ They are not new; they were invisible. `refs doctor` prints the first ten and a count of the rest,
40
+ `refs doctor --json` carries all of them, and
41
+ `refs edit --package=<name> --decline --path=<path> <ref>` records the ones you do not want so they
42
+ stop coming back.
43
+
44
+ ### Added
45
+
46
+ - **A workspace pattern that matches at more than one depth is expanded.** `packages/**/*` — the
47
+ most common pnpm spelling — was reported as `unsupported_pattern`, which also made the whole scan
48
+ unreliable and stood the unregistered-package pass down for that ref. A repository declaring it
49
+ got no answer at all, permanently.
50
+
51
+ Such a pattern is now walked from the deepest directory it names outright. Pruning is the
52
+ MATCHER's decision: minimatch answers "could anything below this directory still match?", so a
53
+ subtree no pattern can reach is never entered, a hidden directory is skipped where a wildcard
54
+ would not select it and walked where a pattern names it, and a package boundary does not stop
55
+ the walk — nested packages are ordinary, and both resolvers glob manifest paths rather than
56
+ stopping at one. Selection matches the manifest path for the same reason: `packages/core/**`
57
+ selects `packages/core` itself, because `**` matches zero segments before the manifest.
58
+ `node_modules` and `.git` are never walked under any pattern — a recursive pattern matches an
59
+ installed dependency's path as a string, and reporting those would be reporting a repository's
60
+ dependencies as its own packages.
61
+
62
+ The whole scan runs under one budget shared by every pattern — 32 levels deep, 20 000
63
+ directories, 200 000 entries — because patterns overlap, and a per-pattern budget would charge
64
+ the same tree once per declaration. Reaching a limit is not itself a failure; having to leave a
65
+ subtree that could still match unwalked is, and that is the only condition `scan_budget_exhausted`
66
+ is reported under. A directory the pattern names but the repository does not have stays silent,
67
+ which is ordinary: astro declares `smoke/**/*` and a fresh clone has no `smoke/`.
68
+
69
+ Measured against the resolvers themselves, on fresh clones: `withastro/astro` now detects 554
70
+ packages where pnpm's own workspace listing reports 554 and refs previously reported 37;
71
+ `vercel/next.js` detects 38 where pnpm reports 38; `payloadcms/payload` 53 where pnpm reports 53.
72
+ Pattern semantics were checked against `@npmcli/map-workspaces` over six pattern shapes.
73
+
74
+ - **A ref with hundreds of findings no longer prints all of them.** The same repositories that
75
+ motivated the expansion can legitimately have hundreds of workspace members, so a ref tracking
76
+ three of them would print 551 repair commands into one `doctor` line. Ten are printed, followed
77
+ by a count of what was held back — act on those and run the check again for the next batch.
78
+ `refs doctor --json` carries every finding on the check itself, uncapped: a finding no command
79
+ can repair is never cleared by acting on the ones printed before it, so a capped list would put
80
+ it permanently out of reach.
81
+
82
+ - **A drift finding you have decided against can be recorded, so it stops coming back.**
83
+ `refs doctor` reports every workspace member a checkout declares that the configuration does not
84
+ have. There was no way to say "I looked, and no": the finding returned on every run forever, so
85
+ `config-drift` sat on `warn` permanently and the next real finding arrived in a line already
86
+ being ignored. On a home tracking four monorepos, six of seven findings were decisions that had
87
+ already been made — a repository root, and four packages published nowhere.
88
+
89
+ `refs edit --package=<name> --decline --path=<path> <ref>` records the decision on the ref, as
90
+ the name AND the path. Neither identifies it alone: a name-only record would also silence a
91
+ different package that later takes the name, and a path-only one would silence whatever moves in.
92
+ The `unregistered` finding now prints this command beside the registration command, so both
93
+ answers are available where the question is asked.
94
+
95
+ What a decline does not do: it never touches a finding about a configured entry (`missing`,
96
+ `relocated`, `ambiguous`, `unverifiable`), never suppresses `discovery_incomplete`, and never
97
+ hides the other claimants of an ambiguous name. The package is reported again if it moves.
98
+ `--undecline` withdraws the decision; registering the package clears it in the same write.
99
+ `refs doctor` says how many decisions a run left unreported, so a quiet check is not a silent
100
+ one.
101
+
8
102
  ## [0.13.1] - 2026-09-12
9
103
 
10
104
  ### Upgrading