@youtyan/code-viewer 0.8.2 → 0.8.3

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.
@@ -666,9 +666,47 @@ var init_annotations = __esm(() => {
666
666
  });
667
667
  });
668
668
 
669
+ // web-src/server/cache.ts
670
+ import { lstatSync } from "node:fs";
671
+ import { join as join2 } from "node:path";
672
+ function cacheFresh(cached, now = Date.now(), ttlMs = CACHE_TTL_MS) {
673
+ return !!cached && now - cached.storedAt <= ttlMs;
674
+ }
675
+ function setTimedCacheEntry(cache, key, value, now = Date.now(), maxEntries = MAX_TIMED_CACHE_ENTRIES) {
676
+ cache.set(key, { ...value, storedAt: now });
677
+ while (cache.size > maxEntries) {
678
+ const oldest = cache.keys().next().value;
679
+ if (oldest === undefined)
680
+ break;
681
+ cache.delete(oldest);
682
+ }
683
+ }
684
+ function worktreeFileSignature(path, cwd) {
685
+ try {
686
+ const stats = lstatSync(join2(cwd, path));
687
+ const inode = "ino" in stats ? stats.ino : 0;
688
+ return `state:file|size:${stats.size}|mtime:${stats.mtimeMs}|ctime:${stats.ctimeMs}|ino:${inode}`;
689
+ } catch {
690
+ return "state:missing";
691
+ }
692
+ }
693
+ function fileDiffCacheKey(options) {
694
+ const worktreeTarget = options.range.from === "worktree" || !options.range.to || options.range.to === "worktree";
695
+ if (options.isUntracked && !worktreeTarget) {
696
+ throw new Error("untracked file diffs require a worktree range");
697
+ }
698
+ const signature = worktreeTarget ? `\x00${worktreeFileSignature(options.path, options.cwd)}` : "";
699
+ if (options.isUntracked) {
700
+ return `u\x00${options.path}${signature}\x00${options.extras.join("\x00")}`;
701
+ }
702
+ return `t\x00${options.path}\x00${options.oldPath || ""}${signature}\x00${[...options.extras, ...options.args].join("\x00")}`;
703
+ }
704
+ var CACHE_TTL_MS = 1500, MAX_TIMED_CACHE_ENTRIES = 200;
705
+ var init_cache = () => {};
706
+
669
707
  // web-src/server/command-resolver.ts
670
708
  import { accessSync, constants, realpathSync, statSync } from "node:fs";
671
- import { dirname as dirname2, isAbsolute, join as join2, relative } from "node:path";
709
+ import { dirname as dirname2, isAbsolute, join as join3, relative } from "node:path";
672
710
  function isExternalCommandName(value) {
673
711
  return commandNameSet.has(value);
674
712
  }
