@cvr/repo 1.1.0 → 1.1.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/bin/repo CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cvr/repo",
3
- "version": "1.1.0",
3
+ "version": "1.1.1",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/cevr/repo.git"
@@ -34,23 +34,53 @@ export class CacheService extends Context.Tag("@cvr/repo/services/cache/CacheSer
34
34
  );
35
35
 
36
36
  const getPath = (spec: PackageSpec) =>
37
- Effect.sync(() => {
37
+ Effect.gen(function* () {
38
38
  // All repos stored as: ~/.cache/repo/{name}[@version]
39
39
  // GitHub: owner/repo -> ~/.cache/repo/owner/repo
40
40
  // npm: package@version -> ~/.cache/repo/package/version (or package/default)
41
41
  // pypi/crates: same pattern
42
42
  const version = Option.getOrElse(spec.version, () => "default");
43
43
  switch (spec.registry) {
44
- case "github":
44
+ case "github": {
45
45
  // GitHub repos don't have versions in path (use git refs)
46
- return pathService.join(cacheDir, spec.name);
46
+ const normalizedPath = pathService.join(cacheDir, spec.name);
47
+
48
+ // Fast path: normalized path exists
49
+ if (yield* fs.exists(normalizedPath)) return normalizedPath;
50
+
51
+ // Fallback: case-insensitive search for legacy cached repos
52
+ // (repos cached before case-normalization fix may have different casing)
53
+ // spec.name guaranteed to be "owner/repo" format for github registry
54
+ const [owner, repo] = spec.name.split("/") as [string, string];
55
+
56
+ const cacheExists = yield* fs.exists(cacheDir);
57
+ if (!cacheExists) return normalizedPath;
58
+
59
+ const entries = yield* fs.readDirectory(cacheDir);
60
+ for (const entry of entries) {
61
+ if (entry.toLowerCase() === owner) {
62
+ const ownerPath = pathService.join(cacheDir, entry);
63
+ const ownerStat = yield* fs.stat(ownerPath);
64
+ if (ownerStat.type !== "Directory") continue;
65
+
66
+ const repoEntries = yield* fs.readDirectory(ownerPath);
67
+ for (const repoEntry of repoEntries) {
68
+ if (repoEntry.toLowerCase() === repo) {
69
+ return pathService.join(ownerPath, repoEntry);
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ return normalizedPath;
76
+ }
47
77
  case "npm":
48
78
  case "pypi":
49
79
  case "crates":
50
80
  // Package registries include version in path
51
81
  return pathService.join(cacheDir, spec.name, version);
52
82
  }
53
- });
83
+ }).pipe(Effect.orDie);
54
84
 
55
85
  const exists = (spec: PackageSpec) =>
56
86
  Effect.gen(function* () {
@@ -41,7 +41,11 @@ export class MetadataService extends Context.Tag("@cvr/repo/services/metadata/Me
41
41
  const cacheRef = yield* Ref.make<CacheState>({ index: null, dirty: false });
42
42
 
43
43
  const specMatches = (a: PackageSpec, b: PackageSpec): boolean => {
44
- if (a.registry !== b.registry || a.name !== b.name) return false;
44
+ if (a.registry !== b.registry) return false;
45
+ // GitHub repos are case-insensitive (legacy cached repos may have different casing)
46
+ const aName = a.registry === "github" ? a.name.toLowerCase() : a.name;
47
+ const bName = b.registry === "github" ? b.name.toLowerCase() : b.name;
48
+ if (aName !== bName) return false;
45
49
  const aVersion = Option.getOrElse(a.version, () => "");
46
50
  const bVersion = Option.getOrElse(b.version, () => "");
47
51
  return aVersion === bVersion;