@youtyan/code-viewer 0.8.1 → 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.
- package/README.md +13 -4
- package/dist/code-viewer.js +433 -180
- package/package.json +1 -1
- package/web/app.js +418 -133
- package/web/style.css +92 -24
package/dist/code-viewer.js
CHANGED
|
@@ -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
|
|
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(
|
|
844
|
+
statSync(join3(current, ".git"));
|
|
807
845
|
return realpathSync(current);
|
|
808
846
|
} catch {}
|
|
809
847
|
const parent = dirname2(current);
|
|
@@ -835,6 +873,110 @@ var init_command_resolver = __esm(() => {
|
|
|
835
873
|
activeOverrides = new Map;
|
|
836
874
|
});
|
|
837
875
|
|
|
876
|
+
// web-src/server/name-pattern.ts
|
|
877
|
+
function parseGlobSegment(pattern) {
|
|
878
|
+
const matchers = [];
|
|
879
|
+
for (let i = 0;i < pattern.length; i++) {
|
|
880
|
+
const ch = pattern[i];
|
|
881
|
+
if (ch === "*") {
|
|
882
|
+
matchers.push({ kind: "star" });
|
|
883
|
+
} else if (ch === "?") {
|
|
884
|
+
matchers.push({ kind: "any" });
|
|
885
|
+
} else if (ch === "[") {
|
|
886
|
+
const close = pattern.indexOf("]", i + 1);
|
|
887
|
+
if (close === -1) {
|
|
888
|
+
matchers.push({ kind: "literal", ch: "[" });
|
|
889
|
+
continue;
|
|
890
|
+
}
|
|
891
|
+
const rawBody = pattern.slice(i + 1, close);
|
|
892
|
+
const negate = rawBody.startsWith("!");
|
|
893
|
+
matchers.push({
|
|
894
|
+
kind: "class",
|
|
895
|
+
body: negate ? rawBody.slice(1) : rawBody,
|
|
896
|
+
negate
|
|
897
|
+
});
|
|
898
|
+
i = close;
|
|
899
|
+
} else {
|
|
900
|
+
matchers.push({ kind: "literal", ch });
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
return matchers;
|
|
904
|
+
}
|
|
905
|
+
function charInClassBody(ch, body) {
|
|
906
|
+
for (let i = 0;i < body.length; ) {
|
|
907
|
+
if (body[i + 1] === "-" && i + 2 < body.length) {
|
|
908
|
+
if (ch >= body[i] && ch <= body[i + 2])
|
|
909
|
+
return true;
|
|
910
|
+
i += 3;
|
|
911
|
+
} else {
|
|
912
|
+
if (ch === body[i])
|
|
913
|
+
return true;
|
|
914
|
+
i += 1;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
return false;
|
|
918
|
+
}
|
|
919
|
+
function matchesAt(matcher, ch) {
|
|
920
|
+
switch (matcher.kind) {
|
|
921
|
+
case "literal":
|
|
922
|
+
return matcher.ch === ch;
|
|
923
|
+
case "any":
|
|
924
|
+
return true;
|
|
925
|
+
case "class":
|
|
926
|
+
return charInClassBody(ch, matcher.body) !== matcher.negate;
|
|
927
|
+
case "star":
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function matchGlobSegment(matchers, name) {
|
|
932
|
+
let mi = 0;
|
|
933
|
+
let ni = 0;
|
|
934
|
+
let starMi = -1;
|
|
935
|
+
let starNi = -1;
|
|
936
|
+
while (ni < name.length) {
|
|
937
|
+
const matcher = matchers[mi];
|
|
938
|
+
if (matcher && matcher.kind === "star") {
|
|
939
|
+
starMi = mi;
|
|
940
|
+
starNi = ni;
|
|
941
|
+
mi++;
|
|
942
|
+
} else if (matcher && matchesAt(matcher, name[ni])) {
|
|
943
|
+
mi++;
|
|
944
|
+
ni++;
|
|
945
|
+
} else if (starMi !== -1) {
|
|
946
|
+
mi = starMi + 1;
|
|
947
|
+
starNi++;
|
|
948
|
+
ni = starNi;
|
|
949
|
+
} else {
|
|
950
|
+
return false;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
while (matchers[mi]?.kind === "star")
|
|
954
|
+
mi++;
|
|
955
|
+
return mi === matchers.length;
|
|
956
|
+
}
|
|
957
|
+
function compileNamePatterns(patterns) {
|
|
958
|
+
const literals = new Set;
|
|
959
|
+
const globs = [];
|
|
960
|
+
for (const pattern of patterns) {
|
|
961
|
+
const lower = pattern.toLowerCase();
|
|
962
|
+
if (GLOB_CHARS.test(lower)) {
|
|
963
|
+
globs.push(parseGlobSegment(lower));
|
|
964
|
+
} else {
|
|
965
|
+
literals.add(lower);
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return {
|
|
969
|
+
matches(name) {
|
|
970
|
+
const lower = name.toLowerCase();
|
|
971
|
+
return literals.has(lower) || globs.some((matchers) => matchGlobSegment(matchers, lower));
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
var GLOB_CHARS;
|
|
976
|
+
var init_name_pattern = __esm(() => {
|
|
977
|
+
GLOB_CHARS = /[*?[\]]/;
|
|
978
|
+
});
|
|
979
|
+
|
|
838
980
|
// web-src/server/runtime.ts
|
|
839
981
|
import { spawn, spawnSync } from "node:child_process";
|
|
840
982
|
import { createReadStream, promises as fs } from "node:fs";
|
|
@@ -1113,14 +1255,16 @@ var init_runtime = () => {};
|
|
|
1113
1255
|
import {
|
|
1114
1256
|
closeSync,
|
|
1115
1257
|
existsSync,
|
|
1116
|
-
lstatSync,
|
|
1258
|
+
lstatSync as lstatSync2,
|
|
1117
1259
|
openSync,
|
|
1118
1260
|
readdirSync,
|
|
1119
1261
|
readFileSync,
|
|
1262
|
+
readlinkSync,
|
|
1120
1263
|
readSync,
|
|
1264
|
+
realpathSync as realpathSync2,
|
|
1121
1265
|
statSync as statSync2
|
|
1122
1266
|
} from "node:fs";
|
|
1123
|
-
import { join as
|
|
1267
|
+
import { dirname as dirname3, join as join4, posix, relative as relative2 } from "node:path";
|
|
1124
1268
|
function normalizeBlameRef(ref, base) {
|
|
1125
1269
|
const rawRef = ref || "worktree";
|
|
1126
1270
|
if (base === "worktree" && rawRef !== "worktree") {
|
|
@@ -1218,12 +1362,76 @@ async function statusPorcelainForPathAsync(path, cwd) {
|
|
|
1218
1362
|
error: gitFailureMessage(res, "git status failed")
|
|
1219
1363
|
};
|
|
1220
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
|
+
}
|
|
1221
1404
|
function show(ref, path, cwd) {
|
|
1222
1405
|
return run(["git", "show", `${ref}:${path}`], cwd);
|
|
1223
1406
|
}
|
|
1224
1407
|
function showAsync(ref, path, cwd) {
|
|
1225
1408
|
return runGitAsync(["git", "show", `${ref}:${path}`], cwd);
|
|
1226
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
|
+
}
|
|
1227
1435
|
function catFileBlobStream(oid, cwd) {
|
|
1228
1436
|
return spawnStream(resolveGitArgs(["git", "cat-file", "blob", oid]), cwd);
|
|
1229
1437
|
}
|
|
@@ -1854,7 +2062,7 @@ function isGitInternalPath(path) {
|
|
|
1854
2062
|
return pathHasSegment(path, ".git");
|
|
1855
2063
|
}
|
|
1856
2064
|
function syntheticUncommittedBlameFromWorktree(cwd, path) {
|
|
1857
|
-
const filePath =
|
|
2065
|
+
const filePath = join4(cwd, path);
|
|
1858
2066
|
try {
|
|
1859
2067
|
const stat = statSync2(filePath);
|
|
1860
2068
|
if (!stat.isFile())
|
|
@@ -2110,10 +2318,10 @@ function sortTreeEntries(entries) {
|
|
|
2110
2318
|
function omittedWorktreeDirectoryReason(name, omitDirNames) {
|
|
2111
2319
|
if (name === ".git")
|
|
2112
2320
|
return "internal";
|
|
2113
|
-
return omitDirNames.
|
|
2321
|
+
return omitDirNames.matches(name) ? "heavy" : undefined;
|
|
2114
2322
|
}
|
|
2115
2323
|
function worktreeSubmodulePaths(cwd) {
|
|
2116
|
-
if (!existsSync(
|
|
2324
|
+
if (!existsSync(join4(cwd, ".gitmodules")))
|
|
2117
2325
|
return new Set;
|
|
2118
2326
|
const res = run(["git", "config", "--file", ".gitmodules", "--get-regexp", "\\.path$"], cwd);
|
|
2119
2327
|
if (res.code !== 0)
|
|
@@ -2125,7 +2333,7 @@ function worktreeSubmodulePaths(cwd) {
|
|
|
2125
2333
|
}).filter(Boolean));
|
|
2126
2334
|
}
|
|
2127
2335
|
async function worktreeSubmodulePathsAsync(cwd) {
|
|
2128
|
-
if (!existsSync(
|
|
2336
|
+
if (!existsSync(join4(cwd, ".gitmodules")))
|
|
2129
2337
|
return new Set;
|
|
2130
2338
|
const res = await runGitAsync(["git", "config", "--file", ".gitmodules", "--get-regexp", "\\.path$"], cwd);
|
|
2131
2339
|
if (res.code !== 0)
|
|
@@ -2136,18 +2344,67 @@ async function worktreeSubmodulePathsAsync(cwd) {
|
|
|
2136
2344
|
return split >= 0 ? normalizeTreePath(line.slice(split + 1)) : "";
|
|
2137
2345
|
}).filter(Boolean));
|
|
2138
2346
|
}
|
|
2139
|
-
function
|
|
2140
|
-
|
|
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) {
|
|
2389
|
+
if (excludeNames.matches(name))
|
|
2141
2390
|
return {
|
|
2142
2391
|
name,
|
|
2143
2392
|
path: "",
|
|
2144
2393
|
type: isDirectory ? "tree" : "blob"
|
|
2145
2394
|
};
|
|
2146
2395
|
const entryPath = base ? `${base}/${name}` : name;
|
|
2147
|
-
const
|
|
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";
|
|
2148
2399
|
const omittedReason = type === "tree" ? omittedWorktreeDirectoryReason(name, omitDirNames) : undefined;
|
|
2149
2400
|
const submodule = type === "commit" && submodulePaths.has(entryPath) ? true : undefined;
|
|
2150
|
-
const baseEntry =
|
|
2401
|
+
const baseEntry = {
|
|
2402
|
+
name,
|
|
2403
|
+
path: entryPath,
|
|
2404
|
+
type,
|
|
2405
|
+
...submodule ? { submodule } : {},
|
|
2406
|
+
...symlinkInfo ? { is_symlink: true, ...symlinkInfo } : {}
|
|
2407
|
+
};
|
|
2151
2408
|
return omittedReason ? {
|
|
2152
2409
|
...baseEntry,
|
|
2153
2410
|
children_omitted: true,
|
|
@@ -2156,14 +2413,16 @@ function worktreeEntryFromDirent(base, dir, name, isDirectory, omitDirNames, exc
|
|
|
2156
2413
|
}
|
|
2157
2414
|
function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_WORKTREE_OMIT_DIR_NAMES, excludeNames = []) {
|
|
2158
2415
|
const base = normalizeTreePath(path);
|
|
2159
|
-
const root =
|
|
2160
|
-
|
|
2161
|
-
|
|
2416
|
+
const root = join4(cwd, base);
|
|
2417
|
+
if (realpathWithinRepo(cwd, root, true) === null)
|
|
2418
|
+
return [];
|
|
2419
|
+
const omitDirNameSet = compileNamePatterns(omitDirNames);
|
|
2420
|
+
const excludeNameSet = compileNamePatterns(excludeNames);
|
|
2162
2421
|
const submodulePaths = worktreeSubmodulePaths(cwd);
|
|
2163
2422
|
let directEntries;
|
|
2164
2423
|
try {
|
|
2165
2424
|
const dirents = readdirSync(root, { withFileTypes: true });
|
|
2166
|
-
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));
|
|
2167
2426
|
} catch {
|
|
2168
2427
|
return [];
|
|
2169
2428
|
}
|
|
@@ -2200,10 +2459,10 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
|
|
|
2200
2459
|
return;
|
|
2201
2460
|
}
|
|
2202
2461
|
for (const entry of entries) {
|
|
2203
|
-
if (excludeNameSet.
|
|
2462
|
+
if (excludeNameSet.matches(entry.name))
|
|
2204
2463
|
continue;
|
|
2205
2464
|
const entryPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
2206
|
-
const full =
|
|
2465
|
+
const full = join4(dir, entry.name);
|
|
2207
2466
|
if (entry.isDirectory()) {
|
|
2208
2467
|
const omittedReason = omittedWorktreeDirectoryReason(entry.name, omitDirNameSet);
|
|
2209
2468
|
if (omittedReason) {
|
|
@@ -2221,11 +2480,7 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
|
|
|
2221
2480
|
continue;
|
|
2222
2481
|
walk(full, entryPath, depth + 1);
|
|
2223
2482
|
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
2224
|
-
if (!pushRecursiveEntry(
|
|
2225
|
-
name: entry.name,
|
|
2226
|
-
path: entryPath,
|
|
2227
|
-
type: "blob"
|
|
2228
|
-
}))
|
|
2483
|
+
if (!pushRecursiveEntry(recursiveWorktreeFileEntry(cwd, full, entry.name, entryPath, entry.isSymbolicLink())))
|
|
2229
2484
|
return;
|
|
2230
2485
|
}
|
|
2231
2486
|
}
|
|
@@ -2235,14 +2490,16 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
|
|
|
2235
2490
|
}
|
|
2236
2491
|
async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames = DEFAULT_WORKTREE_OMIT_DIR_NAMES, excludeNames = []) {
|
|
2237
2492
|
const base = normalizeTreePath(path);
|
|
2238
|
-
const root =
|
|
2239
|
-
|
|
2240
|
-
|
|
2493
|
+
const root = join4(cwd, base);
|
|
2494
|
+
if (realpathWithinRepo(cwd, root, true) === null)
|
|
2495
|
+
return [];
|
|
2496
|
+
const omitDirNameSet = compileNamePatterns(omitDirNames);
|
|
2497
|
+
const excludeNameSet = compileNamePatterns(excludeNames);
|
|
2241
2498
|
const submodulePaths = await worktreeSubmodulePathsAsync(cwd);
|
|
2242
2499
|
let directEntries;
|
|
2243
2500
|
try {
|
|
2244
2501
|
const dirents = readdirSync(root, { withFileTypes: true });
|
|
2245
|
-
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));
|
|
2246
2503
|
} catch {
|
|
2247
2504
|
return [];
|
|
2248
2505
|
}
|
|
@@ -2287,10 +2544,10 @@ async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames
|
|
|
2287
2544
|
return;
|
|
2288
2545
|
}
|
|
2289
2546
|
for (const entry of entries) {
|
|
2290
|
-
if (excludeNameSet.
|
|
2547
|
+
if (excludeNameSet.matches(entry.name))
|
|
2291
2548
|
continue;
|
|
2292
2549
|
const entryPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
2293
|
-
const full =
|
|
2550
|
+
const full = join4(dir, entry.name);
|
|
2294
2551
|
if (entry.isDirectory()) {
|
|
2295
2552
|
const omittedReason = omittedWorktreeDirectoryReason(entry.name, omitDirNameSet);
|
|
2296
2553
|
if (omittedReason) {
|
|
@@ -2308,11 +2565,7 @@ async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames
|
|
|
2308
2565
|
continue;
|
|
2309
2566
|
await walk(full, entryPath, depth + 1);
|
|
2310
2567
|
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
2311
|
-
if (!pushRecursiveEntry(
|
|
2312
|
-
name: entry.name,
|
|
2313
|
-
path: entryPath,
|
|
2314
|
-
type: "blob"
|
|
2315
|
-
}))
|
|
2568
|
+
if (!pushRecursiveEntry(recursiveWorktreeFileEntry(cwd, full, entry.name, entryPath, entry.isSymbolicLink())))
|
|
2316
2569
|
return;
|
|
2317
2570
|
}
|
|
2318
2571
|
}
|
|
@@ -2322,12 +2575,24 @@ async function worktreeFilesystemEntriesAsync(cwd, path, recursive, omitDirNames
|
|
|
2322
2575
|
}
|
|
2323
2576
|
function hasDotGitEntry(dir) {
|
|
2324
2577
|
try {
|
|
2325
|
-
|
|
2578
|
+
lstatSync2(join4(dir, ".git"));
|
|
2326
2579
|
return true;
|
|
2327
2580
|
} catch (err) {
|
|
2328
2581
|
return !!err && typeof err === "object" && "code" in err && err.code !== "ENOENT";
|
|
2329
2582
|
}
|
|
2330
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
|
+
}
|
|
2331
2596
|
function gitTreeEntries(ref, path, cwd, recursive) {
|
|
2332
2597
|
const base = normalizeTreePath(path);
|
|
2333
2598
|
const args = ["git", "-c", "core.quotepath=false", "ls-tree"];
|
|
@@ -2340,17 +2605,7 @@ function gitTreeEntries(ref, path, cwd, recursive) {
|
|
|
2340
2605
|
if (res.code !== 0)
|
|
2341
2606
|
return { code: res.code, entries: [], stderr: res.stderr };
|
|
2342
2607
|
const allowedTypes = recursive ? "blob|commit" : "tree|blob|commit";
|
|
2343
|
-
let entries = res.stdout.split("\x00").filter(Boolean).map((rec) =>
|
|
2344
|
-
const match = rec.match(new RegExp(`^\\d+\\s+(${allowedTypes})\\s+[0-9a-fA-F]+\\t(.+)$`));
|
|
2345
|
-
if (!match)
|
|
2346
|
-
return null;
|
|
2347
|
-
const entryPath = match[2];
|
|
2348
|
-
return {
|
|
2349
|
-
name: entryPath.split("/").pop() || entryPath,
|
|
2350
|
-
path: entryPath,
|
|
2351
|
-
type: match[1]
|
|
2352
|
-
};
|
|
2353
|
-
}).filter((entry) => !!entry);
|
|
2608
|
+
let entries = res.stdout.split("\x00").filter(Boolean).map((rec) => parseLsTreeRecord(rec, allowedTypes)).filter((entry) => !!entry);
|
|
2354
2609
|
if (recursive)
|
|
2355
2610
|
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
2356
2611
|
else
|
|
@@ -2369,17 +2624,7 @@ async function gitTreeEntriesAsync(ref, path, cwd, recursive) {
|
|
|
2369
2624
|
if (res.code !== 0)
|
|
2370
2625
|
return { code: res.code, entries: [], stderr: res.stderr };
|
|
2371
2626
|
const allowedTypes = recursive ? "blob|commit" : "tree|blob|commit";
|
|
2372
|
-
let entries = res.stdout.split("\x00").filter(Boolean).map((rec) =>
|
|
2373
|
-
const match = rec.match(new RegExp(`^\\d+\\s+(${allowedTypes})\\s+[0-9a-fA-F]+\\t(.+)$`));
|
|
2374
|
-
if (!match)
|
|
2375
|
-
return null;
|
|
2376
|
-
const entryPath = match[2];
|
|
2377
|
-
return {
|
|
2378
|
-
name: entryPath.split("/").pop() || entryPath,
|
|
2379
|
-
path: entryPath,
|
|
2380
|
-
type: match[1]
|
|
2381
|
-
};
|
|
2382
|
-
}).filter((entry) => !!entry);
|
|
2627
|
+
let entries = res.stdout.split("\x00").filter(Boolean).map((rec) => parseLsTreeRecord(rec, allowedTypes)).filter((entry) => !!entry);
|
|
2383
2628
|
if (recursive)
|
|
2384
2629
|
entries.sort((a, b) => a.path.localeCompare(b.path));
|
|
2385
2630
|
else
|
|
@@ -2443,7 +2688,7 @@ async function listTreeResultAsync(ref, path, cwd, options = {}) {
|
|
|
2443
2688
|
}
|
|
2444
2689
|
function untrackedMeta(cwd) {
|
|
2445
2690
|
return untracked(cwd).flatMap((path) => {
|
|
2446
|
-
const full =
|
|
2691
|
+
const full = join4(cwd, path);
|
|
2447
2692
|
let fileExists = false;
|
|
2448
2693
|
try {
|
|
2449
2694
|
fileExists = existsSync(full) && statSync2(full).isFile();
|
|
@@ -2475,7 +2720,7 @@ function untrackedMeta(cwd) {
|
|
|
2475
2720
|
async function untrackedMetaAsync(cwd) {
|
|
2476
2721
|
const paths = await untrackedAsync(cwd);
|
|
2477
2722
|
return paths.flatMap((path) => {
|
|
2478
|
-
const full =
|
|
2723
|
+
const full = join4(cwd, path);
|
|
2479
2724
|
let fileExists = false;
|
|
2480
2725
|
try {
|
|
2481
2726
|
fileExists = existsSync(full) && statSync2(full).isFile();
|
|
@@ -2723,9 +2968,11 @@ function truncateToNHunks(diffText, n, maxLines = Number.POSITIVE_INFINITY) {
|
|
|
2723
2968
|
lineTruncated
|
|
2724
2969
|
};
|
|
2725
2970
|
}
|
|
2726
|
-
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";
|
|
2727
2972
|
var init_git = __esm(() => {
|
|
2973
|
+
init_cache();
|
|
2728
2974
|
init_command_resolver();
|
|
2975
|
+
init_name_pattern();
|
|
2729
2976
|
init_runtime();
|
|
2730
2977
|
ALWAYS_WORKTREE_OMIT_DIR_NAMES = [".devbox", ".direnv"];
|
|
2731
2978
|
DEFAULT_WORKTREE_OMIT_DIR_NAMES = [
|
|
@@ -2772,6 +3019,7 @@ var init_git = __esm(() => {
|
|
|
2772
3019
|
"bin",
|
|
2773
3020
|
"obj"
|
|
2774
3021
|
];
|
|
3022
|
+
repoStatusMapCache = new Map;
|
|
2775
3023
|
});
|
|
2776
3024
|
|
|
2777
3025
|
// web-src/server/server-registry.ts
|
|
@@ -2784,16 +3032,16 @@ import {
|
|
|
2784
3032
|
writeFileSync
|
|
2785
3033
|
} from "node:fs";
|
|
2786
3034
|
import { homedir } from "node:os";
|
|
2787
|
-
import { join as
|
|
3035
|
+
import { join as join5 } from "node:path";
|
|
2788
3036
|
function registryDir() {
|
|
2789
3037
|
const override = process.env.CODE_VIEWER_TEST_SERVER_REGISTRY_DIR;
|
|
2790
3038
|
if (override)
|
|
2791
3039
|
return override;
|
|
2792
|
-
return
|
|
3040
|
+
return join5(homedir(), ".cache", "code-viewer", "servers");
|
|
2793
3041
|
}
|
|
2794
3042
|
function serverRegistryFilePath(root) {
|
|
2795
3043
|
const hash = createHash("sha256").update(root).digest("hex").slice(0, 16);
|
|
2796
|
-
return
|
|
3044
|
+
return join5(registryDir(), `${hash}.json`);
|
|
2797
3045
|
}
|
|
2798
3046
|
function writeServerRegistry(entry) {
|
|
2799
3047
|
try {
|
|
@@ -2834,7 +3082,7 @@ function removeServerRegistry(root, pid) {
|
|
|
2834
3082
|
var init_server_registry = () => {};
|
|
2835
3083
|
|
|
2836
3084
|
// web-src/server/cli-helpers.ts
|
|
2837
|
-
import { realpathSync as
|
|
3085
|
+
import { realpathSync as realpathSync3 } from "node:fs";
|
|
2838
3086
|
function takeValue(argv, index, flag) {
|
|
2839
3087
|
const value = argv[index + 1];
|
|
2840
3088
|
if (value === undefined)
|
|
@@ -2893,7 +3141,7 @@ function resolveRepoRootSafe(cwdOption) {
|
|
|
2893
3141
|
const base = cwdOption || process.cwd();
|
|
2894
3142
|
let baseReal;
|
|
2895
3143
|
try {
|
|
2896
|
-
baseReal =
|
|
3144
|
+
baseReal = realpathSync3(base);
|
|
2897
3145
|
} catch {
|
|
2898
3146
|
return {
|
|
2899
3147
|
ok: false,
|
|
@@ -4003,8 +4251,8 @@ __export(exports_file_cli, {
|
|
|
4003
4251
|
FILE_DEFAULT_HISTORY_LIMIT: () => FILE_DEFAULT_HISTORY_LIMIT,
|
|
4004
4252
|
FILE_AGENT_HELP: () => FILE_AGENT_HELP
|
|
4005
4253
|
});
|
|
4006
|
-
import { existsSync as existsSync3, readFileSync as readFileSync4, realpathSync as
|
|
4007
|
-
import { join as
|
|
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";
|
|
4008
4256
|
function validatePath(value) {
|
|
4009
4257
|
return validateRepoRelativePathValue(value, "--path");
|
|
4010
4258
|
}
|
|
@@ -4408,13 +4656,13 @@ function sliceLines(text, start, end) {
|
|
|
4408
4656
|
function safeWorktreePathFromRoot(root, path) {
|
|
4409
4657
|
if (validatePath(path))
|
|
4410
4658
|
return null;
|
|
4411
|
-
const full =
|
|
4659
|
+
const full = join6(root, path);
|
|
4412
4660
|
if (!existsSync3(full))
|
|
4413
4661
|
return null;
|
|
4414
4662
|
try {
|
|
4415
|
-
const realRoot =
|
|
4416
|
-
const realFull =
|
|
4417
|
-
const rel =
|
|
4663
|
+
const realRoot = realpathSync4(root);
|
|
4664
|
+
const realFull = realpathSync4(full);
|
|
4665
|
+
const rel = relative3(realRoot, realFull);
|
|
4418
4666
|
if (rel === "" || rel.startsWith("..") || rel.startsWith("/") || rel.startsWith("\\")) {
|
|
4419
4667
|
return null;
|
|
4420
4668
|
}
|
|
@@ -8766,11 +9014,11 @@ function normalizeGrepMax(value) {
|
|
|
8766
9014
|
return Math.min(parsed, GREP_ABSOLUTE_MAX);
|
|
8767
9015
|
}
|
|
8768
9016
|
function isSkippableSearchPath(path, omitDirNames = [], excludeNames = []) {
|
|
8769
|
-
const omitDirs =
|
|
8770
|
-
const excluded =
|
|
9017
|
+
const omitDirs = compileNamePatterns(omitDirNames);
|
|
9018
|
+
const excluded = compileNamePatterns(excludeNames);
|
|
8771
9019
|
return path.split(/[\\/]+/).some((part) => {
|
|
8772
9020
|
const lower = part.toLowerCase();
|
|
8773
|
-
return lower === ".git" || lower === ".code-viewer" || omitDirs.
|
|
9021
|
+
return lower === ".git" || lower === ".code-viewer" || omitDirs.matches(part) || excluded.matches(part);
|
|
8774
9022
|
});
|
|
8775
9023
|
}
|
|
8776
9024
|
function fixedStringLineMatches(path, text, query, max) {
|
|
@@ -8877,6 +9125,7 @@ function parseGitGrepOutput(stdout, ref, max, omitDirNames = [], excludeNames =
|
|
|
8877
9125
|
}
|
|
8878
9126
|
var GREP_DEFAULT_MAX = 200, GREP_ABSOLUTE_MAX = 500, GREP_MAX_FILE_BYTES, FILE_SEARCH_ABSOLUTE_MAX = 50000, DEFAULT_EXCLUDE_NAMES;
|
|
8879
9127
|
var init_search = __esm(() => {
|
|
9128
|
+
init_name_pattern();
|
|
8880
9129
|
GREP_MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
8881
9130
|
DEFAULT_EXCLUDE_NAMES = [".DS_Store"];
|
|
8882
9131
|
});
|
|
@@ -9317,24 +9566,24 @@ Parse failures and unreachable servers exit 1.
|
|
|
9317
9566
|
|
|
9318
9567
|
// web-src/server/root.ts
|
|
9319
9568
|
import { existsSync as existsSync4 } from "node:fs";
|
|
9320
|
-
import { dirname as
|
|
9569
|
+
import { dirname as dirname4, join as join7, normalize } from "node:path";
|
|
9321
9570
|
import { fileURLToPath } from "node:url";
|
|
9322
9571
|
function findRoot(start) {
|
|
9323
9572
|
let current = start;
|
|
9324
9573
|
for (let i = 0;i < 5; i++) {
|
|
9325
|
-
if (existsSync4(
|
|
9574
|
+
if (existsSync4(join7(current, "package.json")) && existsSync4(join7(current, "web"))) {
|
|
9326
9575
|
return normalize(current);
|
|
9327
9576
|
}
|
|
9328
|
-
const parent =
|
|
9577
|
+
const parent = dirname4(current);
|
|
9329
9578
|
if (parent === current)
|
|
9330
9579
|
break;
|
|
9331
9580
|
current = parent;
|
|
9332
9581
|
}
|
|
9333
|
-
return normalize(
|
|
9582
|
+
return normalize(join7(start, "..", ".."));
|
|
9334
9583
|
}
|
|
9335
9584
|
var ROOT;
|
|
9336
9585
|
var init_root = __esm(() => {
|
|
9337
|
-
ROOT = findRoot(
|
|
9586
|
+
ROOT = findRoot(dirname4(fileURLToPath(import.meta.url)));
|
|
9338
9587
|
});
|
|
9339
9588
|
|
|
9340
9589
|
// web-src/server/skill-cli.ts
|
|
@@ -9349,7 +9598,7 @@ __export(exports_skill_cli, {
|
|
|
9349
9598
|
});
|
|
9350
9599
|
import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync as readdirSync2 } from "node:fs";
|
|
9351
9600
|
import { homedir as homedir2 } from "node:os";
|
|
9352
|
-
import { join as
|
|
9601
|
+
import { join as join8, resolve } from "node:path";
|
|
9353
9602
|
function parseAgentList(value) {
|
|
9354
9603
|
if (value === "all")
|
|
9355
9604
|
return [...AGENT_NAMES];
|
|
@@ -9409,7 +9658,7 @@ function parseSkillArgs(argv) {
|
|
|
9409
9658
|
function discoverBundledSkills(skillsRoot) {
|
|
9410
9659
|
if (!existsSync5(skillsRoot))
|
|
9411
9660
|
return [];
|
|
9412
|
-
return readdirSync2(skillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync5(
|
|
9661
|
+
return readdirSync2(skillsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && existsSync5(join8(skillsRoot, entry.name, "SKILL.md"))).map((entry) => entry.name).sort();
|
|
9413
9662
|
}
|
|
9414
9663
|
function installSkill(args, deps) {
|
|
9415
9664
|
const skills = discoverBundledSkills(deps.skillsRoot);
|
|
@@ -9423,8 +9672,8 @@ function installSkill(args, deps) {
|
|
|
9423
9672
|
const results = [];
|
|
9424
9673
|
for (const agent of args.agents) {
|
|
9425
9674
|
for (const skill of skills) {
|
|
9426
|
-
const sourceDir =
|
|
9427
|
-
const target =
|
|
9675
|
+
const sourceDir = join8(deps.skillsRoot, skill);
|
|
9676
|
+
const target = join8(base, AGENT_SKILL_DIRS[agent], "skills", skill);
|
|
9428
9677
|
const action = existsSync5(target) ? "updated" : "installed";
|
|
9429
9678
|
try {
|
|
9430
9679
|
mkdirSync2(target, { recursive: true });
|
|
@@ -9453,7 +9702,7 @@ function runSkillCli(argv) {
|
|
|
9453
9702
|
return;
|
|
9454
9703
|
}
|
|
9455
9704
|
const result = installSkill(parsed.args, {
|
|
9456
|
-
skillsRoot:
|
|
9705
|
+
skillsRoot: join8(ROOT, "skills"),
|
|
9457
9706
|
homeDir: homedir2(),
|
|
9458
9707
|
projectDir: process.cwd()
|
|
9459
9708
|
});
|
|
@@ -14517,11 +14766,11 @@ import {
|
|
|
14517
14766
|
existsSync as existsSync6,
|
|
14518
14767
|
openSync as openSync2,
|
|
14519
14768
|
readSync as readSync2,
|
|
14520
|
-
realpathSync as
|
|
14769
|
+
realpathSync as realpathSync5,
|
|
14521
14770
|
statSync as statSync4
|
|
14522
14771
|
} from "node:fs";
|
|
14523
14772
|
import { lstat, open, readdir, readFile as readFile2, stat } from "node:fs/promises";
|
|
14524
|
-
import { basename, join as
|
|
14773
|
+
import { basename, join as join9, relative as relative4 } from "node:path";
|
|
14525
14774
|
function isSqliteFile(fullPath) {
|
|
14526
14775
|
try {
|
|
14527
14776
|
const stat2 = statSync4(fullPath);
|
|
@@ -14592,7 +14841,7 @@ async function discoverSqliteFilesAsync(cwd, omitDirNames, signal) {
|
|
|
14592
14841
|
return;
|
|
14593
14842
|
if (omitSet.has(entry.toLowerCase()))
|
|
14594
14843
|
continue;
|
|
14595
|
-
const full =
|
|
14844
|
+
const full = join9(dir, entry);
|
|
14596
14845
|
let entryStat;
|
|
14597
14846
|
try {
|
|
14598
14847
|
entryStat = await lstat(full);
|
|
@@ -14609,7 +14858,7 @@ async function discoverSqliteFilesAsync(cwd, omitDirNames, signal) {
|
|
|
14609
14858
|
continue;
|
|
14610
14859
|
if (!await isSqliteFileAsync(full))
|
|
14611
14860
|
continue;
|
|
14612
|
-
const rel =
|
|
14861
|
+
const rel = relative4(cwd, full);
|
|
14613
14862
|
if (rel.startsWith("..") || rel.startsWith("/"))
|
|
14614
14863
|
continue;
|
|
14615
14864
|
results.push({
|
|
@@ -14636,18 +14885,18 @@ function validateDbPath(cwd, dbPath) {
|
|
|
14636
14885
|
const parts = dbPath.split(/[\\/]+/);
|
|
14637
14886
|
if (parts.some((p) => p === ".." || p.toLowerCase() === ".git" || p.toLowerCase() === ".code-viewer"))
|
|
14638
14887
|
return null;
|
|
14639
|
-
const full =
|
|
14888
|
+
const full = join9(cwd, dbPath);
|
|
14640
14889
|
if (!existsSync6(full))
|
|
14641
14890
|
return null;
|
|
14642
14891
|
let realCwd;
|
|
14643
14892
|
let realFull;
|
|
14644
14893
|
try {
|
|
14645
|
-
realCwd =
|
|
14646
|
-
realFull =
|
|
14894
|
+
realCwd = realpathSync5(cwd);
|
|
14895
|
+
realFull = realpathSync5(full);
|
|
14647
14896
|
} catch {
|
|
14648
14897
|
return null;
|
|
14649
14898
|
}
|
|
14650
|
-
const rel =
|
|
14899
|
+
const rel = relative4(realCwd, realFull);
|
|
14651
14900
|
if (rel === "" || rel.startsWith("..") || rel.startsWith("/"))
|
|
14652
14901
|
return null;
|
|
14653
14902
|
if (!isSqliteFile(realFull))
|
|
@@ -14806,7 +15055,7 @@ function resolveEnvValue(raw, composeDirEnv = {}) {
|
|
|
14806
15055
|
}
|
|
14807
15056
|
async function readDotenvAsync(composeDir) {
|
|
14808
15057
|
try {
|
|
14809
|
-
const content = await readFile2(
|
|
15058
|
+
const content = await readFile2(join9(composeDir, ".env"), "utf-8");
|
|
14810
15059
|
return parseDotenvContent(content);
|
|
14811
15060
|
} catch {
|
|
14812
15061
|
return {};
|
|
@@ -14928,7 +15177,7 @@ function parseComposeContent(content, filepath, composeDir, cwd, composeDirEnv,
|
|
|
14928
15177
|
for (let match = serviceRegex.exec(servicesBlock);match !== null; match = serviceRegex.exec(servicesBlock)) {
|
|
14929
15178
|
servicePositions.push({ name: match[1], start: match.index });
|
|
14930
15179
|
}
|
|
14931
|
-
const relDir =
|
|
15180
|
+
const relDir = relative4(cwd, composeDir);
|
|
14932
15181
|
const isRoot = relDir === "" || relDir === ".";
|
|
14933
15182
|
const relDirSlash = relDir.replace(/\\/g, "/");
|
|
14934
15183
|
const filename = basename(filepath);
|
|
@@ -15033,7 +15282,7 @@ async function walkForMarkerFileAsync(dir, depth, omitSet, hasCapacity, visitDir
|
|
|
15033
15282
|
return;
|
|
15034
15283
|
if (omitSet.has(entry.toLowerCase()))
|
|
15035
15284
|
continue;
|
|
15036
|
-
const full =
|
|
15285
|
+
const full = join9(dir, entry);
|
|
15037
15286
|
let entryStat;
|
|
15038
15287
|
try {
|
|
15039
15288
|
entryStat = await lstat(full);
|
|
@@ -15060,7 +15309,7 @@ async function discoverDockerDatabasesAsync(cwd, omitDirNames = [], signal) {
|
|
|
15060
15309
|
omitSet.add("node_modules");
|
|
15061
15310
|
await walkForMarkerFileAsync(cwd, 0, omitSet, () => results.length < MAX_DOCKER_SERVICES, async (dir) => {
|
|
15062
15311
|
for (const filename of COMPOSE_FILENAMES) {
|
|
15063
|
-
const filepath =
|
|
15312
|
+
const filepath = join9(dir, filename);
|
|
15064
15313
|
if (await pathExistsAsync(filepath)) {
|
|
15065
15314
|
await parseComposeFileAsync(filepath, dir, cwd, results);
|
|
15066
15315
|
break;
|
|
@@ -15224,7 +15473,7 @@ async function discoverSupabaseCliProjectsAsync(cwd, omitDirNames = [], signal)
|
|
|
15224
15473
|
omitSet.add("node_modules");
|
|
15225
15474
|
const results = [];
|
|
15226
15475
|
await walkForMarkerFileAsync(cwd, 0, omitSet, () => results.length < MAX_SUPABASE_PROJECTS, async (dir) => {
|
|
15227
|
-
const configPath =
|
|
15476
|
+
const configPath = join9(dir, "supabase", "config.toml");
|
|
15228
15477
|
if (!await pathExistsAsync(configPath))
|
|
15229
15478
|
return;
|
|
15230
15479
|
try {
|
|
@@ -15232,7 +15481,7 @@ async function discoverSupabaseCliProjectsAsync(cwd, omitDirNames = [], signal)
|
|
|
15232
15481
|
const parsed = parseSupabaseConfigToml(content);
|
|
15233
15482
|
if (!parsed)
|
|
15234
15483
|
return;
|
|
15235
|
-
const relDir =
|
|
15484
|
+
const relDir = relative4(cwd, dir);
|
|
15236
15485
|
const isRoot = relDir === "" || relDir === ".";
|
|
15237
15486
|
const relDirSlash = relDir.replace(/\\/g, "/");
|
|
15238
15487
|
const id = isRoot ? `supabase:${parsed.projectId}` : `supabase:${parsed.projectId}@${encodeURIComponent(relDirSlash)}`;
|
|
@@ -15333,16 +15582,16 @@ function makeId(prefix) {
|
|
|
15333
15582
|
|
|
15334
15583
|
// web-src/server/worktree-watcher.ts
|
|
15335
15584
|
import {
|
|
15336
|
-
lstatSync as
|
|
15585
|
+
lstatSync as lstatSync3,
|
|
15337
15586
|
readdirSync as nodeReaddirSync,
|
|
15338
15587
|
watch as nodeWatch
|
|
15339
15588
|
} from "node:fs";
|
|
15340
|
-
import { join as
|
|
15589
|
+
import { join as join10, relative as relative5 } from "node:path";
|
|
15341
15590
|
function normalizeRelativePath(path) {
|
|
15342
15591
|
return path.replace(/\\/g, "/").replace(/^\/+/, "");
|
|
15343
15592
|
}
|
|
15344
15593
|
function isInsideRoot(root, path) {
|
|
15345
|
-
const rel =
|
|
15594
|
+
const rel = relative5(root, path).replace(/\\/g, "/");
|
|
15346
15595
|
return rel === "" || !rel.startsWith("..") && !rel.startsWith("/");
|
|
15347
15596
|
}
|
|
15348
15597
|
function startWorktreeUpdateWatch(options) {
|
|
@@ -15350,14 +15599,14 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15350
15599
|
const readDirs = options.readdirSync || ((path) => nodeReaddirSync(path, { withFileTypes: true }));
|
|
15351
15600
|
const isDirectory = options.isDirectory || ((path) => {
|
|
15352
15601
|
try {
|
|
15353
|
-
return
|
|
15602
|
+
return lstatSync3(path).isDirectory();
|
|
15354
15603
|
} catch {
|
|
15355
15604
|
return false;
|
|
15356
15605
|
}
|
|
15357
15606
|
});
|
|
15358
15607
|
const directorySignature = options.directorySignature || ((path) => {
|
|
15359
15608
|
try {
|
|
15360
|
-
const stats =
|
|
15609
|
+
const stats = lstatSync3(path);
|
|
15361
15610
|
if (!stats.isDirectory())
|
|
15362
15611
|
return null;
|
|
15363
15612
|
return `${stats.dev}:${stats.ino}`;
|
|
@@ -15380,7 +15629,7 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15380
15629
|
const pendingChangedPaths = new Set;
|
|
15381
15630
|
let watchLimitReported = false;
|
|
15382
15631
|
const ignored = (path) => isSkippableSearchPath(normalizeRelativePath(path), options.omitDirNames, options.excludeNames);
|
|
15383
|
-
const directoryRelativePath = (dir) => normalizeRelativePath(
|
|
15632
|
+
const directoryRelativePath = (dir) => normalizeRelativePath(relative5(options.root, dir));
|
|
15384
15633
|
const ignoredDirectory = (dir) => {
|
|
15385
15634
|
const rel = directoryRelativePath(dir);
|
|
15386
15635
|
return Boolean(rel && ignored(rel));
|
|
@@ -15446,7 +15695,7 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15446
15695
|
for (const entry of entries) {
|
|
15447
15696
|
if (!entry.isDirectory())
|
|
15448
15697
|
continue;
|
|
15449
|
-
const child =
|
|
15698
|
+
const child = join10(dir, entry.name);
|
|
15450
15699
|
if (ignoredDirectory(child))
|
|
15451
15700
|
continue;
|
|
15452
15701
|
children.push(child);
|
|
@@ -15530,10 +15779,10 @@ function startWorktreeUpdateWatch(options) {
|
|
|
15530
15779
|
scheduleUpdate();
|
|
15531
15780
|
return;
|
|
15532
15781
|
}
|
|
15533
|
-
const changed = normalizeRelativePath(
|
|
15782
|
+
const changed = normalizeRelativePath(join10(rel, filename.toString()));
|
|
15534
15783
|
if (ignored(changed))
|
|
15535
15784
|
return;
|
|
15536
|
-
const fullChangedPath =
|
|
15785
|
+
const fullChangedPath = join10(options.root, changed);
|
|
15537
15786
|
if (!isInsideRoot(options.root, fullChangedPath))
|
|
15538
15787
|
return;
|
|
15539
15788
|
if (initialScanAsync) {
|
|
@@ -15582,9 +15831,9 @@ var init_worktree_watcher = __esm(() => {
|
|
|
15582
15831
|
});
|
|
15583
15832
|
|
|
15584
15833
|
// web-src/server/state-store.ts
|
|
15585
|
-
import { join as
|
|
15834
|
+
import { join as join11 } from "node:path";
|
|
15586
15835
|
function codeViewerPath(root, fileName) {
|
|
15587
|
-
return
|
|
15836
|
+
return join11(root, CODE_VIEWER_DIR2, fileName);
|
|
15588
15837
|
}
|
|
15589
15838
|
function isRecord(value) {
|
|
15590
15839
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -16700,7 +16949,7 @@ var init_connection_pool = __esm(() => {
|
|
|
16700
16949
|
// web-src/server/database/connections-store.ts
|
|
16701
16950
|
import { randomUUID } from "node:crypto";
|
|
16702
16951
|
import { chmod } from "node:fs/promises";
|
|
16703
|
-
import { join as
|
|
16952
|
+
import { join as join12 } from "node:path";
|
|
16704
16953
|
function secretKey(cwd, id) {
|
|
16705
16954
|
return `${cwd}\x00${id}`;
|
|
16706
16955
|
}
|
|
@@ -16721,7 +16970,7 @@ function withRuntimeSecrets(cwd, connection) {
|
|
|
16721
16970
|
};
|
|
16722
16971
|
}
|
|
16723
16972
|
function connectionsFilePath(root) {
|
|
16724
|
-
return
|
|
16973
|
+
return join12(root, ".code-viewer", CONNECTIONS_FILE_NAME);
|
|
16725
16974
|
}
|
|
16726
16975
|
function emptyState() {
|
|
16727
16976
|
return { version: 1, connections: [] };
|
|
@@ -18503,9 +18752,9 @@ var init_handle_s3 = __esm(() => {
|
|
|
18503
18752
|
});
|
|
18504
18753
|
|
|
18505
18754
|
// web-src/server/database/query-history.ts
|
|
18506
|
-
import { join as
|
|
18755
|
+
import { join as join13 } from "node:path";
|
|
18507
18756
|
function historyFilePath(root) {
|
|
18508
|
-
return
|
|
18757
|
+
return join13(root, CODE_VIEWER_DIR3, HISTORY_FILE_NAME);
|
|
18509
18758
|
}
|
|
18510
18759
|
function emptyState2() {
|
|
18511
18760
|
return { version: 1, entries: [] };
|
|
@@ -18655,9 +18904,9 @@ var init_query_history = __esm(() => {
|
|
|
18655
18904
|
// web-src/server/database/snapshot-store.ts
|
|
18656
18905
|
import { createHash as createHash6, randomBytes as randomBytes2 } from "node:crypto";
|
|
18657
18906
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
18658
|
-
import { join as
|
|
18907
|
+
import { join as join14 } from "node:path";
|
|
18659
18908
|
async function getStoreDb(cwd) {
|
|
18660
|
-
const dbPath =
|
|
18909
|
+
const dbPath = join14(cwd, CODE_VIEWER_DIR4, SNAPSHOT_DB_NAME);
|
|
18661
18910
|
if (storeDb && storeDbPath === dbPath)
|
|
18662
18911
|
return storeDb;
|
|
18663
18912
|
if (storeDb) {
|
|
@@ -18665,7 +18914,7 @@ async function getStoreDb(cwd) {
|
|
|
18665
18914
|
storeDb.close();
|
|
18666
18915
|
} catch {}
|
|
18667
18916
|
}
|
|
18668
|
-
mkdirSync3(
|
|
18917
|
+
mkdirSync3(join14(cwd, CODE_VIEWER_DIR4), { recursive: true });
|
|
18669
18918
|
const DbClass = await loadSqliteClass();
|
|
18670
18919
|
storeDb = new DbClass(dbPath);
|
|
18671
18920
|
storeDbPath = dbPath;
|
|
@@ -19271,9 +19520,9 @@ var init_snapshot_runner = __esm(() => {
|
|
|
19271
19520
|
});
|
|
19272
19521
|
|
|
19273
19522
|
// web-src/server/database/tabs-store.ts
|
|
19274
|
-
import { join as
|
|
19523
|
+
import { join as join15 } from "node:path";
|
|
19275
19524
|
function tabsFilePath(root) {
|
|
19276
|
-
return
|
|
19525
|
+
return join15(root, CODE_VIEWER_DIR5, TABS_FILE_NAME);
|
|
19277
19526
|
}
|
|
19278
19527
|
function emptyState3() {
|
|
19279
19528
|
return { version: 1, tabs: [], activeTabId: null };
|
|
@@ -21210,7 +21459,7 @@ var init_handle = __esm(() => {
|
|
|
21210
21459
|
|
|
21211
21460
|
// web-src/server/doctor.ts
|
|
21212
21461
|
import { accessSync as accessSync2, constants as constants2, readFileSync as readFileSync6, statSync as statSync5 } from "node:fs";
|
|
21213
|
-
import { dirname as
|
|
21462
|
+
import { dirname as dirname5, join as join16, relative as relative6 } from "node:path";
|
|
21214
21463
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
21215
21464
|
function statusWorse(a, b) {
|
|
21216
21465
|
const rank = { ok: 0, warn: 1, error: 2 };
|
|
@@ -21299,12 +21548,12 @@ function findCodeViewerPackageJson() {
|
|
|
21299
21548
|
try {
|
|
21300
21549
|
let cursor;
|
|
21301
21550
|
try {
|
|
21302
|
-
cursor =
|
|
21551
|
+
cursor = dirname5(fileURLToPath2(import.meta.url));
|
|
21303
21552
|
} catch {
|
|
21304
|
-
cursor =
|
|
21553
|
+
cursor = dirname5(process.argv[1] || ".");
|
|
21305
21554
|
}
|
|
21306
21555
|
for (let depth = 0;depth < 8; depth += 1) {
|
|
21307
|
-
const candidate =
|
|
21556
|
+
const candidate = join16(cursor, "package.json");
|
|
21308
21557
|
try {
|
|
21309
21558
|
const raw = readFileSync6(candidate, "utf8");
|
|
21310
21559
|
const pkg = JSON.parse(raw);
|
|
@@ -21312,7 +21561,7 @@ function findCodeViewerPackageJson() {
|
|
|
21312
21561
|
return { version: pkg.version, path: candidate };
|
|
21313
21562
|
}
|
|
21314
21563
|
} catch {}
|
|
21315
|
-
const next =
|
|
21564
|
+
const next = dirname5(cursor);
|
|
21316
21565
|
if (next === cursor)
|
|
21317
21566
|
break;
|
|
21318
21567
|
cursor = next;
|
|
@@ -21400,7 +21649,7 @@ async function checkSqlite(cwd) {
|
|
|
21400
21649
|
return { id: "sqlite", title: "SQLite driver", rows };
|
|
21401
21650
|
}
|
|
21402
21651
|
async function trySnapshotDbOpen(cwd) {
|
|
21403
|
-
const dbPath =
|
|
21652
|
+
const dbPath = join16(cwd, SNAPSHOT_DB_REL);
|
|
21404
21653
|
try {
|
|
21405
21654
|
statSync5(dbPath);
|
|
21406
21655
|
} catch {
|
|
@@ -21421,8 +21670,8 @@ async function trySnapshotDbOpen(cwd) {
|
|
|
21421
21670
|
}
|
|
21422
21671
|
}
|
|
21423
21672
|
function checkSnapshotStore(cwd) {
|
|
21424
|
-
const dbPath =
|
|
21425
|
-
const dir =
|
|
21673
|
+
const dbPath = join16(cwd, SNAPSHOT_DB_REL);
|
|
21674
|
+
const dir = dirname5(dbPath);
|
|
21426
21675
|
let dirStatus = "ok";
|
|
21427
21676
|
let dirDetail = dir;
|
|
21428
21677
|
let dirHint;
|
|
@@ -21495,7 +21744,7 @@ async function checkGit(cwd, signal) {
|
|
|
21495
21744
|
if (repoCheck && repoCheck.code === 0 && /true/.test(repoCheck.stdout)) {
|
|
21496
21745
|
const topRes = await runCached(gitCache, TTL.gitRepo, commandForExternal("git"), ["rev-parse", "--show-toplevel"], TIMEOUT.git, signal, cwd);
|
|
21497
21746
|
const top = topRes?.stdout.trim() || cwd;
|
|
21498
|
-
const insideCwd =
|
|
21747
|
+
const insideCwd = relative6(top, cwd) || ".";
|
|
21499
21748
|
rows.push({
|
|
21500
21749
|
id: "git.repo",
|
|
21501
21750
|
title: "Working tree",
|
|
@@ -22423,44 +22672,6 @@ function normalizeNewDirectoryName(name) {
|
|
|
22423
22672
|
return trimmed;
|
|
22424
22673
|
}
|
|
22425
22674
|
|
|
22426
|
-
// web-src/server/cache.ts
|
|
22427
|
-
import { lstatSync as lstatSync3 } from "node:fs";
|
|
22428
|
-
import { join as join16 } from "node:path";
|
|
22429
|
-
function cacheFresh(cached, now = Date.now(), ttlMs = CACHE_TTL_MS) {
|
|
22430
|
-
return !!cached && now - cached.storedAt <= ttlMs;
|
|
22431
|
-
}
|
|
22432
|
-
function setTimedCacheEntry(cache, key, value, now = Date.now(), maxEntries = MAX_TIMED_CACHE_ENTRIES) {
|
|
22433
|
-
cache.set(key, { ...value, storedAt: now });
|
|
22434
|
-
while (cache.size > maxEntries) {
|
|
22435
|
-
const oldest = cache.keys().next().value;
|
|
22436
|
-
if (oldest === undefined)
|
|
22437
|
-
break;
|
|
22438
|
-
cache.delete(oldest);
|
|
22439
|
-
}
|
|
22440
|
-
}
|
|
22441
|
-
function worktreeFileSignature(path, cwd) {
|
|
22442
|
-
try {
|
|
22443
|
-
const stats = lstatSync3(join16(cwd, path));
|
|
22444
|
-
const inode = "ino" in stats ? stats.ino : 0;
|
|
22445
|
-
return `state:file|size:${stats.size}|mtime:${stats.mtimeMs}|ctime:${stats.ctimeMs}|ino:${inode}`;
|
|
22446
|
-
} catch {
|
|
22447
|
-
return "state:missing";
|
|
22448
|
-
}
|
|
22449
|
-
}
|
|
22450
|
-
function fileDiffCacheKey(options) {
|
|
22451
|
-
const worktreeTarget = options.range.from === "worktree" || !options.range.to || options.range.to === "worktree";
|
|
22452
|
-
if (options.isUntracked && !worktreeTarget) {
|
|
22453
|
-
throw new Error("untracked file diffs require a worktree range");
|
|
22454
|
-
}
|
|
22455
|
-
const signature = worktreeTarget ? `\x00${worktreeFileSignature(options.path, options.cwd)}` : "";
|
|
22456
|
-
if (options.isUntracked) {
|
|
22457
|
-
return `u\x00${options.path}${signature}\x00${options.extras.join("\x00")}`;
|
|
22458
|
-
}
|
|
22459
|
-
return `t\x00${options.path}\x00${options.oldPath || ""}${signature}\x00${[...options.extras, ...options.args].join("\x00")}`;
|
|
22460
|
-
}
|
|
22461
|
-
var CACHE_TTL_MS = 1500, MAX_TIMED_CACHE_ENTRIES = 200;
|
|
22462
|
-
var init_cache = () => {};
|
|
22463
|
-
|
|
22464
22675
|
// web-src/server/dev-assets.ts
|
|
22465
22676
|
import { basename as basename2 } from "node:path";
|
|
22466
22677
|
function startDevAssetReload(options) {
|
|
@@ -23123,8 +23334,8 @@ var init_journal2 = __esm(() => {
|
|
|
23123
23334
|
});
|
|
23124
23335
|
|
|
23125
23336
|
// web-src/server/search-service.ts
|
|
23126
|
-
import { existsSync as existsSync7, lstatSync as lstatSync4, readFileSync as readFileSync7, realpathSync as
|
|
23127
|
-
import { join as join18, relative as
|
|
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";
|
|
23128
23339
|
async function rgAvailableAsync(cwd) {
|
|
23129
23340
|
if (rgAvailableCache !== null)
|
|
23130
23341
|
return rgAvailableCache;
|
|
@@ -23141,7 +23352,8 @@ async function rgAvailableAsync(cwd) {
|
|
|
23141
23352
|
return rgAvailableCache;
|
|
23142
23353
|
}
|
|
23143
23354
|
function isExcludedScopePath(path, excludeNames) {
|
|
23144
|
-
|
|
23355
|
+
const excluded = compileNamePatterns(excludeNames);
|
|
23356
|
+
return path.split(/[\\/]+/).some((part) => excluded.matches(part));
|
|
23145
23357
|
}
|
|
23146
23358
|
function isSafePath(path) {
|
|
23147
23359
|
if (!path || path.startsWith("/") || path.startsWith("\\") || path.includes("\x00"))
|
|
@@ -23159,12 +23371,12 @@ function safeWorktreePath(env, path) {
|
|
|
23159
23371
|
let realCwd;
|
|
23160
23372
|
let realFull;
|
|
23161
23373
|
try {
|
|
23162
|
-
realCwd =
|
|
23163
|
-
realFull =
|
|
23374
|
+
realCwd = realpathSync6(env.cwd);
|
|
23375
|
+
realFull = realpathSync6(full);
|
|
23164
23376
|
} catch {
|
|
23165
23377
|
return null;
|
|
23166
23378
|
}
|
|
23167
|
-
const rel =
|
|
23379
|
+
const rel = relative7(realCwd, realFull);
|
|
23168
23380
|
if (rel === "" || rel.startsWith("..") || rel.startsWith("/") || rel.startsWith("\\"))
|
|
23169
23381
|
return null;
|
|
23170
23382
|
if (isGitInternalPath(rel))
|
|
@@ -23340,6 +23552,7 @@ var init_search_service = __esm(() => {
|
|
|
23340
23552
|
init_command_resolver();
|
|
23341
23553
|
init_spawn_runner();
|
|
23342
23554
|
init_git();
|
|
23555
|
+
init_name_pattern();
|
|
23343
23556
|
init_search();
|
|
23344
23557
|
});
|
|
23345
23558
|
|
|
@@ -24907,7 +25120,7 @@ import {
|
|
|
24907
25120
|
mkdirSync as mkdirSync4,
|
|
24908
25121
|
openSync as openSync3,
|
|
24909
25122
|
readFileSync as readFileSync9,
|
|
24910
|
-
realpathSync as
|
|
25123
|
+
realpathSync as realpathSync7,
|
|
24911
25124
|
renameSync,
|
|
24912
25125
|
statSync as statSync6,
|
|
24913
25126
|
unlinkSync as unlinkSync2,
|
|
@@ -24915,7 +25128,7 @@ import {
|
|
|
24915
25128
|
writeFileSync as writeFileSync2
|
|
24916
25129
|
} from "node:fs";
|
|
24917
25130
|
import { homedir as homedir3 } from "node:os";
|
|
24918
|
-
import { basename as basename3, dirname as
|
|
25131
|
+
import { basename as basename3, dirname as dirname6, extname as extname2, join as join20, relative as relative8 } from "node:path";
|
|
24919
25132
|
function parseCli() {
|
|
24920
25133
|
const rest = [];
|
|
24921
25134
|
for (let i = 2;i < process.argv.length; i++) {
|
|
@@ -24969,7 +25182,7 @@ Examples:
|
|
|
24969
25182
|
process.exit(1);
|
|
24970
25183
|
}
|
|
24971
25184
|
try {
|
|
24972
|
-
cwd =
|
|
25185
|
+
cwd = realpathSync7(next);
|
|
24973
25186
|
cwdWasExplicit = true;
|
|
24974
25187
|
} catch {
|
|
24975
25188
|
console.error("--cwd must point to an existing directory");
|
|
@@ -25400,7 +25613,7 @@ function worktreePath(path) {
|
|
|
25400
25613
|
function safeOpenWorktreePath(path) {
|
|
25401
25614
|
if (path === "") {
|
|
25402
25615
|
try {
|
|
25403
|
-
const realCwd =
|
|
25616
|
+
const realCwd = realpathSync7(cwd);
|
|
25404
25617
|
if (isGitInternalPath(realCwd))
|
|
25405
25618
|
return null;
|
|
25406
25619
|
return realCwd;
|
|
@@ -25411,7 +25624,7 @@ function safeOpenWorktreePath(path) {
|
|
|
25411
25624
|
return safeWorktreePath2(path);
|
|
25412
25625
|
}
|
|
25413
25626
|
function parentRepoPath(path) {
|
|
25414
|
-
const parent =
|
|
25627
|
+
const parent = dirname6(path);
|
|
25415
25628
|
return parent === "." ? "" : parent;
|
|
25416
25629
|
}
|
|
25417
25630
|
function isoDate(ms) {
|
|
@@ -25469,6 +25682,21 @@ async function attachTreeEntryMetadata(target, entry) {
|
|
|
25469
25682
|
return { ...entry, ...await directoryMetadata(target, entry.path) };
|
|
25470
25683
|
if (entry.type !== "blob")
|
|
25471
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
|
+
}
|
|
25472
25700
|
return { ...entry, ...await fileMetadataForTarget(target, entry.path) };
|
|
25473
25701
|
}
|
|
25474
25702
|
async function readReadme(target, dirPath) {
|
|
@@ -25491,6 +25719,22 @@ async function readReadme(target, dirPath) {
|
|
|
25491
25719
|
}
|
|
25492
25720
|
return null;
|
|
25493
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
|
+
}
|
|
25494
25738
|
async function handleTree(url) {
|
|
25495
25739
|
const target = url.searchParams.get("ref") || url.searchParams.get("target") || "worktree";
|
|
25496
25740
|
const path = (url.searchParams.get("path") || "").replace(/^\/+|\/+$/g, "");
|
|
@@ -25517,12 +25761,21 @@ async function handleTree(url) {
|
|
|
25517
25761
|
if (tree.error)
|
|
25518
25762
|
return text(tree.error, tree.status ?? 500);
|
|
25519
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) : [];
|
|
25520
25770
|
return json2({
|
|
25521
25771
|
ref: target,
|
|
25522
25772
|
path,
|
|
25523
25773
|
project: basename3(cwd),
|
|
25524
25774
|
branch: await currentBranchMetadata(),
|
|
25525
|
-
entries: recursive ? entries
|
|
25775
|
+
entries: recursive ? entries.map(withStatus) : [
|
|
25776
|
+
...await Promise.all(entries.map((entry) => attachTreeEntryMetadata(target, entry).then(withStatus))),
|
|
25777
|
+
...deletedEntries
|
|
25778
|
+
],
|
|
25526
25779
|
readme: await readReadme(target, path),
|
|
25527
25780
|
upload_enabled: uploadEnabled && (target === "worktree" || target === "")
|
|
25528
25781
|
});
|
|
@@ -26218,7 +26471,7 @@ async function handleUploadFiles(req) {
|
|
|
26218
26471
|
if (total > MAX_UPLOAD_TOTAL_BYTES)
|
|
26219
26472
|
return text("upload too large", 413);
|
|
26220
26473
|
const target = join20(realDir, safeName);
|
|
26221
|
-
if (
|
|
26474
|
+
if (relative8(realDir, dirname6(target)) !== "")
|
|
26222
26475
|
return text("invalid filename", 400);
|
|
26223
26476
|
if (existsSync8(target))
|
|
26224
26477
|
return text("file exists", 409);
|
|
@@ -26384,10 +26637,10 @@ async function restoreTrashPath(originalPath, trashPath) {
|
|
|
26384
26637
|
return { ok: false, error: "trash item not found" };
|
|
26385
26638
|
try {
|
|
26386
26639
|
const trashRoot = join20(homedir3(), ".Trash");
|
|
26387
|
-
const trashRelative =
|
|
26640
|
+
const trashRelative = relative8(trashRoot, trashPath);
|
|
26388
26641
|
if (trashRelative === "" || trashRelative.startsWith("..") || trashRelative.startsWith("/") || trashRelative.startsWith("\\"))
|
|
26389
26642
|
return { ok: false, error: "invalid trash handle" };
|
|
26390
|
-
mkdirSync4(
|
|
26643
|
+
mkdirSync4(dirname6(original), { recursive: true });
|
|
26391
26644
|
renameSync(trashPath, original);
|
|
26392
26645
|
return { ok: true };
|
|
26393
26646
|
} catch (error) {
|