@@ -803,7 +841,7 @@ function findGitRootByWalking(start) {
803
841
  let current = start;
804
842
  for (;; ) {
805
843
  try {
806
- statSync(join2(current, ".git"));
844
+ statSync(join3(current, ".git"));
807
845
  return realpathSync(current);
808
846
  } catch {}
809
847
  const parent = dirname2(current);
@@ -1217,14 +1255,16 @@ var init_runtime = () => {};
1217
1255
  import {
1218
1256
  closeSync,
1219
1257
  existsSync,
1220
- lstatSync,
1258
+ lstatSync as lstatSync2,
1221
1259
  openSync,
1222
1260
  readdirSync,
1223
1261
  readFileSync,
1262
+ readlinkSync,
1224
1263
  readSync,
1264
+ realpathSync as realpathSync2,
1225
1265
  statSync as statSync2
1226
1266
  } from "node:fs";
1227
- import { join as join3 } from "node:path";
1267
+ import { dirname as dirname3, join as join4, posix, relative as relative2 } from "node:path";
1228
1268
  function normalizeBlameRef(ref, base) {
1229
1269
  const rawRef = ref || "worktree";
1230
1270
  if (base === "worktree" && rawRef !== "worktree") {
@@ -1322,12 +1362,76 @@ async function statusPorcelainForPathAsync(path, cwd) {
1322
1362
  error: gitFailureMessage(res, "git status failed")
1323
1363
  };
1324
1364
  }
1365
+ async function repoStatusMapAsync(cwd, now = Date.now()) {
1366
+ const cached = repoStatusMapCache.get(cwd);
1367
+ if (cacheFresh(cached, now))
1368
+ return cached.map;
1369
+ const map = new Map;
1370
+ const res = await runGitAsync([
1371
+ "git",
1372
+ "-c",
1373
+ "core.quotepath=false",
1374
+ "status",
1375
+ "--porcelain=v1",
1376
+ "-z",
1377
+ "--untracked-files=all"
1378
+ ], cwd);
1379
+ if (res.code !== 0)
1380
+ return map;
1381
+ const records = res.stdout.split("\x00").filter(Boolean);
1382
+ for (let i = 0;i < records.length; i++) {
1383
+ const record = records[i];
1384
+ const xy = record.slice(0, 2);
1385
+ const path = record.slice(3);
1386
+ if (!path)
1387
+ continue;
1388
+ if (xy === "??") {
1389
+ map.set(path, "A");
1390
+ continue;
1391
+ }
1392
+ if (xy[0] === "R" || xy[0] === "C" || xy[1] === "R" || xy[1] === "C") {
1393
+ i++;
1394
+ map.set(path, "R");
1395
+ continue;
1396
+ }
1397
+ const code = xy[0] !== " " ? xy[0] : xy[1];
1398
+ if (code && code !== " ")
1399
+ map.set(path, code);
1400
+ }
1401
+ setTimedCacheEntry(repoStatusMapCache, cwd, { map }, now);
1402
+ return map;
1403
+ }
1325
1404
  function show(ref, path, cwd) {
1326
1405
  return run(["git", "show", `${ref}:${path}`], cwd);
1327
1406
  }
1328
1407
  function showAsync(ref, path, cwd) {
1329
1408
  return runGitAsync(["git", "show", `${ref}:${path}`], cwd);
1330
1409
  }
1410
+ function resolveSymlinkPath(linkPath, target) {
1411
+ if (!target || target.startsWith("/") || target.includes("\x00"))
1412
+ return null;
1413
+ const baseDir = dirname3(linkPath);
1414
+ const combined = baseDir === "." ? target : `${baseDir}/${target}`;
1415
+ const normalized = posix.normalize(combined);
1416
+ if (normalized === "." || normalized === "")
1417
+ return "";
1418
+ if (normalized === ".." || normalized.startsWith("../"))
1419
+ return null;
1420
+ return normalized;
1421
+ }
1422
+ async function gitSymlinkTargetMetadataAsync(ref, path, cwd) {
1423
+ const res = await showAsync(ref, path, cwd);
1424
+ if (res.code !== 0)
1425
+ return { symlink_target_type: "missing" };
1426
+ const target = res.stdout;
1427
+ const resolved = resolveSymlinkPath(path, target);
1428
+ if (resolved === null)
1429
+ return { symlink_target: target, symlink_target_type: "missing" };
1430
+ const type = await runGitAsync(["git", "cat-file", "-t", `${ref}:${resolved}`], cwd);
1431
+ const kind = type.stdout.trim();
1432
+ const symlink_target_type = kind === "tree" ? "tree" : kind === "blob" ? "blob" : "missing";
1433
+ return symlink_target_type === "missing" ? { symlink_target: target, symlink_target_type } : { symlink_target: target, symlink_target_type, resolved_path: resolved };
1434
+ }
1331
1435
  function catFileBlobStream(oid, cwd) {
1332
1436
  return spawnStream(resolveGitArgs(["git", "cat-file", "blob", oid]), cwd);
1333
1437
  }
@@ -1958,7 +2062,7 @@ function isGitInternalPath(path) {
1958
2062
  return pathHasSegment(path, ".git");
1959
2063
  }
1960
2064
  function syntheticUncommittedBlameFromWorktree(cwd, path) {
1961
- const filePath = join3(cwd, path);
2065
+ const filePath = join4(cwd, path);
1962
2066
  try {
1963
2067
  const stat = statSync2(filePath);
1964
2068
  if (!stat.isFile())
@@ -2217,7 +2321,7 @@ function omittedWorktreeDirectoryReason(name, omitDirNames) {
2217
2321
  return omitDirNames.matches(name) ? "heavy" : undefined;
2218
2322
  }
2219
2323
  function worktreeSubmodulePaths(cwd) {
2220
- if (!existsSync(join3(cwd, ".gitmodules")))
2324
+ if (!existsSync(join4(cwd, ".gitmodules")))
2221
2325
  return new Set;
2222
2326
  const res = run(["git", "config", "--file", ".gitmodules", "--get-regexp", "\\.path$"], cwd);
2223
2327
  if (res.code !== 0)
@@ -2229,7 +2333,7 @@ function worktreeSubmodulePaths(cwd) {
2229
2333
  }).filter(Boolean));
2230
2334
  }
2231
2335
  async function worktreeSubmodulePathsAsync(cwd) {
2232
- if (!existsSync(join3(cwd, ".gitmodules")))
2336
+ if (!existsSync(join4(cwd, ".gitmodules")))
2233
2337
  return new Set;
2234
2338
  const res = await runGitAsync(["git", "config", "--file", ".gitmodules", "--get-regexp", "\\.path$"], cwd);
2235
2339
  if (res.code !== 0)
@@ -2240,7 +2344,48 @@ async function worktreeSubmodulePathsAsync(cwd) {
2240
2344
  return split >= 0 ? normalizeTreePath(line.slice(split + 1)) : "";
2241
2345
  }).filter(Boolean));
2242
2346
  }
2243
- function worktreeEntryFromDirent(base, dir, name, isDirectory, omitDirNames, excludeNames, submodulePaths) {
2347
+ function realpathWithinRepo(cwd, full, allowRoot) {
2348
+ try {
2349
+ const realCwd = realpathSync2(cwd);
2350
+ const realFull = realpathSync2(full);
2351
+ const rel = relative2(realCwd, realFull);
2352
+ if (rel.startsWith("..") || rel.startsWith("/") || rel.startsWith("\\"))
2353
+ return null;
2354
+ if (rel === "" && !allowRoot)
2355
+ return null;
2356
+ return realFull;
2357
+ } catch {
2358
+ return null;
2359
+ }
2360
+ }
2361
+ function resolveWorktreeSymlinkTarget(cwd, full) {
2362
+ let symlink_target;
2363
+ try {
2364
+ symlink_target = readlinkSync(full);
2365
+ } catch {
2366
+ symlink_target = undefined;
2367
+ }
2368
+ let symlink_target_type = "missing";
2369
+ if (realpathWithinRepo(cwd, full, false) !== null) {
2370
+ try {
2371
+ const stat = statSync2(full);
2372
+ symlink_target_type = stat.isDirectory() ? "tree" : stat.isFile() ? "blob" : "missing";
2373
+ } catch {
2374
+ symlink_target_type = "missing";
2375
+ }
2376
+ }
2377
+ return symlink_target === undefined ? { symlink_target_type } : { symlink_target, symlink_target_type };
2378
+ }
2379
+ function recursiveWorktreeFileEntry(cwd, full, name, path, isSymlink) {
2380
+ const symlinkInfo = isSymlink ? resolveWorktreeSymlinkTarget(cwd, full) : null;
2381
+ return {
2382
+ name,
2383
+ path,
2384
+ type: "blob",
2385
+ ...symlinkInfo ? { is_symlink: true, ...symlinkInfo } : {}
2386
+ };
2387
+ }
2388
+ function worktreeEntryFromDirent(cwd, base, dir, name, isDirectory, isSymlink, omitDirNames, excludeNames, submodulePaths) {
2244
2389
  if (excludeNames.matches(name))
2245
2390
  return {
2246
2391
  name,
@@ -2248,10 +2393,18 @@ function worktreeEntryFromDirent(base, dir, name, isDirectory, omitDirNames, exc
2248
2393
  type: isDirectory ? "tree" : "blob"
2249
2394
  };
2250
2395
  const entryPath = base ? `${base}/${name}` : name;
2251
- const type = isDirectory ? hasDotGitEntry(join3(dir, name)) ? "commit" : "tree" : "blob";
2396
+ const symlinkInfo = isSymlink ? resolveWorktreeSymlinkTarget(cwd, join4(dir, name)) : null;
2397
+ const resolvedIsDirectory = symlinkInfo ? symlinkInfo.symlink_target_type === "tree" : isDirectory;
2398
+ const type = symlinkInfo && symlinkInfo.symlink_target_type === "missing" ? "blob" : resolvedIsDirectory ? hasDotGitEntry(join4(dir, name)) ? "commit" : "tree" : "blob";
2252
2399
  const omittedReason = type === "tree" ? omittedWorktreeDirectoryReason(name, omitDirNames) : undefined;
2253
2400
  const submodule = type === "commit" && submodulePaths.has(entryPath) ? true : undefined;
2254
- const baseEntry = submodule ? { name, path: entryPath, type, submodule } : { name, path: entryPath, type };
2401
+ const baseEntry = {
2402
+ name,
2403
+ path: entryPath,
2404
+ type,
2405
+ ...submodule ? { submodule } : {},
2406
+ ...symlinkInfo ? { is_symlink: true, ...symlinkInfo } : {}
2407
+ };
2255
2408
  return omittedReason ? {
2256
2409
  ...baseEntry,
2257
2410
  children_omitted: true,
@@ -2260,14 +2413,16 @@ function worktreeEntryFromDirent(base, dir, name, isDirectory, omitDirNames, exc
2260
2413
  }
2261
2414
  function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_WORKTREE_OMIT_DIR_NAMES, excludeNames = []) {
2262
2415
  const base = normalizeTreePath(path);
2263
- const root = join3(cwd, base);
2416
+ const root = join4(cwd, base);
2417
+ if (realpathWithinRepo(cwd, root, true) === null)
2418
+ return [];
2264
2419
  const omitDirNameSet = compileNamePatterns(omitDirNames);
2265
2420
  const excludeNameSet = compileNamePatterns(excludeNames);
2266
2421
  const submodulePaths = worktreeSubmodulePaths(cwd);
2267
2422
  let directEntries;
2268
2423
  try {
2269
2424
  const dirents = readdirSync(root, { withFileTypes: true });
2270
- directEntries = sortTreeEntries(dirents.map((entry) => worktreeEntryFromDirent(base, root, entry.name, entry.isDirectory(), omitDirNameSet, excludeNameSet, submodulePaths)).filter((entry) => entry.path));
2425
+ directEntries = sortTreeEntries(dirents.map((entry) => worktreeEntryFromDirent(cwd, base, root, entry.name, entry.isDirectory(), entry.isSymbolicLink(), omitDirNameSet, excludeNameSet, submodulePaths)).filter((entry) => entry.path));
2271
2426
  } catch {
2272
2427
  return [];
2273
2428
  }
@@ -2307,7 +2462,7 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
2307
2462
  if (excludeNameSet.matches(entry.name))
2308
2463
  continue;
2309
2464
  const entryPath = prefix ? `${prefix}/${entry.name}` : entry.name;
2310
- const full = join3(dir, entry.name);
2465
+ const full = join4(dir, entry.name);
2311
2466
  if (entry.isDirectory()) {
2312
2467
  const omittedReason = omittedWorktreeDirectoryReason(entry.name, omitDirNameSet);
2313
2468
  if (omittedReason) {
@@ -2325,11 +2480,7 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
2325
2480
  continue;
2326
2481
  walk(full, entryPath, depth + 1);
2327
2482
  } else if (entry.isFile() || entry.isSymbolicLink()) {
2328
- if (!pushRecursiveEntry({
2329
- name: entry.name,
2330
- path: entryPath,
2331
- type: "blob"
2332
- }))
2483
+ if (!pushRecursiveEntry(recursiveWorktreeFileEntry(cwd, full, entry.name, entryPath, entry.isSymbolicLink())))
2333
2484
  return;
2334
2485
  }
2335
2486
  }
@@ -2339,14 +2490,16 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
2339
2490
  }
2340
2491
  async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames = DEFAULT_WORKTREE_OMIT_DIR_NAMES, excludeNames = []) {
2341
2492
  const base = normalizeTreePath(path);
2342
- const root = join3(cwd, base);
2493
+ const root = join4(cwd, base);
2494
+ if (realpathWithinRepo(cwd, root, true) === null)
2495
+ return [];
2343
2496
  const omitDirNameSet = compileNamePatterns(omitDirNames);
2344
2497
  const excludeNameSet = compileNamePatterns(excludeNames);
2345
2498
  const submodulePaths = await worktreeSubmodulePathsAsync(cwd);
2346
2499
  let directEntries;
2347
2500
  try {
2348
2501
  const dirents = readdirSync(root, { withFileTypes: true });
2349
- directEntries = sortTreeEntries(dirents.map((entry) => worktreeEntryFromDirent(base, root, entry.name, entry.isDirectory(), omitDirNameSet, excludeNameSet, submodulePaths)).filter((entry) => entry.path));
2502
+ directEntries = sortTreeEntries(dirents.map((entry) => worktreeEntryFromDirent(cwd, base, root, entry.name, entry.isDirectory(), entry.isSymbolicLink(), omitDirNameSet, excludeNameSet, submodulePaths)).filter((entry) => entry.path));
2350
2503
  } catch {
2351
2504
  return [];
2352
2505
  }
@@ -2394,7 +2547,7 @@ async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames
2394
2547
  if (excludeNameSet.matches(entry.name))
2395
2548
  continue;
2396
2549
  const entryPath = prefix ? `${prefix}/${entry.name}` : entry.name;
2397
- const full = join3(dir, entry.name);
2550
+ const full = join4(dir, entry.name);
2398
2551
  if (entry.isDirectory()) {
2399
2552
  const omittedReason = omittedWorktreeDirectoryReason(entry.name, omitDirNameSet);
2400
2553
  if (omittedReason) {
@@ -2412,11 +2565,7 @@ async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames
2412
2565
  continue;
2413
2566
  await walk(full, entryPath, depth + 1);
2414
2567
  } else if (entry.isFile() || entry.isSymbolicLink()) {
2415
- if (!pushRecursiveEntry({
2416
- name: entry.name,
2417
- path: entryPath,
2418
- type: "blob"
2419
- }))
2568
+ if (!pushRecursiveEntry(recursiveWorktreeFileEntry(cwd, full, entry.name, entryPath, entry.isSymbolicLink())))
2420
2569
  return;
2421
2570
  }
2422
2571
  }
@@ -2426,12 +2575,24 @@ async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames
2426
2575
  }
2427
2576
  function hasDotGitEntry(dir) {
2428
2577
  try {
2429
- lstatSync(join3(dir, ".git"));
2578
+ lstatSync2(join4(dir, ".git"));
2430
2579
  return true;
2431
2580
  } catch (err) {
2432
2581
  return !!err && typeof err === "object" && "code" in err && err.code !== "ENOENT";
2433
2582
  }
2434
2583
  }
2584
+ function parseLsTreeRecord(rec, allowedTypes) {
2585
+ const match = rec.match(new RegExp(`^(\\d+)\\s+(${allowedTypes})\\s+[0-9a-fA-F]+\\t(.+)$`));
2586
+ if (!match)
2587
+ return null;
2588
+ const [, mode, type, entryPath] = match;
2589
+ return {
2590
+ name: entryPath.split("/").pop() || entryPath,
2591
+ path: entryPath,
2592
+ type,
2593
+ ...mode === LS_TREE_SYMLINK_MODE ? { is_symlink: true } : {}
2594
+ };
2595
+ }
2435
2596
  function gitTreeEntries(ref, path, cwd, recursive) {
2436
2597
  const base = normalizeTreePath(path);
2437
2598
  const args = ["git", "-c", "core.quotepath=false", "ls-tree"];
@@ -2444,17 +2605,7 @@ function gitTreeEntries(ref, path, cwd, recursive) {
2444
2605
  if (res.code !== 0)
2445
2606
  return { code: res.code, entries: [], stderr: res.stderr };
2446
2607
  const allowedTypes = recursive ? "blob|commit" : "tree|blob|commit";
2447
- let entries = res.stdout.split("\x00").filter(Boolean).map((rec) => {
2448
- const match = rec.match(new RegExp(`^\\d+\\s+(${allowedTypes})\\s+[0-9a-fA-F]+\\t(.+)$`));
2449
- if (!match)
2450
- return null;
2451
- const entryPath = match[2];
2452
- return {
2453
- name: entryPath.split("/").pop() || entryPath,
2454
- path: entryPath,
2455
- type: match[1]
2456
- };
2457
- }).filter((entry) => !!entry);
2608
+ let entries = res.stdout.split("\x00").filter(Boolean).map((rec) => parseLsTreeRecord(rec, allowedTypes)).filter((entry) => !!entry);
2458
2609
  if (recursive)
2459
2610
  entries.sort((a, b) => a.path.localeCompare(b.path));
2460
2611
  else
@@ -2473,17 +2624,7 @@ async function gitTreeEntriesAsync(ref, path, cwd, recursive) {
2473
2624
  if (res.code !== 0)
2474
2625
  return { code: res.code, entries: [], stderr: res.stderr };
2475
2626
  const allowedTypes = recursive ? "blob|commit" : "tree|blob|commit";
2476
- let entries = res.stdout.split("\x00").filter(Boolean).map((rec) => {
2477
- const match = rec.match(new RegExp(`^\\d+\\s+(${allowedTypes})\\s+[0-9a-fA-F]+\\t(.+)$`));
2478
- if (!match)
2479
- return null;
2480
- const entryPath = match[2];
2481
- return {
2482
- name: entryPath.split("/").pop() || entryPath,
2483
- path: entryPath,
2484
- type: match[1]
2485
- };
2486
- }).filter((entry) => !!entry);
2627
+ let entries = res.stdout.split("\x00").filter(Boolean).map((rec) => parseLsTreeRecord(rec, allowedTypes)).filter((entry) => !!entry);
2487
2628
  if (recursive)
2488
2629
  entries.sort((a, b) => a.path.localeCompare(b.path));
2489
2630
  else
@@ -2547,7 +2688,7 @@ async function listTreeResultAsync(ref, path, cwd, options = {}) {
2547
2688
  }
2548
2689
  function untrackedMeta(cwd) {
2549
2690
  return untracked(cwd).flatMap((path) => {
2550
- const full = join3(cwd, path);
2691
+ const full = join4(cwd, path);
2551
2692
  let fileExists = false;
2552
2693
  try {
2553
2694
  fileExists = existsSync(full) && statSync2(full).isFile();
@@ -2579,7 +2720,7 @@ function untrackedMeta(cwd) {
2579
2720
  async function untrackedMetaAsync(cwd) {
2580
2721
  const paths = await untrackedAsync(cwd);
2581
2722
  return paths.flatMap((path) => {
2582
- const full = join3(cwd, path);
2723
+ const full = join4(cwd, path);
2583
2724
  let fileExists = false;
2584
2725
  try {
2585
2726
  fileExists = existsSync(full) && statSync2(full).isFile();
@@ -2827,8 +2968,9 @@ function truncateToNHunks(diffText, n, maxLines = Number.POSITIVE_INFINITY) {
2827
2968
  lineTruncated
2828
2969
  };
2829
2970
  }
2830
- var BLAME_ZERO_SHA = "0000000000000000000000000000000000000000", WORKTREE_RECURSIVE_DEPTH_LIMIT = 32, WORKTREE_RECURSIVE_ENTRY_LIMIT = 50000, DEFAULT_REF_COMMIT_LIMIT = 100, MAX_REF_COMMIT_LIMIT = 500, COMMIT_FORMAT = "%H%x00%s%x00%an%x00%aI", ALWAYS_WORKTREE_OMIT_DIR_NAMES, DEFAULT_WORKTREE_OMIT_DIR_NAMES, GIT_COMMAND_TIMEOUT_MS = 20000, HISTORY_FORMAT = "%H%x00%s%x00%an%x00%aI%x00%P%x00%b", MAX_HISTORY_LIMIT = 200;
2971
+ var BLAME_ZERO_SHA = "0000000000000000000000000000000000000000", WORKTREE_RECURSIVE_DEPTH_LIMIT = 32, WORKTREE_RECURSIVE_ENTRY_LIMIT = 50000, DEFAULT_REF_COMMIT_LIMIT = 100, MAX_REF_COMMIT_LIMIT = 500, COMMIT_FORMAT = "%H%x00%s%x00%an%x00%aI", ALWAYS_WORKTREE_OMIT_DIR_NAMES, DEFAULT_WORKTREE_OMIT_DIR_NAMES, GIT_COMMAND_TIMEOUT_MS = 20000, repoStatusMapCache, HISTORY_FORMAT = "%H%x00%s%x00%an%x00%aI%x00%P%x00%b", MAX_HISTORY_LIMIT = 200, LS_TREE_SYMLINK_MODE = "120000";
2831
2972
  var init_git = __esm(() => {
2973
+ init_cache();
2832
2974
  init_command_resolver();
2833
2975
  init_name_pattern();
2834
2976
  init_runtime();
@@ -2877,6 +3019,7 @@ var init_git = __esm(() => {
2877
3019
  "bin",
2878
3020
  "obj"
2879
3021
  ];
3022
+ repoStatusMapCache = new Map;
2880
3023
  });
2881
3024
 
2882
3025
  // web-src/server/server-registry.ts
@@ -2889,16 +3032,16 @@ import {
2889
3032
  writeFileSync
2890
3033
  } from "node:fs";
2891
3034
  import { homedir } from "node:os";
2892
- import { join as join4 } from "node:path";
3035
+ import { join as join5 } from "node:path";
2893
3036
  function registryDir() {
2894
3037
  const override = process.env.CODE_VIEWER_TEST_SERVER_REGISTRY_DIR;
2895
3038
  if (override)
2896
3039
  return override;
2897
- return join4(homedir(), ".cache", "code-viewer", "servers");
3040
+ return join5(homedir(), ".cache", "code-viewer", "servers");
2898
3041
  }
2899
3042
  function serverRegistryFilePath(root) {
2900
3043
  const hash = createHash("sha256").update(root).digest("hex").slice(0, 16);
2901
- return join4(registryDir(), `${hash}.json`);
3044
+ return join5(registryDir(), `${hash}.json`);
2902
3045
  }
2903
3046
  function writeServerRegistry(entry) {
2904
3047
  try {
@@ -2939,7 +3082,7 @@ function removeServerRegistry(root, pid) {
2939
3082
  var init_server_registry = () => {};
2940
3083
 
2941
3084
  // web-src/server/cli-helpers.ts
2942
- import { realpathSync as realpathSync2 } from "node:fs";
3085
+ import { realpathSync as realpathSync3 } from "node:fs";
2943
3086
  function takeValue(argv, index, flag) {
2944
3087
  const value = argv[index + 1];
2945
3088
  if (value === undefined)
@@ -2998,7 +3141,7 @@ function resolveRepoRootSafe(cwdOption) {
2998
3141
  const base = cwdOption || process.cwd();
2999
3142
  let baseReal;
3000
3143
  try {
3001
- baseReal = realpathSync2(base);
3144
+ baseReal = realpathSync3(base);
3002
3145
  } catch {
3003
3146
  return {
3004
3147
  ok: false,
@@ -4108,8 +4251,8 @@ __export(exports_file_cli, {
4108
4251
  FILE_DEFAULT_HISTORY_LIMIT: () => FILE_DEFAULT_HISTORY_LIMIT,
4109
4252
  FILE_AGENT_HELP: () => FILE_AGENT_HELP
4110
4253
  });
4111
- import { existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync3, statSync as statSync3 } from "node:fs";
4112
- import { join as join5, relative as relative2 } from "node:path";
4254
+ import { existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as realpathSync4, statSync as statSync3 } from "node:fs";
4255
+ import { join as join6, relative as relative3 } from "node:path";
4113
4256
  function validatePath(value) {
4114
4257
  return validateRepoRelativePathValue(value, "--path");
4115
4258
  }
@@ -4513,13 +4656,13 @@ function sliceLines(text, start, end) {
4513
4656
  function safeWorktreePathFromRoot(root, path) {
4514
4657
  if (validatePath(path))
4515
4658
  return null;
4516
- const full = join5(root, path);
4659
+ const full = join6(root, path);
4517
4660
  if (!existsSync3(full))
4518
4661
  return null;
4519
4662
  try {
4520
- const realRoot = realpathSync3(root);
4521
- const realFull = realpathSync3(full);
4522
- const rel = relative2(realRoot, realFull);
4663
+ const realRoot = realpathSync4(root);
4664
+ const realFull = realpathSync4(full);
4665
+ const rel = relative3(realRoot, realFull);
4523
4666
  if (rel === "" || rel.startsWith("..") || rel.startsWith("/") || rel.startsWith("\\")) {
4524
4667
  return null;
4525
4668
  }
@@ -9423,24 +9566,24 @@ Parse failures and unreachable servers exit 1.
9423
9566
 
9424
9567
  // web-src/server/root.ts
9425
9568
  import { existsSync as existsSync4 } from "node:fs";
9426
- import { dirname as dirname3, join as join6, normalize } from "node:path";
9569
+ import { dirname as dirname4, join as join7, normalize } from "node:path";
9427
9570
  import { fileURLToPath } from "node:url";
9428
9571
  function findRoot(start) {
9429
9572
  let current = start;
9430
9573
  for (let i = 0;i < 5; i++) {
9431
- if (existsSync4(join6(current, "package.json")) && existsSync4(join6(current, "web"))) {
9574
+ if (existsSync4(join7(current, "package.json")) && existsSync4(join7(current, "web"))) {
9432
9575
  return normalize(current);
9433
9576
  }
9434
- const parent = dirname3(current);
9577
+ const parent = dirname4(current);
9435
9578
  if (parent === current)
9436
9579
  break;
9437
9580
  current = parent;
9438
9581
  }
9439
- return normalize(join6(start, "..", ".."));
9582
+ return normalize(join7(start, "..", ".."));
9440
9583
  }
9441
9584
  var ROOT;
9442
9585
  var init_root = __esm(() => {
9443
- ROOT = findRoot(dirname3(fileURLToPath(import.meta.url)));
9586
+ ROOT = findRoot(dirname4(fileURLToPath(import.meta.url)));
9444
9587
  });
9445
9588
 
9446
9589
  // web-src/server/skill-cli.ts
@@ -9455,7 +9598,7 @@ __export(exports_skill_cli, {
9455
9598
  });
9456
9599
  import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "node:fs";
9457
9600
  import { homedir as homedir2 } from "node:os";
9458
- import { join as join7, resolve } from "node:path";
9601
+ import { join as join8, resolve } from "node:path";
9459
9602
  function parseAgentList(value) {
9460
9603
  if (value === "all")
9461
9604
  return [...AGENT_NAMES];
@@ -9515,7 +9658,7 @@ function parseSkillArgs(argv) {
9515
9658
  function discoverBundledSkills(skillsRoot) {
9516
9659
  if (!existsSync5(skillsRoot))
9517
9660
  return [];
9518
- return readdirSync2(skillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync5(join7(skillsRoot, entry.name, "SKILL.md"))).map((entry) => entry.name).sort();
9661
+ return readdirSync2(skillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync5(join8(skillsRoot, entry.name, "SKILL.md"))).map((entry) => entry.name).sort();
9519
9662
  }
9520
9663
  function installSkill(args, deps) {
9521
9664
  const skills = discoverBundledSkills(deps.skillsRoot);
@@ -9529,8 +9672,8 @@ function installSkill(args, deps) {
9529
9672
  const results = [];
9530
9673
  for (const agent of args.agents) {
9531
9674
  for (const skill of skills) {
9532
- const sourceDir = join7(deps.skillsRoot, skill);
9533
- const target = join7(base, AGENT_SKILL_DIRS[agent], "skills", skill);
9675
+ const sourceDir = join8(deps.skillsRoot, skill);
9676
+ const target = join8(base, AGENT_SKILL_DIRS[agent], "skills", skill);
9534
9677
  const action = existsSync5(target) ? "updated" : "installed";
9535
9678
  try {
9536
9679
  mkdirSync2(target, { recursive: true });
@@ -9559,7 +9702,7 @@ function runSkillCli(argv) {
9559
9702
  return;
9560
9703
  }
9561
9704
  const result = installSkill(parsed.args, {
9562
- skillsRoot: join7(ROOT, "skills"),
9705
+ skillsRoot: join8(ROOT, "skills"),
9563
9706
  homeDir: homedir2(),
9564
9707
  projectDir: process.cwd()
9565
9708
  });
@@ -14623,11 +14766,11 @@ import {
14623
14766
  existsSync as existsSync6,
14624
14767
  openSync as openSync2,
14625
14768
  readSync as readSync2,
14626
- realpathSync as realpathSync4,
14769
+ realpathSync as realpathSync5,
14627
14770
  statSync as statSync4
14628
14771
  } from "node:fs";
14629
14772
  import { lstat, open, readdir, readFile as readFile2, stat } from "node:fs/promises";
14630
- import { basename, join as join8, relative as relative3 } from "node:path";
14773
+ import { basename, join as join9, relative as relative4 } from "node:path";
14631
14774
  function isSqliteFile(fullPath) {
14632
14775
  try {
14633
14776
  const stat2 = statSync4(fullPath);
@@ -14698,7 +14841,7 @@ async function discoverSqliteFilesAsync(cwd, omitDirNames, signal) {
14698
14841
  return;
14699
14842
  if (omitSet.has(entry.toLowerCase()))
14700
14843
  continue;
14701
- const full = join8(dir, entry);
14844
+ const full = join9(dir, entry);
14702
14845
  let entryStat;
14703
14846
  try {
14704
14847
  entryStat = await lstat(full);
@@ -14715,7 +14858,7 @@ async function discoverSqliteFilesAsync(cwd, omitDirNames, signal) {
14715
14858
  continue;
14716
14859
  if (!await isSqliteFileAsync(full))
14717
14860
  continue;
14718
- const rel = relative3(cwd, full);
14861
+ const rel = relative4(cwd, full);
14719
14862
  if (rel.startsWith("..") || rel.startsWith("/"))
14720
14863
  continue;
14721
14864
  results.push({
@@ -14742,18 +14885,18 @@ function validateDbPath(cwd, dbPath) {
14742
14885
  const parts = dbPath.split(/[\\/]+/);
14743
14886
  if (parts.some((p) => p === ".." || p.toLowerCase() === ".git" || p.toLowerCase() === ".code-viewer"))
14744
14887
  return null;
14745
- const full = join8(cwd, dbPath);
14888
+ const full = join9(cwd, dbPath);
14746
14889
  if (!existsSync6(full))
14747
14890
  return null;
14748
14891
  let realCwd;
14749
14892
  let realFull;
14750
14893
  try {
14751
- realCwd = realpathSync4(cwd);
14752
- realFull = realpathSync4(full);
14894
+ realCwd = realpathSync5(cwd);
14895
+ realFull = realpathSync5(full);
14753
14896
  } catch {
14754
14897
  return null;
14755
14898
  }
14756
- const rel = relative3(realCwd, realFull);
14899
+ const rel = relative4(realCwd, realFull);
14757
14900
  if (rel === "" || rel.startsWith("..") || rel.startsWith("/"))
14758
14901
  return null;
14759
14902
  if (!isSqliteFile(realFull))
@@ -14912,7 +15055,7 @@ function resolveEnvValue(raw, composeDirEnv = {}) {
14912
15055
  }
14913
15056
  async function readDotenvAsync(composeDir) {
14914
15057
  try {
14915
- const content = await readFile2(join8(composeDir, ".env"), "utf-8");
15058
+ const content = await readFile2(join9(composeDir, ".env"), "utf-8");
14916
15059
  return parseDotenvContent(content);
14917
15060
  } catch {
14918
15061
  return {};
@@ -15034,7 +15177,7 @@ function parseComposeContent(content, filepath, composeDir, cwd, composeDirEnv,
15034
15177
  for (let match = serviceRegex.exec(servicesBlock);match !== null; match = serviceRegex.exec(servicesBlock)) {
15035
15178
  servicePositions.push({ name: match[1], start: match.index });
15036
15179
  }
15037
- const relDir = relative3(cwd, composeDir);
15180
+ const relDir = relative4(cwd, composeDir);
15038
15181
  const isRoot = relDir === "" || relDir === ".";
15039
15182
  const relDirSlash = relDir.replace(/\\/g, "/");
15040
15183
  const filename = basename(filepath);
@@ -15139,7 +15282,7 @@ async function walkForMarkerFileAsync(dir, depth, omitSet, hasCapacity, visitDir
15139
15282
  return;
15140
15283
  if (omitSet.has(entry.toLowerCase()))
15141
15284
  continue;
15142
- const full = join8(dir, entry);
15285
+ const full = join9(dir, entry);
15143
15286
  let entryStat;
15144
15287
  try {
15145
15288
  entryStat = await lstat(full);
@@ -15166,7 +15309,7 @@ async function discoverDockerDatabasesAsync(cwd, omitDirNames = [], signal) {
15166
15309
  omitSet.add("node_modules");
15167
15310
  await walkForMarkerFileAsync(cwd, 0, omitSet, () => results.length < MAX_DOCKER_SERVICES, async (dir) => {
15168
15311
  for (const filename of COMPOSE_FILENAMES) {
15169
- const filepath = join8(dir, filename);
15312
+ const filepath = join9(dir, filename);
15170
15313
  if (await pathExistsAsync(filepath)) {
15171
15314
  await parseComposeFileAsync(filepath, dir, cwd, results);
15172
15315
  break;
@@ -15330,7 +15473,7 @@ async function discoverSupabaseCliProjectsAsync(cwd, omitDirNames = [], signal)
15330
15473
  omitSet.add("node_modules");
15331
15474
  const results = [];
15332
15475
  await walkForMarkerFileAsync(cwd, 0, omitSet, () => results.length < MAX_SUPABASE_PROJECTS, async (dir) => {
15333
- const configPath = join8(dir, "supabase", "config.toml");
15476
+ const configPath = join9(dir, "supabase", "config.toml");
15334
15477
  if (!await pathExistsAsync(configPath))
15335
15478
  return;
15336
15479
  try {
@@ -15338,7 +15481,7 @@ async function discoverSupabaseCliProjectsAsync(cwd, omitDirNames = [], signal)
15338
15481
  const parsed = parseSupabaseConfigToml(content);
15339
15482
  if (!parsed)
15340
15483
  return;
15341
- const relDir = relative3(cwd, dir);
15484
+ const relDir = relative4(cwd, dir);
15342
15485
  const isRoot = relDir === "" || relDir === ".";
15343
15486
  const relDirSlash = relDir.replace(/\\/g, "/");
15344
15487
  const id = isRoot ? `supabase:${parsed.projectId}` : `supabase:${parsed.projectId}@${encodeURIComponent(relDirSlash)}`;
@@ -15439,16 +15582,16 @@ function makeId(prefix) {
15439
15582
 
15440
15583
  // web-src/server/worktree-watcher.ts
15441
15584
  import {
15442
- lstatSync as lstatSync2,
15585
+ lstatSync as lstatSync3,
15443
15586
  readdirSync as nodeReaddirSync,
15444
15587
  watch as nodeWatch
15445
15588
  } from "node:fs";
15446
- import { join as join9, relative as relative4 } from "node:path";
15589
+ import { join as join10, relative as relative5 } from "node:path";
15447
15590
  function normalizeRelativePath(path) {
15448
15591
  return path.replace(/\\/g, "/").replace(/^\/+/, "");
15449
15592
  }
15450
15593
  function isInsideRoot(root, path) {
15451
- const rel = relative4(root, path).replace(/\\/g, "/");
15594
+ const rel = relative5(root, path).replace(/\\/g, "/");
15452
15595
  return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
15453
15596
  }
15454
15597
  function startWorktreeUpdateWatch(options) {
@@ -15456,14 +15599,14 @@ function startWorktreeUpdateWatch(options) {
15456
15599
  const readDirs = options.readdirSync || ((path) => nodeReaddirSync(path, { withFileTypes: true }));
15457
15600
  const isDirectory = options.isDirectory || ((path) => {
15458
15601
  try {
15459
- return lstatSync2(path).isDirectory();
15602
+ return lstatSync3(path).isDirectory();
15460
15603
  } catch {
15461
15604
  return false;
15462
15605
  }
15463
15606
  });
15464
15607
  const directorySignature = options.directorySignature || ((path) => {
15465
15608
  try {
15466
- const stats = lstatSync2(path);
15609
+ const stats = lstatSync3(path);
15467
15610
  if (!stats.isDirectory())
15468
15611
  return null;
15469
15612
  return `${stats.dev}:${stats.ino}`;
@@ -15486,7 +15629,7 @@ function startWorktreeUpdateWatch(options) {
15486
15629
  const pendingChangedPaths = new Set;
15487
15630
  let watchLimitReported = false;
15488
15631
  const ignored = (path) => isSkippableSearchPath(normalizeRelativePath(path), options.omitDirNames, options.excludeNames);
15489
- const directoryRelativePath = (dir) => normalizeRelativePath(relative4(options.root, dir));
15632
+ const directoryRelativePath = (dir) => normalizeRelativePath(relative5(options.root, dir));
15490
15633
  const ignoredDirectory = (dir) => {
15491
15634
  const rel = directoryRelativePath(dir);
15492
15635
  return Boolean(rel && ignored(rel));
@@ -15552,7 +15695,7 @@ function startWorktreeUpdateWatch(options) {
15552
15695
  for (const entry of entries) {
15553
15696
  if (!entry.isDirectory())
15554
15697
  continue;
15555
- const child = join9(dir, entry.name);
15698
+ const child = join10(dir, entry.name);
15556
15699
  if (ignoredDirectory(child))
15557
15700
  continue;
15558
15701
  children.push(child);
@@ -15636,10 +15779,10 @@ function startWorktreeUpdateWatch(options) {
15636
15779
  scheduleUpdate();
15637
15780
  return;
15638
15781
  }
15639
- const changed = normalizeRelativePath(join9(rel, filename.toString()));
15782
+ const changed = normalizeRelativePath(join10(rel, filename.toString()));
15640
15783
  if (ignored(changed))
15641
15784
  return;
15642
- const fullChangedPath = join9(options.root, changed);
15785
+ const fullChangedPath = join10(options.root, changed);
15643
15786
  if (!isInsideRoot(options.root, fullChangedPath))
15644
15787
  return;
15645
15788
  if (initialScanAsync) {
@@ -15688,9 +15831,9 @@ var init_worktree_watcher = __esm(() => {
15688
15831
  });
15689
15832
 
15690
15833
  // web-src/server/state-store.ts
15691
- import { join as join10 } from "node:path";
15834
+ import { join as join11 } from "node:path";
15692
15835
  function codeViewerPath(root, fileName) {
15693
- return join10(root, CODE_VIEWER_DIR2, fileName);
15836
+ return join11(root, CODE_VIEWER_DIR2, fileName);
15694
15837
  }
15695
15838
  function isRecord(value) {
15696
15839
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -16806,7 +16949,7 @@ var init_connection_pool = __esm(() => {
16806
16949
  // web-src/server/database/connections-store.ts
16807
16950
  import { randomUUID } from "node:crypto";
16808
16951
  import { chmod } from "node:fs/promises";
16809
- import { join as join11 } from "node:path";
16952
+ import { join as join12 } from "node:path";
16810
16953
  function secretKey(cwd, id) {
16811
16954
  return `${cwd}\x00${id}`;
16812
16955
  }
@@ -16827,7 +16970,7 @@ function withRuntimeSecrets(cwd, connection) {
16827
16970
  };
16828
16971
  }
16829
16972
  function connectionsFilePath(root) {
16830
- return join11(root, ".code-viewer", CONNECTIONS_FILE_NAME);
16973
+ return join12(root, ".code-viewer", CONNECTIONS_FILE_NAME);
16831
16974
  }
16832
16975
  function emptyState() {
16833
16976
  return { version: 1, connections: [] };
@@ -18609,9 +18752,9 @@ var init_handle_s3 = __esm(() => {
18609
18752
  });
18610
18753
 
18611
18754
  // web-src/server/database/query-history.ts
18612
- import { join as join12 } from "node:path";
18755
+ import { join as join13 } from "node:path";
18613
18756
  function historyFilePath(root) {
18614
- return join12(root, CODE_VIEWER_DIR3, HISTORY_FILE_NAME);
18757
+ return join13(root, CODE_VIEWER_DIR3, HISTORY_FILE_NAME);
18615
18758
  }
18616
18759
  function emptyState2() {
18617
18760
  return { version: 1, entries: [] };
@@ -18761,9 +18904,9 @@ var init_query_history = __esm(() => {
18761
18904
  // web-src/server/database/snapshot-store.ts
18762
18905
  import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
18763
18906
  import { mkdirSync as mkdirSync3 } from "node:fs";
18764
- import { join as join13 } from "node:path";
18907
+ import { join as join14 } from "node:path";
18765
18908
  async function getStoreDb(cwd) {
18766
- const dbPath = join13(cwd, CODE_VIEWER_DIR4, SNAPSHOT_DB_NAME);
18909
+ const dbPath = join14(cwd, CODE_VIEWER_DIR4, SNAPSHOT_DB_NAME);
18767
18910
  if (storeDb && storeDbPath === dbPath)
18768
18911
  return storeDb;
18769
18912
  if (storeDb) {
@@ -18771,7 +18914,7 @@ async function getStoreDb(cwd) {
18771
18914
  storeDb.close();
18772
18915
  } catch {}
18773
18916
  }
18774
- mkdirSync3(join13(cwd, CODE_VIEWER_DIR4), { recursive: true });
18917
+ mkdirSync3(join14(cwd, CODE_VIEWER_DIR4), { recursive: true });
18775
18918
  const DbClass = await loadSqliteClass();
18776
18919
  storeDb = new DbClass(dbPath);
18777
18920
  storeDbPath = dbPath;
@@ -19377,9 +19520,9 @@ var init_snapshot_runner = __esm(() => {
19377
19520
  });
19378
19521
 
19379
19522
  // web-src/server/database/tabs-store.ts
19380
- import { join as join14 } from "node:path";
19523
+ import { join as join15 } from "node:path";
19381
19524
  function tabsFilePath(root) {
19382
- return join14(root, CODE_VIEWER_DIR5, TABS_FILE_NAME);
19525
+ return join15(root, CODE_VIEWER_DIR5, TABS_FILE_NAME);
19383
19526
  }
19384
19527
  function emptyState3() {
19385
19528
  return { version: 1, tabs: [], activeTabId: null };
@@ -21316,7 +21459,7 @@ var init_handle = __esm(() => {
21316
21459
 
21317
21460
  // web-src/server/doctor.ts
21318
21461
  import { accessSync as accessSync2, constants as constants2, readFileSync as readFileSync6, statSync as statSync5 } from "node:fs";
21319
- import { dirname as dirname4, join as join15, relative as relative5 } from "node:path";
21462
+ import { dirname as dirname5, join as join16, relative as relative6 } from "node:path";
21320
21463
  import { fileURLToPath as fileURLToPath2 } from "node:url";
21321
21464
  function statusWorse(a, b) {
21322
21465
  const rank = { ok: 0, warn: 1, error: 2 };
@@ -21405,12 +21548,12 @@ function findCodeViewerPackageJson() {
21405
21548
  try {
21406
21549
  let cursor;
21407
21550
  try {
21408
- cursor = dirname4(fileURLToPath2(import.meta.url));
21551
+ cursor = dirname5(fileURLToPath2(import.meta.url));
21409
21552
  } catch {
21410
- cursor = dirname4(process.argv[1] || ".");
21553
+ cursor = dirname5(process.argv[1] || ".");
21411
21554
  }
21412
21555
  for (let depth = 0;depth < 8; depth += 1) {
21413
- const candidate = join15(cursor, "package.json");
21556
+ const candidate = join16(cursor, "package.json");
21414
21557
  try {
21415
21558
  const raw = readFileSync6(candidate, "utf8");
21416
21559
  const pkg = JSON.parse(raw);
@@ -21418,7 +21561,7 @@ function findCodeViewerPackageJson() {
21418
21561
  return { version: pkg.version, path: candidate };
21419
21562
  }
21420
21563
  } catch {}
21421
- const next = dirname4(cursor);
21564
+ const next = dirname5(cursor);
21422
21565
  if (next === cursor)
21423
21566
  break;
21424
21567
  cursor = next;
@@ -21506,7 +21649,7 @@ async function checkSqlite(cwd) {
21506
21649
  return { id: "sqlite", title: "SQLite driver", rows };
21507
21650
  }
21508
21651
  async function trySnapshotDbOpen(cwd) {
21509
- const dbPath = join15(cwd, SNAPSHOT_DB_REL);
21652
+ const dbPath = join16(cwd, SNAPSHOT_DB_REL);
21510
21653
  try {
21511
21654
  statSync5(dbPath);
21512
21655
  } catch {
@@ -21527,8 +21670,8 @@ async function trySnapshotDbOpen(cwd) {
21527
21670
  }
21528
21671
  }
21529
21672
  function checkSnapshotStore(cwd) {
21530
- const dbPath = join15(cwd, SNAPSHOT_DB_REL);
21531
- const dir = dirname4(dbPath);
21673
+ const dbPath = join16(cwd, SNAPSHOT_DB_REL);
21674
+ const dir = dirname5(dbPath);
21532
21675
  let dirStatus = "ok";
21533
21676
  let dirDetail = dir;
21534
21677
  let dirHint;
@@ -21601,7 +21744,7 @@ async function checkGit(cwd, signal) {
21601
21744
  if (repoCheck && repoCheck.code === 0 && /true/.test(repoCheck.stdout)) {
21602
21745
  const topRes = await runCached(gitCache, TTL.gitRepo, commandForExternal("git"), ["rev-parse", "--show-toplevel"], TIMEOUT.git, signal, cwd);
21603
21746
  const top = topRes?.stdout.trim() || cwd;
21604
- const insideCwd = relative5(top, cwd) || ".";
21747
+ const insideCwd = relative6(top, cwd) || ".";
21605
21748
  rows.push({
21606
21749
  id: "git.repo",
21607
21750
  title: "Working tree",
@@ -22529,44 +22672,6 @@ function normalizeNewDirectoryName(name) {
22529
22672
  return trimmed;
22530
22673
  }
22531
22674
 
22532
- // web-src/server/cache.ts
22533
- import { lstatSync as lstatSync3 } from "node:fs";
22534
- import { join as join16 } from "node:path";
22535
- function cacheFresh(cached, now = Date.now(), ttlMs = CACHE_TTL_MS) {
22536
- return !!cached && now - cached.storedAt <= ttlMs;
22537
- }
22538
- function setTimedCacheEntry(cache, key, value, now = Date.now(), maxEntries = MAX_TIMED_CACHE_ENTRIES) {
22539
- cache.set(key, { ...value, storedAt: now });
22540
- while (cache.size > maxEntries) {
22541
- const oldest = cache.keys().next().value;
22542
- if (oldest === undefined)
22543
- break;
22544
- cache.delete(oldest);
22545
- }
22546
- }
22547
- function worktreeFileSignature(path, cwd) {
22548
- try {
22549
- const stats = lstatSync3(join16(cwd, path));
22550
- const inode = "ino" in stats ? stats.ino : 0;
22551
- return `state:file|size:${stats.size}|mtime:${stats.mtimeMs}|ctime:${stats.ctimeMs}|ino:${inode}`;
22552
- } catch {
22553
- return "state:missing";
22554
- }
22555
- }
22556
- function fileDiffCacheKey(options) {
22557
- const worktreeTarget = options.range.from === "worktree" || !options.range.to || options.range.to === "worktree";
22558
- if (options.isUntracked && !worktreeTarget) {
22559
- throw new Error("untracked file diffs require a worktree range");
22560
- }
22561
- const signature = worktreeTarget ? `\x00${worktreeFileSignature(options.path, options.cwd)}` : "";
22562
- if (options.isUntracked) {
22563
- return `u\x00${options.path}${signature}\x00${options.extras.join("\x00")}`;
22564
- }
22565
- return `t\x00${options.path}\x00${options.oldPath || ""}${signature}\x00${[...options.extras, ...options.args].join("\x00")}`;
22566
- }
22567
- var CACHE_TTL_MS = 1500, MAX_TIMED_CACHE_ENTRIES = 200;
22568
- var init_cache = () => {};
22569
-
22570
22675
  // web-src/server/dev-assets.ts
22571
22676
  import { basename as basename2 } from "node:path";
22572
22677
  function startDevAssetReload(options) {
@@ -23229,8 +23334,8 @@ var init_journal2 = __esm(() => {
23229
23334
  });
23230
23335
 
23231
23336
  // web-src/server/search-service.ts
23232
- import { existsSync as existsSync7, lstatSync as lstatSync4, readFileSync as readFileSync7, realpathSync as realpathSync5 } from "node:fs";
23233
- import { join as join18, relative as relative6 } from "node:path";
23337
+ import { existsSync as existsSync7, lstatSync as lstatSync4, readFileSync as readFileSync7, realpathSync as realpathSync6 } from "node:fs";
23338
+ import { join as join18, relative as relative7 } from "node:path";
23234
23339
  async function rgAvailableAsync(cwd) {
23235
23340
  if (rgAvailableCache !== null)
23236
23341
  return rgAvailableCache;
@@ -23266,12 +23371,12 @@ function safeWorktreePath(env, path) {
23266
23371
  let realCwd;
23267
23372
  let realFull;
23268
23373
  try {
23269
- realCwd = realpathSync5(env.cwd);
23270
- realFull = realpathSync5(full);
23374
+ realCwd = realpathSync6(env.cwd);
23375
+ realFull = realpathSync6(full);
23271
23376
  } catch {
23272
23377
  return null;
23273
23378
  }
23274
- const rel = relative6(realCwd, realFull);
23379
+ const rel = relative7(realCwd, realFull);
23275
23380
  if (rel === "" || rel.startsWith("..") || rel.startsWith("/") || rel.startsWith("\\"))
23276
23381
  return null;
23277
23382
  if (isGitInternalPath(rel))
@@ -25015,7 +25120,7 @@ import {
25015
25120
  mkdirSync as mkdirSync4,
25016
25121
  openSync as openSync3,
25017
25122
  readFileSync as readFileSync9,
25018
- realpathSync as realpathSync6,
25123
+ realpathSync as realpathSync7,
25019
25124
  renameSync,
25020
25125
  statSync as statSync6,
25021
25126
  unlinkSync as unlinkSync2,
@@ -25023,7 +25128,7 @@ import {
25023
25128
  writeFileSync as writeFileSync2
25024
25129
  } from "node:fs";
25025
25130
  import { homedir as homedir3 } from "node:os";
25026
- import { basename as basename3, dirname as dirname5, extname as extname2, join as join20, relative as relative7 } from "node:path";
25131
+ import { basename as basename3, dirname as dirname6, extname as extname2, join as join20, relative as relative8 } from "node:path";
25027
25132
  function parseCli() {
25028
25133
  const rest = [];
25029
25134
  for (let i = 2;i < process.argv.length; i++) {
@@ -25077,7 +25182,7 @@ Examples:
25077
25182
  process.exit(1);
25078
25183
  }
25079
25184
  try {
25080
- cwd = realpathSync6(next);
25185
+ cwd = realpathSync7(next);
25081
25186
  cwdWasExplicit = true;
25082
25187
  } catch {
25083
25188
  console.error("--cwd must point to an existing directory");
@@ -25508,7 +25613,7 @@ function worktreePath(path) {
25508
25613
  function safeOpenWorktreePath(path) {
25509
25614
  if (path === "") {
25510
25615
  try {
25511
- const realCwd = realpathSync6(cwd);
25616
+ const realCwd = realpathSync7(cwd);
25512
25617
  if (isGitInternalPath(realCwd))
25513
25618
  return null;
25514
25619
  return realCwd;
@@ -25519,7 +25624,7 @@ function safeOpenWorktreePath(path) {
25519
25624
  return safeWorktreePath2(path);
25520
25625
  }
25521
25626
  function parentRepoPath(path) {
25522
- const parent = dirname5(path);
25627
+ const parent = dirname6(path);
25523
25628
  return parent === "." ? "" : parent;
25524
25629
  }
25525
25630
  function isoDate(ms) {
@@ -25577,6 +25682,21 @@ async function attachTreeEntryMetadata(target, entry) {
25577
25682
  return { ...entry, ...await directoryMetadata(target, entry.path) };
25578
25683
  if (entry.type !== "blob")
25579
25684
  return entry;
25685
+ if (entry.is_symlink && target !== "worktree" && target !== "") {
25686
+ const symlinkMeta = await gitSymlinkTargetMetadataAsync(target, entry.path, cwd);
25687
+ if (symlinkMeta.symlink_target_type === "tree")
25688
+ return {
25689
+ ...entry,
25690
+ ...symlinkMeta,
25691
+ type: "tree",
25692
+ ...await directoryMetadata(target, entry.path)
25693
+ };
25694
+ return {
25695
+ ...entry,
25696
+ ...symlinkMeta,
25697
+ ...await fileMetadataForTarget(target, entry.path)
25698
+ };
25699
+ }
25580
25700
  return { ...entry, ...await fileMetadataForTarget(target, entry.path) };
25581
25701
  }
25582
25702
  async function readReadme(target, dirPath) {
@@ -25599,6 +25719,22 @@ async function readReadme(target, dirPath) {
25599
25719
  }
25600
25720
  return null;
25601
25721
  }
25722
+ function deletedTreeEntriesForPath(statusMap, basePath) {
25723
+ const entries = [];
25724
+ for (const [path, status] of statusMap) {
25725
+ if (status !== "D")
25726
+ continue;
25727
+ if (basePath) {
25728
+ if (!path.startsWith(`${basePath}/`))
25729
+ continue;
25730
+ }
25731
+ const rel = basePath ? path.slice(basePath.length + 1) : path;
25732
+ if (!rel || rel.includes("/"))
25733
+ continue;
25734
+ entries.push({ name: rel, path, type: "blob", status: "D" });
25735
+ }
25736
+ return entries;
25737
+ }
25602
25738
  async function handleTree(url) {
25603
25739
  const target = url.searchParams.get("ref") || url.searchParams.get("target") || "worktree";
25604
25740
  const path = (url.searchParams.get("path") || "").replace(/^\/+|\/+$/g, "");
@@ -25625,12 +25761,21 @@ async function handleTree(url) {
25625
25761
  if (tree.error)
25626
25762
  return text(tree.error, tree.status ?? 500);
25627
25763
  const entries = tree.entries.filter((entry) => !isExcludedScopePath(entry.path, excludeNames));
25764
+ const statusMap = target === "worktree" || target === "" ? await repoStatusMapAsync(cwd) : null;
25765
+ const withStatus = (entry) => {
25766
+ const status = statusMap?.get(entry.path);
25767
+ return status ? { ...entry, status } : entry;
25768
+ };
25769
+ const deletedEntries = !recursive && statusMap ? deletedTreeEntriesForPath(statusMap, path) : [];
25628
25770
  return json2({
25629
25771
  ref: target,
25630
25772
  path,
25631
25773
  project: basename3(cwd),
25632
25774
  branch: await currentBranchMetadata(),
25633
- entries: recursive ? entries : await Promise.all(entries.map((entry) => attachTreeEntryMetadata(target, entry))),
25775
+ entries: recursive ? entries.map(withStatus) : [
25776
+ ...await Promise.all(entries.map((entry) => attachTreeEntryMetadata(target, entry).then(withStatus))),
25777
+ ...deletedEntries
25778
+ ],
25634
25779
  readme: await readReadme(target, path),
25635
25780
  upload_enabled: uploadEnabled && (target === "worktree" || target === "")
25636
25781
  });
@@ -26326,7 +26471,7 @@ async function handleUploadFiles(req) {
26326
26471
  if (total > MAX_UPLOAD_TOTAL_BYTES)
26327
26472
  return text("upload too large", 413);
26328
26473
  const target = join20(realDir, safeName);
26329
- if (relative7(realDir, dirname5(target)) !== "")
26474
+ if (relative8(realDir, dirname6(target)) !== "")
26330
26475
  return text("invalid filename", 400);
26331
26476
  if (existsSync8(target))
26332
26477
  return text("file exists", 409);
@@ -26492,10 +26637,10 @@ async function restoreTrashPath(originalPath, trashPath) {
26492
26637
  return { ok: false, error: "trash item not found" };
26493
26638
  try {
26494
26639
  const trashRoot = join20(homedir3(), ".Trash");
26495
- const trashRelative = relative7(trashRoot, trashPath);
26640
+ const trashRelative = relative8(trashRoot, trashPath);
26496
26641
  if (trashRelative === "" || trashRelative.startsWith("..") || trashRelative.startsWith("/") || trashRelative.startsWith("\\"))
26497
26642
  return { ok: false, error: "invalid trash handle" };
26498
- mkdirSync4(dirname5(original), { recursive: true });
26643
+ mkdirSync4(dirname6(original), { recursive: true });
26499
26644
  renameSync(trashPath, original);
26500
26645
  return { ok: true };
26501
26646
  } catch (error) {