docs-cache 0.5.3 → 0.5.4

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.
@@ -177,35 +177,54 @@ const ensureCommitAvailable = async (repoPath, commit, options) => {
177
177
  logger: options?.logger
178
178
  });
179
179
  };
180
- const isSparseEligible = (include) => {
181
- if (!include || include.length === 0) {
182
- return false;
180
+ const patternHasGlob = (pattern) => pattern.includes("*") || pattern.includes("?") || pattern.includes("[");
181
+ const normalizeSparsePatterns = (include) => (include ?? []).map((pattern) => pattern.replace(/\\/g, "/")).filter(Boolean);
182
+ const isDirectoryLiteral = (pattern) => pattern.endsWith("/");
183
+ const toNoConePattern = (pattern) => {
184
+ if (!patternHasGlob(pattern) && isDirectoryLiteral(pattern)) {
185
+ return pattern.endsWith("/") ? pattern : `${pattern}/`;
186
+ }
187
+ return pattern;
188
+ };
189
+ const resolveSparseSpec = (include) => {
190
+ const normalized = normalizeSparsePatterns(include);
191
+ if (normalized.length === 0) {
192
+ return { enabled: false, mode: "cone", patterns: [] };
183
193
  }
184
- for (const pattern of include) {
185
- if (!pattern || pattern.includes("**")) {
186
- return false;
194
+ const conePaths = [];
195
+ let coneEligible = true;
196
+ for (const pattern of normalized) {
197
+ if (pattern.includes("**")) {
198
+ coneEligible = false;
199
+ break;
187
200
  }
201
+ if (patternHasGlob(pattern)) {
202
+ coneEligible = false;
203
+ break;
204
+ }
205
+ if (isDirectoryLiteral(pattern)) {
206
+ conePaths.push(pattern.replace(/\/+$/, ""));
207
+ continue;
208
+ }
209
+ coneEligible = false;
210
+ break;
188
211
  }
189
- return true;
190
- };
191
- const extractSparsePaths = (include) => {
192
- if (!include) {
193
- return [];
212
+ const uniquePaths = Array.from(new Set(conePaths.filter(Boolean)));
213
+ if (coneEligible && uniquePaths.length > 0) {
214
+ return { enabled: true, mode: "cone", patterns: uniquePaths };
194
215
  }
195
- const paths = include.map((pattern) => {
196
- const normalized = pattern.replace(/\\/g, "/");
197
- const starIndex = normalized.indexOf("*");
198
- const base = starIndex === -1 ? normalized : normalized.slice(0, starIndex);
199
- return base.replace(/\/+$|\/$/, "");
200
- });
201
- return Array.from(new Set(paths.filter((value) => value.length > 0)));
216
+ return {
217
+ enabled: true,
218
+ mode: "no-cone",
219
+ patterns: normalized.map(toNoConePattern)
220
+ };
202
221
  };
203
222
  const cloneRepo = async (params, outDir) => {
204
223
  if (params.offline) {
205
224
  throw new Error(`Cannot clone ${params.repo} while offline.`);
206
225
  }
207
226
  const isCommitRef = /^[0-9a-f]{7,40}$/i.test(params.ref);
208
- const useSparse = isSparseEligible(params.include);
227
+ const sparseSpec = resolveSparseSpec(params.include);
209
228
  const buildCloneArgs = () => {
210
229
  const cloneArgs2 = [
211
230
  "clone",
@@ -218,7 +237,7 @@ const cloneRepo = async (params, outDir) => {
218
237
  return cloneArgs2;
219
238
  };
220
239
  const cloneArgs = buildCloneArgs();
221
- if (useSparse) {
240
+ if (sparseSpec.enabled) {
222
241
  cloneArgs.push("--sparse");
223
242
  }
224
243
  if (!isCommitRef) {
@@ -239,14 +258,16 @@ const cloneRepo = async (params, outDir) => {
239
258
  logger: params.logger,
240
259
  offline: params.offline
241
260
  });
242
- if (useSparse) {
243
- const sparsePaths = extractSparsePaths(params.include);
244
- if (sparsePaths.length > 0) {
245
- await git(["-C", outDir, "sparse-checkout", "set", ...sparsePaths], {
246
- timeoutMs: params.timeoutMs,
247
- logger: params.logger
248
- });
261
+ if (sparseSpec.enabled) {
262
+ const sparseArgs = ["-C", outDir, "sparse-checkout", "set"];
263
+ if (sparseSpec.mode === "no-cone") {
264
+ sparseArgs.push("--no-cone");
249
265
  }
266
+ sparseArgs.push(...sparseSpec.patterns);
267
+ await git(sparseArgs, {
268
+ timeoutMs: params.timeoutMs,
269
+ logger: params.logger
270
+ });
250
271
  }
251
272
  await git(
252
273
  ["-C", outDir, "checkout", "--quiet", "--detach", params.resolvedCommit],
@@ -281,9 +302,14 @@ const addWorktreeFromCache = async (params, cachePath, outDir) => {
281
302
  allowFileProtocol: true
282
303
  }
283
304
  );
284
- const sparsePaths = isSparseEligible(params.include) ? extractSparsePaths(params.include) : [];
285
- if (sparsePaths.length > 0) {
286
- await git(["-C", outDir, "sparse-checkout", "set", ...sparsePaths], {
305
+ const sparseSpec = resolveSparseSpec(params.include);
306
+ if (sparseSpec.enabled) {
307
+ const sparseArgs = ["-C", outDir, "sparse-checkout", "set"];
308
+ if (sparseSpec.mode === "no-cone") {
309
+ sparseArgs.push("--no-cone");
310
+ }
311
+ sparseArgs.push(...sparseSpec.patterns);
312
+ await git(sparseArgs, {
287
313
  timeoutMs: params.timeoutMs,
288
314
  logger: params.logger,
289
315
  allowFileProtocol: true
@@ -380,7 +406,7 @@ const cloneOrUpdateRepo = async (params, outDir) => {
380
406
  const cacheExists = await exists(cachePath);
381
407
  const cacheValid = cacheExists && await isValidGitRepo(cachePath);
382
408
  const isCommitRef = /^[0-9a-f]{7,40}$/i.test(params.ref);
383
- const useSparse = isSparseEligible(params.include);
409
+ const sparseSpec = resolveSparseSpec(params.include);
384
410
  let usedCache = cacheValid;
385
411
  let worktreeUsed = false;
386
412
  const cacheRoot = resolveGitCacheDir();
@@ -410,7 +436,7 @@ const cloneOrUpdateRepo = async (params, outDir) => {
410
436
  if (await isPartialClone(cachePath)) {
411
437
  localCloneArgs.splice(2, 0, "--filter=blob:none");
412
438
  }
413
- if (useSparse) {
439
+ if (sparseSpec.enabled) {
414
440
  localCloneArgs.push("--sparse");
415
441
  }
416
442
  if (!isCommitRef) {
@@ -428,15 +454,17 @@ const cloneOrUpdateRepo = async (params, outDir) => {
428
454
  progressLogger: params.progressLogger,
429
455
  forceProgress: Boolean(params.progressLogger)
430
456
  });
431
- if (useSparse) {
432
- const sparsePaths = extractSparsePaths(params.include);
433
- if (sparsePaths.length > 0) {
434
- await git(["-C", outDir, "sparse-checkout", "set", ...sparsePaths], {
435
- timeoutMs: params.timeoutMs,
436
- allowFileProtocol: true,
437
- logger: params.logger
438
- });
457
+ if (sparseSpec.enabled) {
458
+ const sparseArgs = ["-C", outDir, "sparse-checkout", "set"];
459
+ if (sparseSpec.mode === "no-cone") {
460
+ sparseArgs.push("--no-cone");
439
461
  }
462
+ sparseArgs.push(...sparseSpec.patterns);
463
+ await git(sparseArgs, {
464
+ timeoutMs: params.timeoutMs,
465
+ allowFileProtocol: true,
466
+ logger: params.logger
467
+ });
440
468
  }
441
469
  await ensureCommitAvailable(outDir, params.resolvedCommit, {
442
470
  timeoutMs: params.timeoutMs,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "docs-cache",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "0.5.3",
5
+ "version": "0.5.4",
6
6
  "packageManager": "pnpm@10.14.0+sha512.ad27a79641b49c3e481a16a805baa71817a04bbe06a38d17e60e2eaee83f6a146c6a688125f5792e48dd5ba30e7da52a5cda4c3992b9ccf333f9ce223af84748",
7
7
  "description": "CLI for deterministic local caching of external documentation for agents and tools",
8
8
  "author": "Frederik Bosch",