





















@@ -11,6 +11,7 @@ const CORE_TEST_CONFIGS = new Set([
11111212const CORE_PROD_CONFIGS = new Set(["tsconfig.core.json"]);
1313const TSGO_SPARSE_SKIP_ENV_KEY = "OPENCLAW_TSGO_SPARSE_SKIP";
14+const CORE_SPARSE_ROOTS = ["packages", "ui/src"];
14151516const CORE_PROD_REQUIRED_PATHS = [
1617{
@@ -53,7 +54,12 @@ export function createSparseTsgoSkipEnv(baseEnv = process.env) {
53545455export function getSparseTsgoGuardError(
5556args,
56-{ cwd = process.cwd(), fileExists = fs.existsSync, isSparseCheckoutEnabled } = {},
57+{
58+ cwd = process.cwd(),
59+ fileExists = fs.existsSync,
60+ isSparseCheckoutEnabled,
61+ sparseCheckoutPatterns,
62+} = {},
5763) {
5864const projectPath = readProjectFlag(args);
5965const projectName = projectPath ? path.basename(projectPath) : null;
@@ -71,20 +77,33 @@ export function getSparseTsgoGuardError(
7177return null;
7278}
737974-const missingPaths = getRequiredPathsForProject(projectName, cwd, fileExists).filter(
75-(relativePath) => !fileExists(path.join(cwd, relativePath)),
76-);
80+const sparsePatterns = sparseCheckoutPatterns ?? getSparseCheckoutPatterns({ cwd });
81+const missingPaths = [
82+ ...getRequiredSparseRootsForProject(projectName).filter((relativePath) =>
83+sparsePatterns ? !isSparseRootCovered(relativePath, sparsePatterns) : false,
84+),
85+ ...getRequiredPathsForProject(projectName, cwd, fileExists).filter(
86+(relativePath) => !fileExists(path.join(cwd, relativePath)),
87+),
88+];
7789if (missingPaths.length === 0) {
7890return null;
7991}
80928193return [
82-`${projectName} cannot be typechecked from this sparse checkout because tracked project inputs are missing:`,
94+`${projectName} cannot be typechecked from this sparse checkout because tracked project inputs are missing or only partially included:`,
8395 ...missingPaths.map((relativePath) => `- ${relativePath}`),
8496"Expand this worktree's sparse checkout to include those paths, or rerun in a full worktree.",
8597].join("\n");
8698}
8799100+function getRequiredSparseRootsForProject(projectName) {
101+if (CORE_PROD_CONFIGS.has(projectName) || CORE_TEST_CONFIGS.has(projectName)) {
102+return CORE_SPARSE_ROOTS;
103+}
104+return [];
105+}
106+88107function getRequiredPathsForProject(projectName, cwd, fileExists) {
89108const requiredPaths = [];
90109if (CORE_PROD_CONFIGS.has(projectName)) {
@@ -117,6 +136,46 @@ function getGitBooleanConfig(name, { cwd }) {
117136return (result.stdout ?? "").trim() === "true";
118137}
119138139+function getSparseCheckoutPatterns({ cwd }) {
140+const result = spawnSync("git", ["sparse-checkout", "list"], {
141+ cwd,
142+encoding: "utf8",
143+stdio: ["ignore", "pipe", "pipe"],
144+shell: process.platform === "win32",
145+});
146+147+if (result.error || (result.status ?? 1) !== 0) {
148+return null;
149+}
150+151+return (result.stdout ?? "")
152+.split(/\r?\n/)
153+.map((line) => line.trim())
154+.filter(Boolean);
155+}
156+157+function isSparseRootCovered(relativeRoot, patterns) {
158+const root = normalizeSparsePattern(relativeRoot);
159+return patterns.some((pattern) => {
160+if (pattern.startsWith("!")) {
161+return false;
162+}
163+164+const normalized = normalizeSparsePattern(pattern);
165+return normalized === root || (normalized.length > 0 && root.startsWith(`${normalized}/`));
166+});
167+}
168+169+function normalizeSparsePattern(pattern) {
170+return pattern
171+.trim()
172+.replaceAll("\\", "/")
173+.replace(/^!/, "")
174+.replace(/^\/+/, "")
175+.replace(/\/\*\*$/, "")
176+.replace(/\/+$/, "");
177+}
178+120179function readProjectFlag(args) {
121180return readFlagValue(args, "-p") ?? readFlagValue(args, "--project");
122181}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。