mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-12 21:53:00 -06:00
fix(tooling): bound tsgo core test memory
This commit is contained in:
+3
-3
@@ -1942,7 +1942,7 @@
|
||||
"tsgo:all": "node scripts/run-tsgo.mjs -b tsconfig.projects.json",
|
||||
"tsgo:core": "node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo",
|
||||
"tsgo:core:all": "node scripts/run-tsgo.mjs -b tsconfig.core.projects.json",
|
||||
"tsgo:core:test": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo",
|
||||
"tsgo:core:test": "node scripts/run-tsgo.mjs -b test/tsconfig/tsconfig.core.test.projects.json",
|
||||
"tsgo:extensions": "node scripts/run-tsgo.mjs -p tsconfig.extensions.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions.tsbuildinfo",
|
||||
"tsgo:extensions:all": "node scripts/run-tsgo.mjs -b tsconfig.extensions.projects.json",
|
||||
"tsgo:extensions:test": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo",
|
||||
@@ -1953,8 +1953,8 @@
|
||||
"tsgo:test:extensions": "pnpm tsgo:extensions:test",
|
||||
"tsgo:test:packages": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.packages.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-packages.tsbuildinfo",
|
||||
"tsgo:test:root": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.root.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-root.tsbuildinfo",
|
||||
"tsgo:test:src": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-src.tsbuildinfo",
|
||||
"tsgo:test:ui": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfo",
|
||||
"tsgo:test:src": "node scripts/run-tsgo.mjs -b test/tsconfig/tsconfig.core.test.src.projects.json",
|
||||
"tsgo:test:ui": "node scripts/run-tsgo.mjs -b test/tsconfig/tsconfig.core.test.ui.projects.json",
|
||||
"tsgo:ui": "node scripts/run-tsgo.mjs -p tsconfig.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/ui.tsbuildinfo",
|
||||
"tui": "node scripts/run-node.mjs tui",
|
||||
"tui:dev": "node --import tsx scripts/run-with-env.mts OPENCLAW_PROFILE=dev -- node scripts/run-node.mjs --dev tui",
|
||||
|
||||
@@ -2,18 +2,28 @@
|
||||
|
||||
// Enforces core tsgo project boundaries and sparse-checkout safety.
|
||||
import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { resolveRepoToolBinPath } from "./lib/local-heavy-check-runtime.mts";
|
||||
import { createManagedCommandInvocation } from "./lib/managed-child-process.mts";
|
||||
import { resolveRepoRoot } from "./lib/repo-root.mjs";
|
||||
import {
|
||||
findTsgoCoreTestShardViolations,
|
||||
TSGO_CORE_TEST_MAX_ROOTS,
|
||||
TSGO_CORE_TEST_SHARDS,
|
||||
} from "./lib/tsgo-core-test-shards.mts";
|
||||
const repoRoot = resolveRepoRoot(import.meta.url);
|
||||
const tsgoPath = resolveRepoToolBinPath("tsgo", { cwd: repoRoot });
|
||||
const canonicalCoreTestConfig = "test/tsconfig/tsconfig.core.test.json";
|
||||
const coreTestProjectsConfig = "test/tsconfig/tsconfig.core.test.projects.json";
|
||||
|
||||
const coreGraphs = [
|
||||
{ name: "core", config: "tsconfig.core.json" },
|
||||
{ name: "ui", config: "tsconfig.ui.json" },
|
||||
{ name: "core-test", config: "test/tsconfig/tsconfig.core.test.json" },
|
||||
{ name: "core-test-agents", config: "test/tsconfig/tsconfig.core.test.agents.json" },
|
||||
{ name: "core-test-non-agents", config: "test/tsconfig/tsconfig.core.test.non-agents.json" },
|
||||
...TSGO_CORE_TEST_SHARDS.map((shard) => ({
|
||||
name: `core-test-${shard.name}`,
|
||||
config: shard.config,
|
||||
})),
|
||||
];
|
||||
function normalizeFilePath(filePath: string) {
|
||||
const normalized = filePath.trim().replaceAll("\\", "/");
|
||||
@@ -46,6 +56,105 @@ function listGraphFiles(graph: (typeof coreGraphs)[number]) {
|
||||
return (result.stdout ?? "").split(/\r?\n/u).map(normalizeFilePath).filter(Boolean);
|
||||
}
|
||||
|
||||
function readGraphConfig(config: string): {
|
||||
compilerOptions?: { tsBuildInfoFile?: string };
|
||||
files?: string[];
|
||||
} {
|
||||
const tsgo = createManagedCommandInvocation({
|
||||
args: ["-p", config, "--pretty", "false", "--showConfig"],
|
||||
bin: tsgoPath,
|
||||
});
|
||||
const result = spawnSync(tsgo.command, tsgo.args, {
|
||||
cwd: repoRoot,
|
||||
encoding: "utf8",
|
||||
maxBuffer: 256 * 1024 * 1024,
|
||||
shell: tsgo.shell,
|
||||
windowsVerbatimArguments: tsgo.windowsVerbatimArguments,
|
||||
});
|
||||
if (result.error) {
|
||||
throw result.error;
|
||||
}
|
||||
if ((result.status ?? 1) !== 0) {
|
||||
const output = [result.stdout, result.stderr].filter(Boolean).join("\n");
|
||||
throw new Error(`${config} config expansion failed with exit code ${result.status}\n${output}`);
|
||||
}
|
||||
return JSON.parse(result.stdout ?? "") as {
|
||||
compilerOptions?: { tsBuildInfoFile?: string };
|
||||
files?: string[];
|
||||
};
|
||||
}
|
||||
|
||||
function listProjectLeaves(config: string, seen = new Set<string>()): string[] {
|
||||
const absoluteConfig = path.resolve(repoRoot, config);
|
||||
if (seen.has(absoluteConfig)) {
|
||||
throw new Error(`Project-reference cycle at ${normalizeFilePath(absoluteConfig)}`);
|
||||
}
|
||||
seen.add(absoluteConfig);
|
||||
const parsed = JSON.parse(fs.readFileSync(absoluteConfig, "utf8")) as {
|
||||
references?: { path: string }[];
|
||||
};
|
||||
if (!parsed.references || parsed.references.length === 0) {
|
||||
return [normalizeFilePath(absoluteConfig)];
|
||||
}
|
||||
return parsed.references.flatMap((reference) => {
|
||||
const referencedConfig = path.resolve(path.dirname(absoluteConfig), reference.path);
|
||||
return listProjectLeaves(path.relative(repoRoot, referencedConfig), seen);
|
||||
});
|
||||
}
|
||||
|
||||
const testRootPattern = /\.test\.(?:ts|tsx)$/u;
|
||||
const canonicalRoots = (readGraphConfig(canonicalCoreTestConfig).files ?? [])
|
||||
.map(normalizeFilePath)
|
||||
.filter((file) => testRootPattern.test(file));
|
||||
const shardConfigs = TSGO_CORE_TEST_SHARDS.map((shard) => ({
|
||||
...shard,
|
||||
expanded: readGraphConfig(shard.config),
|
||||
}));
|
||||
const shardViolations = findTsgoCoreTestShardViolations({
|
||||
canonicalRoots,
|
||||
shards: shardConfigs.map((shard) => ({
|
||||
name: shard.name,
|
||||
roots: (shard.expanded.files ?? [])
|
||||
.map(normalizeFilePath)
|
||||
.filter((file) => testRootPattern.test(file)),
|
||||
})),
|
||||
});
|
||||
|
||||
const expectedLeaves = TSGO_CORE_TEST_SHARDS.map((shard) => shard.config).toSorted();
|
||||
const actualLeaves = listProjectLeaves(coreTestProjectsConfig).toSorted();
|
||||
if (JSON.stringify(actualLeaves) !== JSON.stringify(expectedLeaves)) {
|
||||
shardViolations.push(
|
||||
`${coreTestProjectsConfig} must reference exactly these leaves: ${expectedLeaves.join(", ")}`,
|
||||
);
|
||||
}
|
||||
|
||||
const buildInfoOwners = new Map<string, string[]>();
|
||||
for (const shard of shardConfigs) {
|
||||
const buildInfo = shard.expanded.compilerOptions?.tsBuildInfoFile;
|
||||
if (!buildInfo) {
|
||||
shardViolations.push(`${shard.name}: missing compilerOptions.tsBuildInfoFile`);
|
||||
continue;
|
||||
}
|
||||
const owners = buildInfoOwners.get(buildInfo) ?? [];
|
||||
owners.push(shard.name);
|
||||
buildInfoOwners.set(buildInfo, owners);
|
||||
}
|
||||
for (const [buildInfo, owners] of buildInfoOwners) {
|
||||
if (owners.length > 1) {
|
||||
shardViolations.push(`shared tsBuildInfoFile (${owners.join(", ")}): ${buildInfo}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (shardViolations.length > 0) {
|
||||
console.error(
|
||||
`Core test shards must cover every canonical test root exactly once and stay at or below ${TSGO_CORE_TEST_MAX_ROOTS} roots:`,
|
||||
);
|
||||
for (const violation of shardViolations) {
|
||||
console.error(`- ${violation}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const violations: string[] = [];
|
||||
for (const graph of coreGraphs) {
|
||||
const extensionFiles = listGraphFiles(graph).filter((file) => file.startsWith("extensions/"));
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
export const TSGO_CORE_TEST_MAX_ROOTS = 720;
|
||||
|
||||
export const TSGO_CORE_TEST_SHARDS = [
|
||||
{ name: "agents-root", config: "test/tsconfig/tsconfig.core.test.agents-root.json" },
|
||||
{ name: "agents-other", config: "test/tsconfig/tsconfig.core.test.agents-other.json" },
|
||||
{ name: "gateway", config: "test/tsconfig/tsconfig.core.test.gateway.json" },
|
||||
{ name: "infra", config: "test/tsconfig/tsconfig.core.test.infra.json" },
|
||||
{ name: "commands", config: "test/tsconfig/tsconfig.core.test.commands.json" },
|
||||
{
|
||||
name: "plugins-platform",
|
||||
config: "test/tsconfig/tsconfig.core.test.plugins-platform.json",
|
||||
},
|
||||
{ name: "config-cli", config: "test/tsconfig/tsconfig.core.test.config-cli.json" },
|
||||
{ name: "messaging", config: "test/tsconfig/tsconfig.core.test.messaging.json" },
|
||||
{ name: "services", config: "test/tsconfig/tsconfig.core.test.services.json" },
|
||||
{ name: "other", config: "test/tsconfig/tsconfig.core.test.other.json" },
|
||||
{
|
||||
name: "ui-pages-e2e",
|
||||
config: "test/tsconfig/tsconfig.core.test.ui-pages-e2e.json",
|
||||
},
|
||||
{ name: "ui-other", config: "test/tsconfig/tsconfig.core.test.ui-other.json" },
|
||||
{ name: "packages", config: "test/tsconfig/tsconfig.test.packages.json" },
|
||||
] as const;
|
||||
|
||||
export type TsgoCoreTestShard = (typeof TSGO_CORE_TEST_SHARDS)[number];
|
||||
|
||||
export function findTsgoCoreTestShardViolations(params: {
|
||||
canonicalRoots: readonly string[];
|
||||
maxRoots?: number;
|
||||
shards: readonly { name: string; roots: readonly string[] }[];
|
||||
}): string[] {
|
||||
const maxRoots = params.maxRoots ?? TSGO_CORE_TEST_MAX_ROOTS;
|
||||
const canonical = new Set(params.canonicalRoots);
|
||||
const owners = new Map<string, string[]>();
|
||||
const violations: string[] = [];
|
||||
|
||||
for (const shard of params.shards) {
|
||||
if (shard.roots.length > maxRoots) {
|
||||
violations.push(
|
||||
`${shard.name}: ${shard.roots.length} test roots exceeds the ${maxRoots} limit`,
|
||||
);
|
||||
}
|
||||
for (const root of shard.roots) {
|
||||
const rootOwners = owners.get(root) ?? [];
|
||||
rootOwners.push(shard.name);
|
||||
owners.set(root, rootOwners);
|
||||
}
|
||||
}
|
||||
|
||||
for (const root of canonical) {
|
||||
const rootOwners = owners.get(root) ?? [];
|
||||
if (rootOwners.length === 0) {
|
||||
violations.push(`unassigned: ${root}`);
|
||||
} else if (rootOwners.length > 1) {
|
||||
violations.push(`assigned ${rootOwners.length} times (${rootOwners.join(", ")}): ${root}`);
|
||||
}
|
||||
}
|
||||
for (const [root, rootOwners] of owners) {
|
||||
if (!canonical.has(root)) {
|
||||
violations.push(`not in the canonical core-test graph (${rootOwners.join(", ")}): ${root}`);
|
||||
}
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
@@ -4,19 +4,32 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { readFlagValue } from "./arg-utils.mts";
|
||||
import { createManagedCommandInvocation } from "./managed-child-process.mts";
|
||||
import { TSGO_CORE_TEST_SHARDS } from "./tsgo-core-test-shards.mts";
|
||||
|
||||
const PACKAGE_TEST_CONFIGS = new Set(["tsconfig.test.packages.json"]);
|
||||
const CORE_TEST_CONFIGS = new Set([
|
||||
"tsconfig.core.test.json",
|
||||
"tsconfig.core.test.agents.json",
|
||||
"tsconfig.core.test.non-agents.json",
|
||||
"tsconfig.core.test.projects.json",
|
||||
"tsconfig.core.test.src.projects.json",
|
||||
"tsconfig.core.test.ui.projects.json",
|
||||
...TSGO_CORE_TEST_SHARDS.map((shard) => path.basename(shard.config)).filter(
|
||||
(config) => !PACKAGE_TEST_CONFIGS.has(config),
|
||||
),
|
||||
]);
|
||||
|
||||
const CORE_PROD_CONFIGS = new Set(["tsconfig.core.json"]);
|
||||
const UI_PROD_CONFIGS = new Set(["tsconfig.ui.json"]);
|
||||
const GUARDED_CONFIGS = new Set([
|
||||
...CORE_PROD_CONFIGS,
|
||||
...UI_PROD_CONFIGS,
|
||||
...CORE_TEST_CONFIGS,
|
||||
...PACKAGE_TEST_CONFIGS,
|
||||
]);
|
||||
const TSGO_SPARSE_SKIP_ENV_KEY = "OPENCLAW_TSGO_SPARSE_SKIP";
|
||||
const CORE_PROD_SPARSE_ROOTS = ["packages"];
|
||||
const UI_PROD_SPARSE_ROOTS = ["packages", "src", "ui/config", "ui/src"];
|
||||
const CORE_TEST_SPARSE_ROOTS = ["packages", "ui/config", "ui/src"];
|
||||
const PACKAGE_TEST_SPARSE_ROOTS = ["packages"];
|
||||
|
||||
const CORE_PROD_REQUIRED_PATHS = [
|
||||
{
|
||||
@@ -100,15 +113,8 @@ export function getSparseTsgoGuardError(
|
||||
sparseCheckoutPatterns,
|
||||
}: SparseGuardOptions = {},
|
||||
) {
|
||||
const projectPath = readProjectFlag(args);
|
||||
const projectName = projectPath ? path.basename(projectPath) : null;
|
||||
if (
|
||||
!projectName ||
|
||||
(!CORE_PROD_CONFIGS.has(projectName) &&
|
||||
!UI_PROD_CONFIGS.has(projectName) &&
|
||||
!CORE_TEST_CONFIGS.has(projectName)) ||
|
||||
isMetadataOnlyCommand(args)
|
||||
) {
|
||||
const projectNames = readProjectNames(args);
|
||||
if (projectNames.length === 0 || isMetadataOnlyCommand(args)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -120,11 +126,17 @@ export function getSparseTsgoGuardError(
|
||||
|
||||
const sparsePatterns = sparseCheckoutPatterns ?? getSparseCheckoutPatterns({ cwd });
|
||||
const missingPaths = [
|
||||
...getRequiredSparseRootsForProject(projectName).filter((relativePath) =>
|
||||
sparsePatterns ? !isSparseRootCovered(relativePath, sparsePatterns) : false,
|
||||
...new Set(
|
||||
projectNames
|
||||
.flatMap(getRequiredSparseRootsForProject)
|
||||
.filter((relativePath) =>
|
||||
sparsePatterns ? !isSparseRootCovered(relativePath, sparsePatterns) : false,
|
||||
),
|
||||
),
|
||||
...getRequiredPathsForProject(projectName, cwd, fileExists).filter(
|
||||
(relativePath) => !fileExists(path.join(cwd, relativePath)),
|
||||
...new Set(
|
||||
projectNames
|
||||
.flatMap((projectName) => getRequiredPathsForProject(projectName, cwd, fileExists))
|
||||
.filter((relativePath) => !fileExists(path.join(cwd, relativePath))),
|
||||
),
|
||||
];
|
||||
if (missingPaths.length === 0) {
|
||||
@@ -132,7 +144,7 @@ export function getSparseTsgoGuardError(
|
||||
}
|
||||
|
||||
return [
|
||||
`${projectName} cannot be typechecked from this sparse checkout because tracked project inputs are missing or only partially included:`,
|
||||
`${projectNames.join(", ")} cannot be typechecked from this sparse checkout because tracked project inputs are missing or only partially included:`,
|
||||
...missingPaths.map((relativePath) => `- ${relativePath}`),
|
||||
"Expand this worktree's sparse checkout to include those paths, or rerun in a full worktree.",
|
||||
].join("\n");
|
||||
@@ -148,6 +160,9 @@ function getRequiredSparseRootsForProject(projectName: string) {
|
||||
if (CORE_TEST_CONFIGS.has(projectName)) {
|
||||
return CORE_TEST_SPARSE_ROOTS;
|
||||
}
|
||||
if (PACKAGE_TEST_CONFIGS.has(projectName)) {
|
||||
return PACKAGE_TEST_SPARSE_ROOTS;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -236,8 +251,20 @@ function normalizeSparsePattern(pattern: string) {
|
||||
.replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
function readProjectFlag(args: readonly string[]) {
|
||||
return readFlagValue(args, "-p") ?? readFlagValue(args, "--project");
|
||||
function readProjectNames(args: readonly string[]) {
|
||||
const projectPath = readFlagValue(args, "-p") ?? readFlagValue(args, "--project");
|
||||
const candidates = projectPath
|
||||
? [projectPath]
|
||||
: args.some((arg) => arg === "-b" || arg === "--build")
|
||||
? args.filter((arg) => !arg.startsWith("-"))
|
||||
: [];
|
||||
return [
|
||||
...new Set(candidates.map((candidate) => path.basename(candidate)).filter(isGuardedConfig)),
|
||||
];
|
||||
}
|
||||
|
||||
function isGuardedConfig(config: string) {
|
||||
return GUARDED_CONFIGS.has(config);
|
||||
}
|
||||
|
||||
function isMetadataOnlyCommand(args: readonly string[]) {
|
||||
|
||||
+37
-26
@@ -14,10 +14,23 @@ import {
|
||||
} from "./lib/local-heavy-check-runtime.mts";
|
||||
import { createManagedCommandInvocation } from "./lib/managed-child-process.mts";
|
||||
import { resolveRepoRoot } from "./lib/repo-root.mjs";
|
||||
import { TSGO_CORE_TEST_SHARDS, type TsgoCoreTestShard } from "./lib/tsgo-core-test-shards.mts";
|
||||
const repoRoot = resolveRepoRoot(import.meta.url);
|
||||
const artifactRoot = path.resolve(repoRoot, ".artifacts/tsgo-profile");
|
||||
const tsgoPath = resolveRepoToolBinPath("tsgo", { cwd: repoRoot });
|
||||
|
||||
type GraphDefinition = { config: string; description: string };
|
||||
type CoreTestGraphName = `core-test-${TsgoCoreTestShard["name"]}`;
|
||||
const CORE_TEST_GRAPH_DEFINITIONS = Object.fromEntries(
|
||||
TSGO_CORE_TEST_SHARDS.map((shard) => [
|
||||
`core-test-${shard.name}`,
|
||||
{
|
||||
config: shard.config,
|
||||
description: `bounded core test shard: ${shard.name}`,
|
||||
},
|
||||
]),
|
||||
) as Record<CoreTestGraphName, GraphDefinition>;
|
||||
|
||||
const GRAPH_DEFINITIONS = {
|
||||
core: {
|
||||
config: "tsconfig.core.json",
|
||||
@@ -27,18 +40,7 @@ const GRAPH_DEFINITIONS = {
|
||||
config: "tsconfig.ui.json",
|
||||
description: "UI production graph",
|
||||
},
|
||||
"core-test": {
|
||||
config: "test/tsconfig/tsconfig.core.test.json",
|
||||
description: "core colocated test graph",
|
||||
},
|
||||
"core-test-agents": {
|
||||
config: "test/tsconfig/tsconfig.core.test.agents.json",
|
||||
description: "diagnostic slice: core agent colocated tests",
|
||||
},
|
||||
"core-test-non-agents": {
|
||||
config: "test/tsconfig/tsconfig.core.test.non-agents.json",
|
||||
description: "diagnostic slice: core tests excluding agent test roots",
|
||||
},
|
||||
...CORE_TEST_GRAPH_DEFINITIONS,
|
||||
extensions: {
|
||||
config: "tsconfig.extensions.json",
|
||||
description: "bundled extension production graph",
|
||||
@@ -50,6 +52,10 @@ const GRAPH_DEFINITIONS = {
|
||||
} as const;
|
||||
|
||||
type GraphName = keyof typeof GRAPH_DEFINITIONS;
|
||||
const DEFAULT_GRAPHS = [
|
||||
...TSGO_CORE_TEST_SHARDS.map((shard) => `core-test-${shard.name}` as CoreTestGraphName),
|
||||
"extensions-test",
|
||||
] satisfies GraphName[];
|
||||
type ProfileOptions = {
|
||||
all: boolean;
|
||||
deep: boolean;
|
||||
@@ -73,19 +79,19 @@ function usage(): string {
|
||||
"",
|
||||
"Graphs:",
|
||||
...Object.entries(GRAPH_DEFINITIONS).map(
|
||||
([name, graph]) => ` ${name.padEnd(16)} ${graph.description}`,
|
||||
([name, graph]) => ` ${name.padEnd(26)} ${graph.description}`,
|
||||
),
|
||||
"",
|
||||
"Options:",
|
||||
" --all Profile all graphs",
|
||||
" --reuse Reuse profile tsbuildinfo files instead of forcing fresh checks",
|
||||
" --deep Also write --generateTrace and --generateCpuProfile artifacts",
|
||||
" --explain Also write --explainFiles artifacts",
|
||||
" --deep Also write --generateTrace and --pprofDir artifacts",
|
||||
" --explain Also write list-only --explainFiles artifacts",
|
||||
" --out=<dir> Output directory (default: .artifacts/tsgo-profile)",
|
||||
" --json Print JSON report to stdout",
|
||||
" --help Show this help",
|
||||
"",
|
||||
"Default graphs: core-test extensions-test",
|
||||
"Default graphs: all bounded core-test shards and extensions-test",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@@ -138,7 +144,7 @@ function parseArgs(argv: string[]): { options: ProfileOptions; selectedGraphs: G
|
||||
? (Object.keys(GRAPH_DEFINITIONS) as GraphName[])
|
||||
: graphNames.length > 0
|
||||
? graphNames
|
||||
: (["core-test", "extensions-test"] satisfies GraphName[]);
|
||||
: DEFAULT_GRAPHS;
|
||||
|
||||
return { options, selectedGraphs };
|
||||
}
|
||||
@@ -351,7 +357,7 @@ function renderTextReport(report: ProfileReport): string {
|
||||
lines.push(`- ${group.key}: ${group.count}`);
|
||||
}
|
||||
if (graph.deep) {
|
||||
lines.push(`Deep artifacts: ${graph.deep.traceDir}, ${graph.deep.cpuProfile}`);
|
||||
lines.push(`Deep artifacts: ${graph.deep.traceDir}, ${graph.deep.profileDir}`);
|
||||
}
|
||||
if (graph.explain) {
|
||||
lines.push(`Explain: ${graph.explain.artifact}`);
|
||||
@@ -397,25 +403,30 @@ function profileGraph(name: GraphName, options: ProfileOptions) {
|
||||
checkBuildInfo,
|
||||
"--extendedDiagnostics",
|
||||
];
|
||||
let deep: { cpuProfile: string; traceDir: string } | undefined;
|
||||
let deep: { profileDir: string; traceDir: string } | undefined;
|
||||
if (options.deep) {
|
||||
const traceDir = path.join(outDir, `${name}-trace`);
|
||||
const cpuProfile = path.join(outDir, `${name}.cpuprofile`);
|
||||
const profileDir = path.join(outDir, `${name}-pprof`);
|
||||
fs.rmSync(traceDir, { force: true, recursive: true });
|
||||
fs.rmSync(cpuProfile, { force: true });
|
||||
checkArgs.push("--generateTrace", traceDir, "--generateCpuProfile", cpuProfile);
|
||||
fs.rmSync(profileDir, { force: true, recursive: true });
|
||||
fs.mkdirSync(profileDir, { recursive: true });
|
||||
checkArgs.push("--generateTrace", traceDir, "--pprofDir", profileDir);
|
||||
deep = {
|
||||
traceDir: path.relative(repoRoot, traceDir),
|
||||
cpuProfile: path.relative(repoRoot, cpuProfile),
|
||||
profileDir: path.relative(repoRoot, profileDir),
|
||||
};
|
||||
}
|
||||
const check = runTsgo(`${name}:check`, checkArgs);
|
||||
let explain: { artifact: string; elapsedMs: number } | undefined;
|
||||
if (options.explain) {
|
||||
const explainArtifact = path.join(outDir, `${name}.explain.txt`);
|
||||
const explainResult = runTsgo(`${name}:explainFiles`, [...baseArgs, "--explainFiles"], {
|
||||
maxBuffer: 256 * 1024 * 1024,
|
||||
});
|
||||
const explainResult = runTsgo(
|
||||
`${name}:explainFiles`,
|
||||
[...baseArgs, "--listFilesOnly", "--explainFiles"],
|
||||
{
|
||||
maxBuffer: 256 * 1024 * 1024,
|
||||
},
|
||||
);
|
||||
fs.writeFileSync(explainArtifact, `${explainResult.stdout}${explainResult.stderr}`);
|
||||
explain = {
|
||||
artifact: path.relative(repoRoot, explainArtifact),
|
||||
|
||||
@@ -84,7 +84,7 @@ describe("run-tsgo sparse guard", () => {
|
||||
}
|
||||
|
||||
expect(
|
||||
getSparseTsgoGuardError(["-p", "test/tsconfig/tsconfig.core.test.non-agents.json"], {
|
||||
getSparseTsgoGuardError(["-p", "test/tsconfig/tsconfig.core.test.other.json"], {
|
||||
cwd,
|
||||
isSparseCheckoutEnabled: () => true,
|
||||
sparseCheckoutPatterns: ["/packages/", "/ui/config/", "/ui/src/"],
|
||||
@@ -92,6 +92,50 @@ describe("run-tsgo sparse guard", () => {
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("guards the core-test build aggregate", () => {
|
||||
const cwd = createTempDir("openclaw-run-tsgo-");
|
||||
|
||||
expect(
|
||||
getSparseTsgoGuardError(["-b", "test/tsconfig/tsconfig.core.test.projects.json"], {
|
||||
cwd,
|
||||
isSparseCheckoutEnabled: () => true,
|
||||
}),
|
||||
).toContain("tsconfig.core.test.projects.json cannot be typechecked from this sparse checkout");
|
||||
});
|
||||
|
||||
it("guards core-test build projects after options and alongside other projects", () => {
|
||||
const cwd = createTempDir("openclaw-run-tsgo-");
|
||||
|
||||
expect(
|
||||
getSparseTsgoGuardError(
|
||||
[
|
||||
"-b",
|
||||
"--pretty",
|
||||
"false",
|
||||
"tsconfig.extensions.json",
|
||||
"test/tsconfig/tsconfig.core.test.projects.json",
|
||||
],
|
||||
{
|
||||
cwd,
|
||||
isSparseCheckoutEnabled: () => true,
|
||||
},
|
||||
),
|
||||
).toContain("tsconfig.core.test.projects.json cannot be typechecked from this sparse checkout");
|
||||
});
|
||||
|
||||
it("keeps package-test sparse roots package-scoped", () => {
|
||||
const cwd = createTempDir("openclaw-run-tsgo-");
|
||||
|
||||
expect(
|
||||
getSparseTsgoGuardError(["-p", "test/tsconfig/tsconfig.test.packages.json"], {
|
||||
cwd,
|
||||
fileExists: () => true,
|
||||
isSparseCheckoutEnabled: () => true,
|
||||
sparseCheckoutPatterns: ["/packages/"],
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("rejects sparse core worktrees that include only selected ui and package files", () => {
|
||||
const cwd = createTempDir("openclaw-run-tsgo-");
|
||||
const requiredPaths = [
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { findTsgoCoreTestShardViolations } from "../../scripts/lib/tsgo-core-test-shards.mts";
|
||||
|
||||
describe("tsgo core test shards", () => {
|
||||
it("accepts an exact once-only partition within the root budget", () => {
|
||||
expect(
|
||||
findTsgoCoreTestShardViolations({
|
||||
canonicalRoots: ["src/a.test.ts", "src/b.test.ts"],
|
||||
maxRoots: 1,
|
||||
shards: [
|
||||
{ name: "a", roots: ["src/a.test.ts"] },
|
||||
{ name: "b", roots: ["src/b.test.ts"] },
|
||||
],
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("reports missing, duplicate, extra, and oversized shard roots", () => {
|
||||
expect(
|
||||
findTsgoCoreTestShardViolations({
|
||||
canonicalRoots: ["src/a.test.ts", "src/b.test.ts", "src/missing.test.ts"],
|
||||
maxRoots: 1,
|
||||
shards: [
|
||||
{ name: "first", roots: ["src/a.test.ts", "src/b.test.ts"] },
|
||||
{ name: "second", roots: ["src/b.test.ts", "src/extra.test.ts"] },
|
||||
],
|
||||
}),
|
||||
).toEqual([
|
||||
"first: 2 test roots exceeds the 1 limit",
|
||||
"second: 2 test roots exceeds the 1 limit",
|
||||
"assigned 2 times (first, second): src/b.test.ts",
|
||||
"unassigned: src/missing.test.ts",
|
||||
"not in the canonical core-test graph (second): src/extra.test.ts",
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-agents-other.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/agents/**/*.test.ts",
|
||||
"../../src/agents/**/*.test.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"../../node_modules",
|
||||
"../../dist",
|
||||
"../../**/dist/**",
|
||||
"../../src/agents/*.test.ts",
|
||||
"../../src/agents/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-agents-root.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/agents/*.test.ts",
|
||||
"../../src/agents/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.test.json",
|
||||
"include": [
|
||||
"../../src/**/*.d.ts",
|
||||
"../../src/agents/**/*.test.ts",
|
||||
"../../src/agents/**/*.test.tsx",
|
||||
"../../ui/**/*.d.ts",
|
||||
"../../packages/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-commands.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/commands/**/*.test.ts",
|
||||
"../../src/commands/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-config-cli.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/config/**/*.test.ts",
|
||||
"../../src/config/**/*.test.tsx",
|
||||
"../../src/cli/**/*.test.ts",
|
||||
"../../src/cli/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-gateway.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/gateway/**/*.test.ts",
|
||||
"../../src/gateway/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-infra.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/infra/**/*.test.ts",
|
||||
"../../src/infra/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-messaging.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/auto-reply/**/*.test.ts",
|
||||
"../../src/auto-reply/**/*.test.tsx",
|
||||
"../../src/channels/**/*.test.ts",
|
||||
"../../src/channels/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.json",
|
||||
"exclude": [
|
||||
"../../node_modules",
|
||||
"../../dist",
|
||||
"../../**/dist/**",
|
||||
"../../src/agents/**/*.test.ts",
|
||||
"../../src/agents/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-other.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/**/*.test.ts",
|
||||
"../../src/**/*.test.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"../../node_modules",
|
||||
"../../dist",
|
||||
"../../**/dist/**",
|
||||
"../../src/agents/**",
|
||||
"../../src/gateway/**",
|
||||
"../../src/infra/**",
|
||||
"../../src/commands/**",
|
||||
"../../src/plugins/**",
|
||||
"../../src/config/**",
|
||||
"../../src/cli/**",
|
||||
"../../src/auto-reply/**",
|
||||
"../../src/channels/**",
|
||||
"../../src/cron/**",
|
||||
"../../src/plugin-sdk/**",
|
||||
"../../src/skills/**",
|
||||
"../../src/secrets/**",
|
||||
"../../src/shared/**",
|
||||
"../../src/security/**",
|
||||
"../../src/acp/**",
|
||||
"../../src/tui/**",
|
||||
"../../src/media/**",
|
||||
"../../src/system-agent/**",
|
||||
"../../src/logging/**",
|
||||
"../../src/hooks/**",
|
||||
"../../src/daemon/**"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-plugins-platform.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/plugins/**/*.test.ts",
|
||||
"../../src/plugins/**/*.test.tsx",
|
||||
"../../src/security/**/*.test.ts",
|
||||
"../../src/security/**/*.test.tsx",
|
||||
"../../src/acp/**/*.test.ts",
|
||||
"../../src/acp/**/*.test.tsx",
|
||||
"../../src/tui/**/*.test.ts",
|
||||
"../../src/tui/**/*.test.tsx",
|
||||
"../../src/media/**/*.test.ts",
|
||||
"../../src/media/**/*.test.tsx",
|
||||
"../../src/system-agent/**/*.test.ts",
|
||||
"../../src/system-agent/**/*.test.tsx",
|
||||
"../../src/logging/**/*.test.ts",
|
||||
"../../src/logging/**/*.test.tsx",
|
||||
"../../src/hooks/**/*.test.ts",
|
||||
"../../src/hooks/**/*.test.tsx",
|
||||
"../../src/daemon/**/*.test.ts",
|
||||
"../../src/daemon/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.core.test.src.projects.json" },
|
||||
{ "path": "./tsconfig.core.test.ui.projects.json" },
|
||||
{ "path": "./tsconfig.test.packages.json" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-services.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/cron/**/*.test.ts",
|
||||
"../../src/cron/**/*.test.tsx",
|
||||
"../../src/plugin-sdk/**/*.test.ts",
|
||||
"../../src/plugin-sdk/**/*.test.tsx",
|
||||
"../../src/skills/**/*.test.ts",
|
||||
"../../src/skills/**/*.test.tsx",
|
||||
"../../src/secrets/**/*.test.ts",
|
||||
"../../src/secrets/**/*.test.tsx",
|
||||
"../../src/shared/**/*.test.ts",
|
||||
"../../src/shared/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.json",
|
||||
"files": [
|
||||
"../../src/config/sessions/session-entry.test-compat.d.ts",
|
||||
"../../src/infra/host-env-security-policy.d.ts",
|
||||
"../../src/state/openclaw-agent-db.generated.d.ts",
|
||||
"../../src/state/openclaw-state-db.generated.d.ts",
|
||||
"../../src/types/agent-sessions.d.ts",
|
||||
"../../src/types/microsoft-teams-sdk.d.ts",
|
||||
"../../src/types/node-runtime-globals.d.ts",
|
||||
"../../src/types/qrcode.d.ts",
|
||||
"../../ui/src/css.d.ts",
|
||||
"../../ui/src/i18n/virtual-locale.d.ts",
|
||||
"../../ui/src/markdown-it-task-lists.d.ts",
|
||||
"../../ui/src/types/highlight-js-subpaths.d.ts",
|
||||
"../../ui/src/types/novnc.d.ts"
|
||||
],
|
||||
"include": []
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.core.test.agents-root.json" },
|
||||
{ "path": "./tsconfig.core.test.agents-other.json" },
|
||||
{ "path": "./tsconfig.core.test.gateway.json" },
|
||||
{ "path": "./tsconfig.core.test.infra.json" },
|
||||
{ "path": "./tsconfig.core.test.commands.json" },
|
||||
{ "path": "./tsconfig.core.test.plugins-platform.json" },
|
||||
{ "path": "./tsconfig.core.test.config-cli.json" },
|
||||
{ "path": "./tsconfig.core.test.messaging.json" },
|
||||
{ "path": "./tsconfig.core.test.services.json" },
|
||||
{ "path": "./tsconfig.core.test.other.json" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-ui-other.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../ui/src/main.ts",
|
||||
"../../ui/**/*.test.ts",
|
||||
"../../ui/**/*.test.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"../../node_modules",
|
||||
"../../dist",
|
||||
"../../**/dist/**",
|
||||
"../../ui/src/pages/**",
|
||||
"../../ui/src/e2e/**"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/core-test-ui-pages-e2e.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../ui/src/main.ts",
|
||||
"../../ui/src/pages/**/*.test.ts",
|
||||
"../../ui/src/pages/**/*.test.tsx",
|
||||
"../../ui/src/e2e/**/*.test.ts",
|
||||
"../../ui/src/e2e/**/*.test.tsx"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.core.test.ui-pages-e2e.json" },
|
||||
{ "path": "./tsconfig.core.test.ui-other.json" }
|
||||
]
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.test.json",
|
||||
"extends": "./tsconfig.core.test.shard.json",
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "../../.artifacts/tsgo-cache/test-packages.tsbuildinfo"
|
||||
},
|
||||
"include": [
|
||||
"../../src/**/*.d.ts",
|
||||
"../../ui/**/*.d.ts",
|
||||
"../../extensions/**/*.d.ts",
|
||||
"../../packages/**/*.d.ts",
|
||||
"../../packages/**/*.test.ts",
|
||||
"../../packages/**/*.test.tsx"
|
||||
]
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.test.json",
|
||||
"compilerOptions": {
|
||||
// Retained plain-Node script exceptions are imported by their owner tests.
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"../../src/**/*.d.ts",
|
||||
"../../src/**/*.test.ts",
|
||||
"../../src/**/*.test.tsx",
|
||||
"../../ui/**/*.d.ts",
|
||||
"../../ui/src/main.ts",
|
||||
"../../extensions/**/*.d.ts",
|
||||
"../../packages/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "./tsconfig.test.json",
|
||||
"include": [
|
||||
"../../src/**/*.d.ts",
|
||||
"../../ui/**/*.d.ts",
|
||||
"../../ui/**/*.test.ts",
|
||||
"../../ui/**/*.test.tsx",
|
||||
"../../extensions/**/*.d.ts",
|
||||
"../../packages/**/*.d.ts"
|
||||
]
|
||||
}
|
||||
@@ -3,6 +3,6 @@
|
||||
"references": [
|
||||
{ "path": "./tsconfig.core.json" },
|
||||
{ "path": "./tsconfig.ui.json" },
|
||||
{ "path": "./test/tsconfig/tsconfig.core.test.json" }
|
||||
{ "path": "./test/tsconfig/tsconfig.core.test.projects.json" }
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user