Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/scripts/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 42 kB image not shown  

Quelle  test-projects.test-support.mjs   Sprache: unbekannt

 
Spracherkennung für: .mjs vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

import { execFileSync } from "node:child_process";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import { isChannelSurfaceTestFile } from "../test/vitest/vitest.channel-paths.mjs";
import {
  isCommandsLightTarget,
  resolveCommandsLightIncludePattern,
} from "../test/vitest/vitest.commands-light-paths.mjs";
import { isAcpxExtensionRoot } from "../test/vitest/vitest.extension-acpx-paths.mjs";
import { isBlueBubblesExtensionRoot } from "../test/vitest/vitest.extension-bluebubbles-paths.mjs";
import { isBrowserExtensionRoot } from "../test/vitest/vitest.extension-browser-paths.mjs";
import { resolveSplitChannelExtensionShard } from "../test/vitest/vitest.extension-channel-split-paths.mjs";
import { isDiffsExtensionRoot } from "../test/vitest/vitest.extension-diffs-paths.mjs";
import { isFeishuExtensionRoot } from "../test/vitest/vitest.extension-feishu-paths.mjs";
import { isIrcExtensionRoot } from "../test/vitest/vitest.extension-irc-paths.mjs";
import { isMatrixExtensionRoot } from "../test/vitest/vitest.extension-matrix-paths.mjs";
import { isMattermostExtensionRoot } from "../test/vitest/vitest.extension-mattermost-paths.mjs";
import { isMediaExtensionRoot } from "../test/vitest/vitest.extension-media-paths.mjs";
import { isMemoryExtensionRoot } from "../test/vitest/vitest.extension-memory-paths.mjs";
import { isMessagingExtensionRoot } from "../test/vitest/vitest.extension-messaging-paths.mjs";
import { isMiscExtensionRoot } from "../test/vitest/vitest.extension-misc-paths.mjs";
import { isMsTeamsExtensionRoot } from "../test/vitest/vitest.extension-msteams-paths.mjs";
import {
  isProviderExtensionRoot,
  isProviderOpenAiExtensionRoot,
} from "../test/vitest/vitest.extension-provider-paths.mjs";
import { isQaExtensionRoot } from "../test/vitest/vitest.extension-qa-paths.mjs";
import { isTelegramExtensionRoot } from "../test/vitest/vitest.extension-telegram-paths.mjs";
import { isVoiceCallExtensionRoot } from "../test/vitest/vitest.extension-voice-call-paths.mjs";
import { isWhatsAppExtensionRoot } from "../test/vitest/vitest.extension-whatsapp-paths.mjs";
import { isZaloExtensionRoot } from "../test/vitest/vitest.extension-zalo-paths.mjs";
import {
  isPluginSdkLightTarget,
  resolvePluginSdkLightIncludePattern,
} from "../test/vitest/vitest.plugin-sdk-paths.mjs";
import { fullSuiteVitestShards } from "../test/vitest/vitest.test-shards.mjs";
import { resolveUnitFastTestIncludePattern } from "../test/vitest/vitest.unit-fast-paths.mjs";
import {
  isBoundaryTestFile,
  isBundledPluginDependentUnitTestFile,
} from "../test/vitest/vitest.unit-paths.mjs";
import { detectChangedLanes } from "./changed-lanes.mjs";
import { isCiLikeEnv, resolveLocalFullSuiteProfile } from "./lib/vitest-local-scheduling.mjs";
import { resolveVitestCliEntry, resolveVitestNodeArgs } from "./run-vitest.mjs";

const DEFAULT_VITEST_CONFIG = "test/vitest/vitest.unit.config.ts";
const AGENTS_VITEST_CONFIG = "test/vitest/vitest.agents.config.ts";
const ACP_VITEST_CONFIG = "test/vitest/vitest.acp.config.ts";
const AUTO_REPLY_CORE_VITEST_CONFIG = "test/vitest/vitest.auto-reply-core.config.ts";
const AUTO_REPLY_VITEST_CONFIG = "test/vitest/vitest.auto-reply.config.ts";
const AUTO_REPLY_REPLY_VITEST_CONFIG = "test/vitest/vitest.auto-reply-reply.config.ts";
const AUTO_REPLY_TOP_LEVEL_VITEST_CONFIG = "test/vitest/vitest.auto-reply-top-level.config.ts";
const BOUNDARY_VITEST_CONFIG = "test/vitest/vitest.boundary.config.ts";
const BUNDLED_VITEST_CONFIG = "test/vitest/vitest.bundled.config.ts";
const CHANNEL_VITEST_CONFIG = "test/vitest/vitest.channels.config.ts";
const CLI_VITEST_CONFIG = "test/vitest/vitest.cli.config.ts";
const COMMANDS_LIGHT_VITEST_CONFIG = "test/vitest/vitest.commands-light.config.ts";
const COMMANDS_VITEST_CONFIG = "test/vitest/vitest.commands.config.ts";
const CONTRACTS_CHANNEL_CONFIG_VITEST_CONFIG =
  "test/vitest/vitest.contracts-channel-config.config.ts";
const CONTRACTS_CHANNEL_REGISTRY_VITEST_CONFIG =
  "test/vitest/vitest.contracts-channel-registry.config.ts";
const CONTRACTS_CHANNEL_SESSION_VITEST_CONFIG =
  "test/vitest/vitest.contracts-channel-session.config.ts";
const CONTRACTS_CHANNEL_SURFACE_VITEST_CONFIG =
  "test/vitest/vitest.contracts-channel-surface.config.ts";
const CONTRACTS_PLUGIN_VITEST_CONFIG = "test/vitest/vitest.contracts-plugin.config.ts";
const CRON_VITEST_CONFIG = "test/vitest/vitest.cron.config.ts";
const DAEMON_VITEST_CONFIG = "test/vitest/vitest.daemon.config.ts";
const E2E_VITEST_CONFIG = "test/vitest/vitest.e2e.config.ts";
const EXTENSION_ACPX_VITEST_CONFIG = "test/vitest/vitest.extension-acpx.config.ts";
const EXTENSION_BLUEBUBBLES_VITEST_CONFIG = "test/vitest/vitest.extension-bluebubbles.config.ts";
const EXTENSION_BROWSER_VITEST_CONFIG = "test/vitest/vitest.extension-browser.config.ts";
const EXTENSION_CHANNELS_VITEST_CONFIG = "test/vitest/vitest.extension-channels.config.ts";
const EXTENSION_DIFFS_VITEST_CONFIG = "test/vitest/vitest.extension-diffs.config.ts";
const EXTENSION_DISCORD_VITEST_CONFIG = "test/vitest/vitest.extension-discord.config.ts";
const EXTENSION_FEISHU_VITEST_CONFIG = "test/vitest/vitest.extension-feishu.config.ts";
const EXTENSION_IMESSAGE_VITEST_CONFIG = "test/vitest/vitest.extension-imessage.config.ts";
const EXTENSION_IRC_VITEST_CONFIG = "test/vitest/vitest.extension-irc.config.ts";
const EXTENSION_LINE_VITEST_CONFIG = "test/vitest/vitest.extension-line.config.ts";
const EXTENSION_MATTERMOST_VITEST_CONFIG = "test/vitest/vitest.extension-mattermost.config.ts";
const EXTENSION_MEDIA_VITEST_CONFIG = "test/vitest/vitest.extension-media.config.ts";
const EXTENSION_MATRIX_VITEST_CONFIG = "test/vitest/vitest.extension-matrix.config.ts";
const EXTENSION_MEMORY_VITEST_CONFIG = "test/vitest/vitest.extension-memory.config.ts";
const EXTENSION_MSTEAMS_VITEST_CONFIG = "test/vitest/vitest.extension-msteams.config.ts";
const EXTENSION_MESSAGING_VITEST_CONFIG = "test/vitest/vitest.extension-messaging.config.ts";
const EXTENSION_MISC_VITEST_CONFIG = "test/vitest/vitest.extension-misc.config.ts";
const EXTENSION_PROVIDER_OPENAI_VITEST_CONFIG =
  "test/vitest/vitest.extension-provider-openai.config.ts";
const EXTENSION_PROVIDERS_VITEST_CONFIG = "test/vitest/vitest.extension-providers.config.ts";
const EXTENSION_QA_VITEST_CONFIG = "test/vitest/vitest.extension-qa.config.ts";
const EXTENSION_SIGNAL_VITEST_CONFIG = "test/vitest/vitest.extension-signal.config.ts";
const EXTENSION_SLACK_VITEST_CONFIG = "test/vitest/vitest.extension-slack.config.ts";
const EXTENSION_TELEGRAM_VITEST_CONFIG = "test/vitest/vitest.extension-telegram.config.ts";
const EXTENSION_VOICE_CALL_VITEST_CONFIG = "test/vitest/vitest.extension-voice-call.config.ts";
const EXTENSION_WHATSAPP_VITEST_CONFIG = "test/vitest/vitest.extension-whatsapp.config.ts";
const EXTENSION_ZALO_VITEST_CONFIG = "test/vitest/vitest.extension-zalo.config.ts";
const EXTENSIONS_VITEST_CONFIG = "test/vitest/vitest.extensions.config.ts";
const FULL_EXTENSIONS_VITEST_CONFIG = "test/vitest/vitest.full-extensions.config.ts";
const GATEWAY_CLIENT_VITEST_CONFIG = "test/vitest/vitest.gateway-client.config.ts";
const GATEWAY_CORE_VITEST_CONFIG = "test/vitest/vitest.gateway-core.config.ts";
const GATEWAY_METHODS_VITEST_CONFIG = "test/vitest/vitest.gateway-methods.config.ts";
const GATEWAY_SERVER_VITEST_CONFIG = "test/vitest/vitest.gateway-server.config.ts";
const GATEWAY_VITEST_CONFIG = "test/vitest/vitest.gateway.config.ts";
const HOOKS_VITEST_CONFIG = "test/vitest/vitest.hooks.config.ts";
const INFRA_VITEST_CONFIG = "test/vitest/vitest.infra.config.ts";
const MEDIA_VITEST_CONFIG = "test/vitest/vitest.media.config.ts";
const MEDIA_UNDERSTANDING_VITEST_CONFIG = "test/vitest/vitest.media-understanding.config.ts";
const LOGGING_VITEST_CONFIG = "test/vitest/vitest.logging.config.ts";
const PLUGIN_SDK_LIGHT_VITEST_CONFIG = "test/vitest/vitest.plugin-sdk-light.config.ts";
const PLUGIN_SDK_VITEST_CONFIG = "test/vitest/vitest.plugin-sdk.config.ts";
const PLUGINS_VITEST_CONFIG = "test/vitest/vitest.plugins.config.ts";
const UNIT_FAST_VITEST_CONFIG = "test/vitest/vitest.unit-fast.config.ts";
const UNIT_SECURITY_VITEST_CONFIG = "test/vitest/vitest.unit-security.config.ts";
const UNIT_SRC_VITEST_CONFIG = "test/vitest/vitest.unit-src.config.ts";
const UNIT_SUPPORT_VITEST_CONFIG = "test/vitest/vitest.unit-support.config.ts";
const UNIT_UI_VITEST_CONFIG = "test/vitest/vitest.unit-ui.config.ts";
const PROCESS_VITEST_CONFIG = "test/vitest/vitest.process.config.ts";
const RUNTIME_CONFIG_VITEST_CONFIG = "test/vitest/vitest.runtime-config.config.ts";
const SECRETS_VITEST_CONFIG = "test/vitest/vitest.secrets.config.ts";
const SHARED_CORE_VITEST_CONFIG = "test/vitest/vitest.shared-core.config.ts";
const TASKS_VITEST_CONFIG = "test/vitest/vitest.tasks.config.ts";
const TOOLING_VITEST_CONFIG = "test/vitest/vitest.tooling.config.ts";
const TUI_VITEST_CONFIG = "test/vitest/vitest.tui.config.ts";
const UI_VITEST_CONFIG = "test/vitest/vitest.ui.config.ts";
const UTILS_VITEST_CONFIG = "test/vitest/vitest.utils.config.ts";
const WIZARD_VITEST_CONFIG = "test/vitest/vitest.wizard.config.ts";
const INCLUDE_FILE_ENV_KEY = "OPENCLAW_VITEST_INCLUDE_FILE";
const FS_MODULE_CACHE_PATH_ENV_KEY = "OPENCLAW_VITEST_FS_MODULE_CACHE_PATH";
const CHANGED_ARGS_PATTERN = /^--changed(?:=(.+))?$/u;
const VITEST_CONFIG_BY_KIND = {
  acp: ACP_VITEST_CONFIG,
  agent: AGENTS_VITEST_CONFIG,
  autoReplyCore: AUTO_REPLY_CORE_VITEST_CONFIG,
  autoReplyReply: AUTO_REPLY_REPLY_VITEST_CONFIG,
  autoReplyTopLevel: AUTO_REPLY_TOP_LEVEL_VITEST_CONFIG,
  autoReply: AUTO_REPLY_VITEST_CONFIG,
  boundary: BOUNDARY_VITEST_CONFIG,
  bundled: BUNDLED_VITEST_CONFIG,
  channel: CHANNEL_VITEST_CONFIG,
  cli: CLI_VITEST_CONFIG,
  command: COMMANDS_VITEST_CONFIG,
  commandLight: COMMANDS_LIGHT_VITEST_CONFIG,
  contractsChannelConfig: CONTRACTS_CHANNEL_CONFIG_VITEST_CONFIG,
  contractsChannelRegistry: CONTRACTS_CHANNEL_REGISTRY_VITEST_CONFIG,
  contractsChannelSession: CONTRACTS_CHANNEL_SESSION_VITEST_CONFIG,
  contractsChannelSurface: CONTRACTS_CHANNEL_SURFACE_VITEST_CONFIG,
  contractsPlugin: CONTRACTS_PLUGIN_VITEST_CONFIG,
  cron: CRON_VITEST_CONFIG,
  daemon: DAEMON_VITEST_CONFIG,
  e2e: E2E_VITEST_CONFIG,
  extension: EXTENSIONS_VITEST_CONFIG,
  extensionFull: FULL_EXTENSIONS_VITEST_CONFIG,
  extensionAcpx: EXTENSION_ACPX_VITEST_CONFIG,
  extensionBlueBubbles: EXTENSION_BLUEBUBBLES_VITEST_CONFIG,
  extensionBrowser: EXTENSION_BROWSER_VITEST_CONFIG,
  extensionChannel: EXTENSION_CHANNELS_VITEST_CONFIG,
  extensionDiffs: EXTENSION_DIFFS_VITEST_CONFIG,
  extensionDiscord: EXTENSION_DISCORD_VITEST_CONFIG,
  extensionFeishu: EXTENSION_FEISHU_VITEST_CONFIG,
  extensionImessage: EXTENSION_IMESSAGE_VITEST_CONFIG,
  extensionIrc: EXTENSION_IRC_VITEST_CONFIG,
  extensionLine: EXTENSION_LINE_VITEST_CONFIG,
  extensionMatrix: EXTENSION_MATRIX_VITEST_CONFIG,
  extensionMattermost: EXTENSION_MATTERMOST_VITEST_CONFIG,
  extensionMedia: EXTENSION_MEDIA_VITEST_CONFIG,
  extensionMemory: EXTENSION_MEMORY_VITEST_CONFIG,
  extensionMessaging: EXTENSION_MESSAGING_VITEST_CONFIG,
  extensionMisc: EXTENSION_MISC_VITEST_CONFIG,
  extensionMsTeams: EXTENSION_MSTEAMS_VITEST_CONFIG,
  extensionProviderOpenAi: EXTENSION_PROVIDER_OPENAI_VITEST_CONFIG,
  extensionProvider: EXTENSION_PROVIDERS_VITEST_CONFIG,
  extensionQa: EXTENSION_QA_VITEST_CONFIG,
  extensionSignal: EXTENSION_SIGNAL_VITEST_CONFIG,
  extensionSlack: EXTENSION_SLACK_VITEST_CONFIG,
  extensionTelegram: EXTENSION_TELEGRAM_VITEST_CONFIG,
  extensionVoiceCall: EXTENSION_VOICE_CALL_VITEST_CONFIG,
  extensionWhatsApp: EXTENSION_WHATSAPP_VITEST_CONFIG,
  extensionZalo: EXTENSION_ZALO_VITEST_CONFIG,
  gatewayClient: GATEWAY_CLIENT_VITEST_CONFIG,
  gatewayCore: GATEWAY_CORE_VITEST_CONFIG,
  gatewayMethods: GATEWAY_METHODS_VITEST_CONFIG,
  gatewayServer: GATEWAY_SERVER_VITEST_CONFIG,
  gateway: GATEWAY_VITEST_CONFIG,
  hooks: HOOKS_VITEST_CONFIG,
  infra: INFRA_VITEST_CONFIG,
  logging: LOGGING_VITEST_CONFIG,
  media: MEDIA_VITEST_CONFIG,
  mediaUnderstanding: MEDIA_UNDERSTANDING_VITEST_CONFIG,
  plugin: PLUGINS_VITEST_CONFIG,
  pluginSdk: PLUGIN_SDK_VITEST_CONFIG,
  pluginSdkLight: PLUGIN_SDK_LIGHT_VITEST_CONFIG,
  process: PROCESS_VITEST_CONFIG,
  unitFast: UNIT_FAST_VITEST_CONFIG,
  unitSecurity: UNIT_SECURITY_VITEST_CONFIG,
  unitSrc: UNIT_SRC_VITEST_CONFIG,
  unitSupport: UNIT_SUPPORT_VITEST_CONFIG,
  unitUi: UNIT_UI_VITEST_CONFIG,
  runtimeConfig: RUNTIME_CONFIG_VITEST_CONFIG,
  secrets: SECRETS_VITEST_CONFIG,
  sharedCore: SHARED_CORE_VITEST_CONFIG,
  tasks: TASKS_VITEST_CONFIG,
  tooling: TOOLING_VITEST_CONFIG,
  tui: TUI_VITEST_CONFIG,
  ui: UI_VITEST_CONFIG,
  utils: UTILS_VITEST_CONFIG,
  wizard: WIZARD_VITEST_CONFIG,
};
const BROAD_CHANGED_RERUN_PATTERNS = [
  /^package\.json$/u,
  /^pnpm-lock\.yaml$/u,
  /^test\/setup(?:\.shared|\.extensions|-openclaw-runtime)?\.ts$/u,
  /^vitest(?:\..+)?\.(?:config\.ts|paths\.mjs)$/u,
  /^test\/vitest\/vitest\.(?:config|shared\.config|scoped-config|performance-config)\.ts$/u,
  /^test\/helpers\//u,
];
const PRECISE_SOURCE_TEST_TARGETS = new Map([
  [
    "test/helpers/plugins/tts-contract-suites.ts",
    [
      "src/plugins/contracts/core-extension-facade-boundary.test.ts",
      "src/plugins/contracts/tts.contract.test.ts",
    ],
  ],
]);
const TOOLING_SOURCE_TEST_TARGETS = new Map([
  ["scripts/changed-lanes.mjs", ["test/scripts/changed-lanes.test.ts"]],
  ["scripts/check-changed.mjs", ["test/scripts/changed-lanes.test.ts"]],
  ["scripts/lib/vitest-local-scheduling.mjs", ["test/scripts/vitest-local-scheduling.test.ts"]],
  [
    "scripts/run-vitest.mjs",
    [
      "test/scripts/run-vitest.test.ts",
      "test/scripts/test-projects.test.ts",
      "test/scripts/vitest-local-scheduling.test.ts",
    ],
  ],
  ["scripts/test-extension-batch.mjs", ["test/scripts/test-extension.test.ts"]],
  ["scripts/lib/extension-test-plan.mjs", ["test/scripts/test-extension.test.ts"]],
  ["scripts/lib/vitest-batch-runner.mjs", ["test/scripts/test-extension.test.ts"]],
  ["scripts/test-projects.mjs", ["test/scripts/test-projects.test.ts"]],
  ["scripts/test-projects.test-support.d.mts", ["test/scripts/test-projects.test.ts"]],
  ["scripts/test-projects.test-support.mjs", ["test/scripts/test-projects.test.ts"]],
]);
const TOOLING_TEST_TARGETS = new Map([
  ["test/scripts/changed-lanes.test.ts", ["test/scripts/changed-lanes.test.ts"]],
  ["test/scripts/test-projects.test.ts", ["test/scripts/test-projects.test.ts"]],
  [
    "test/scripts/vitest-local-scheduling.test.ts",
    ["test/scripts/vitest-local-scheduling.test.ts"],
  ],
]);
const SOURCE_TEST_TARGETS = new Map([
  ...PRECISE_SOURCE_TEST_TARGETS,
  ["extensions/google-meet/index.ts", ["extensions/google-meet/index.test.ts"]],
  ["extensions/google-meet/src/cli.ts", ["extensions/google-meet/src/cli.test.ts"]],
  ["extensions/google-meet/src/create.ts", ["extensions/google-meet/index.test.ts"]],
  ["extensions/google-meet/src/oauth.ts", ["extensions/google-meet/src/oauth.test.ts"]],
  ["src/agents/live-model-turn-probes.ts", ["src/agents/live-model-turn-probes.test.ts"]],
  [
    "src/auto-reply/reply/dispatch-from-config.ts",
    ["src/auto-reply/reply/dispatch-from-config.test.ts"],
  ],
  [
    "src/auto-reply/reply/effective-reply-route.ts",
    [
      "src/auto-reply/reply/effective-reply-route.test.ts",
      "src/auto-reply/reply/dispatch-from-config.test.ts",
    ],
  ],
]);
const GENERATED_CHANGED_TEST_TARGETS = new Set([
  "src/canvas-host/a2ui/.bundle.hash",
  "src/canvas-host/a2ui/a2ui.bundle.js",
]);
const VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_TIMEOUT_MS";
const VITEST_NO_OUTPUT_RETRY_ENV_KEY = "OPENCLAW_VITEST_NO_OUTPUT_RETRY";
export const DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS = "180000";
const VITEST_CONFIG_TARGET_KIND_BY_PATH = new Map(
  Object.entries(VITEST_CONFIG_BY_KIND).map(([kind, config]) => [config, kind]),
);
const CHANNEL_CONTRACT_CONFIG_PATTERNS = new Map([
  [
    CONTRACTS_CHANNEL_SURFACE_VITEST_CONFIG,
    [
      "src/channels/plugins/contracts/channel-catalog.contract.test.ts",
      "src/channels/plugins/contracts/channel-import-guardrails.test.ts",
      "src/channels/plugins/contracts/group-policy.fallback.contract.test.ts",
      "src/channels/plugins/contracts/outbound-payload.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-a.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-e.contract.test.ts",
    ],
  ],
  [
    CONTRACTS_CHANNEL_CONFIG_VITEST_CONFIG,
    [
      "src/channels/plugins/contracts/plugins-core.authorize-config-write.policy.contract.test.ts",
      "src/channels/plugins/contracts/plugins-core.authorize-config-write.targets.contract.test.ts",
      "src/channels/plugins/contracts/plugins-core.catalog.entries.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-b.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-f.contract.test.ts",
    ],
  ],
  [
    CONTRACTS_CHANNEL_REGISTRY_VITEST_CONFIG,
    [
      "src/channels/plugins/contracts/plugins-core.catalog.paths.contract.test.ts",
      "src/channels/plugins/contracts/plugins-core.loader.contract.test.ts",
      "src/channels/plugins/contracts/plugins-core.registry.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-c.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-g.contract.test.ts",
    ],
  ],
  [
    CONTRACTS_CHANNEL_SESSION_VITEST_CONFIG,
    [
      "src/channels/plugins/contracts/plugins-core.resolve-config-writes.contract.test.ts",
      "src/channels/plugins/contracts/registry.contract.test.ts",
      "src/channels/plugins/contracts/session-binding.registry-backed.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-d.contract.test.ts",
      "src/channels/plugins/contracts/*-shard-h.contract.test.ts",
    ],
  ],
]);

function normalizePathPattern(value) {
  return value.replaceAll("\\", "/");
}

function isExistingPathTarget(arg, cwd) {
  return fs.existsSync(path.resolve(cwd, arg));
}

function isExistingFileTarget(arg, cwd) {
  try {
    return fs.statSync(path.resolve(cwd, arg)).isFile();
  } catch {
    return false;
  }
}

function isGlobTarget(arg) {
  return /[*?[\]{}]/u.test(arg);
}

function isFileLikeTarget(arg) {
  return /\.(?:test|spec)\.[cm]?[jt]sx?$/u.test(arg);
}

function isLikelyFileTarget(arg) {
  return /(?:^|\/)[^/]+\.[A-Za-z0-9]+$/u.test(arg);
}

function isPathLikeTargetArg(arg, cwd) {
  if (!arg || arg === "--" || arg.startsWith("-")) {
    return false;
  }
  return isExistingPathTarget(arg, cwd) || isGlobTarget(arg) || isFileLikeTarget(arg);
}

function toRepoRelativeTarget(arg, cwd) {
  if (isGlobTarget(arg)) {
    return normalizePathPattern(arg.replace(/^\.\//u, ""));
  }
  const absolute = path.resolve(cwd, arg);
  return normalizePathPattern(path.relative(cwd, absolute));
}

function toScopedIncludePattern(arg, cwd) {
  const relative = toRepoRelativeTarget(arg, cwd);
  if (isGlobTarget(relative) || isFileLikeTarget(relative)) {
    return relative;
  }
  if (isExistingFileTarget(arg, cwd) || isLikelyFileTarget(relative)) {
    const directory = normalizePathPattern(path.posix.dirname(relative));
    return directory === "." ? "**/*.test.ts" : `${directory}/**/*.test.ts`;
  }
  return `${relative.replace(/\/+$/u, "")}/**/*.test.ts`;
}

function resolveVitestConfigTargetKind(relative) {
  return VITEST_CONFIG_TARGET_KIND_BY_PATH.get(relative) ?? null;
}

function isVitestConfigTargetForKind(kind, targetArg, cwd) {
  return resolveVitestConfigTargetKind(toRepoRelativeTarget(targetArg, cwd)) === kind;
}

function resolveChannelContractTargetKind(relative) {
  if (!relative.startsWith("src/channels/plugins/contracts/")) {
    return null;
  }
  const name = path.posix.basename(relative);
  if (/-shard-[ae]\.contract\.test\.ts$/u.test(name)) {
    return "contractsChannelSurface";
  }
  if (/-shard-[bf]\.contract\.test\.ts$/u.test(name)) {
    return "contractsChannelConfig";
  }
  if (/-shard-[cg]\.contract\.test\.ts$/u.test(name)) {
    return "contractsChannelRegistry";
  }
  if (/-shard-[dh]\.contract\.test\.ts$/u.test(name)) {
    return "contractsChannelSession";
  }
  if (
    [
      "channel-catalog.contract.test.ts",
      "channel-import-guardrails.test.ts",
      "group-policy.fallback.contract.test.ts",
      "outbound-payload.contract.test.ts",
    ].includes(name)
  ) {
    return "contractsChannelSurface";
  }
  if (
    [
      "plugins-core.authorize-config-write.policy.contract.test.ts",
      "plugins-core.authorize-config-write.targets.contract.test.ts",
      "plugins-core.catalog.entries.contract.test.ts",
    ].includes(name)
  ) {
    return "contractsChannelConfig";
  }
  if (
    [
      "plugins-core.catalog.paths.contract.test.ts",
      "plugins-core.loader.contract.test.ts",
      "plugins-core.registry.contract.test.ts",
    ].includes(name)
  ) {
    return "contractsChannelRegistry";
  }
  return "contractsChannelSession";
}

function listChangedPathsFromGit(baseRef, cwd) {
  return [
    ...new Set([
      ...runGitNameOnlyDiff(cwd, [`${baseRef}...HEAD`]),
      ...runGitNameOnlyDiff(cwd, ["--cached", "--diff-filter=ACMR"]),
      ...runGitNameOnlyDiff(cwd, ["--diff-filter=ACMR"]),
      ...runGitLsFiles(cwd, ["--others", "--exclude-standard"]),
    ]),
  ].toSorted((left, right) => left.localeCompare(right));
}

function runGitNameOnlyDiff(cwd, extraArgs) {
  return execFileSync("git", ["diff", "--name-only", ...extraArgs], {
    cwd,
    encoding: "utf8",
    stdio: ["ignore", "pipe", "pipe"],
  })
    .split("\n")
    .map((line) => normalizePathPattern(line.trim()))
    .filter((line) => line.length > 0);
}

function runGitLsFiles(cwd, extraArgs) {
  return execFileSync("git", ["ls-files", ...extraArgs], {
    cwd,
    encoding: "utf8",
    stdio: ["ignore", "pipe", "pipe"],
  })
    .split("\n")
    .map((line) => normalizePathPattern(line.trim()))
    .filter((line) => line.length > 0);
}

function extractChangedBaseRef(args) {
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    const match = arg.match(CHANGED_ARGS_PATTERN);
    if (!match) {
      continue;
    }
    if (match[1]) {
      return match[1];
    }
    const nextArg = args[index + 1];
    return nextArg && nextArg !== "--" && !nextArg.startsWith("-") ? nextArg : "HEAD";
  }
  return null;
}

function stripChangedArgs(args) {
  const strippedArgs = [];
  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    const match = arg.match(CHANGED_ARGS_PATTERN);
    if (!match) {
      strippedArgs.push(arg);
      continue;
    }
    if (!match[1]) {
      const nextArg = args[index + 1];
      if (nextArg && nextArg !== "--" && !nextArg.startsWith("-")) {
        index += 1;
      }
    }
  }
  return strippedArgs;
}

function shouldKeepBroadChangedRun(changedPaths) {
  return changedPaths.some((changedPath) =>
    PRECISE_SOURCE_TEST_TARGETS.has(changedPath)
      ? false
      : BROAD_CHANGED_RERUN_PATTERNS.some((pattern) => pattern.test(changedPath)),
  );
}

function resolveToolingChangedTestTargets(changedPaths) {
  const targets = [];
  for (const changedPath of changedPaths) {
    const testTargets = resolveToolingTestTargets(changedPath);
    if (!testTargets) {
      return null;
    }
    targets.push(...testTargets);
  }
  return [...new Set(targets)];
}

function resolveToolingTestTargets(changedPath) {
  return TOOLING_SOURCE_TEST_TARGETS.get(changedPath) ?? TOOLING_TEST_TARGETS.get(changedPath);
}

function isRoutableChangedTarget(changedPath) {
  if (GENERATED_CHANGED_TEST_TARGETS.has(changedPath)) {
    return false;
  }
  if (changedPath.endsWith(".live.test.ts")) {
    return false;
  }
  return /^(?:src|test|extensions|ui|packages)(?:\/|$)/u.test(changedPath);
}

export function resolveChangedTestTargetPlan(changedPaths) {
  if (changedPaths.length === 0) {
    return { mode: "none", targets: [] };
  }
  const toolingTargets = resolveToolingChangedTestTargets(changedPaths);
  if (toolingTargets) {
    return { mode: "targets", targets: toolingTargets };
  }
  if (shouldKeepBroadChangedRun(changedPaths)) {
    return { mode: "broad", targets: [] };
  }
  const changedLanes = detectChangedLanes(changedPaths);
  if (changedLanes.lanes.all) {
    return { mode: "broad", targets: [] };
  }
  const targets = changedPaths.flatMap((changedPath) => {
    const mappedTargets =
      resolveToolingTestTargets(changedPath) ?? SOURCE_TEST_TARGETS.get(changedPath);
    if (mappedTargets) {
      return mappedTargets;
    }
    return isRoutableChangedTarget(changedPath) ? [changedPath] : [];
  });
  if (changedLanes.extensionImpactFromCore) {
    targets.push("extensions");
  }
  return { mode: "targets", targets: [...new Set(targets)] };
}

export function listFullExtensionVitestProjectConfigs() {
  return (
    fullSuiteVitestShards.find((shard) => shard.config === FULL_EXTENSIONS_VITEST_CONFIG)
      ?.projects ?? []
  );
}

export function resolveChangedTargetArgs(
  args,
  cwd = process.cwd(),
  listChangedPaths = listChangedPathsFromGit,
) {
  const baseRef = extractChangedBaseRef(args);
  if (!baseRef) {
    return null;
  }
  const changedPaths = listChangedPaths(baseRef, cwd);
  const plan = resolveChangedTestTargetPlan(changedPaths);
  if (plan.mode === "broad") {
    return null;
  }
  return plan.targets;
}

function classifyTarget(arg, cwd) {
  const relative = toRepoRelativeTarget(arg, cwd);
  const configTargetKind = resolveVitestConfigTargetKind(relative);
  if (configTargetKind) {
    return configTargetKind;
  }
  if (resolveUnitFastTestIncludePattern(relative)) {
    return "unitFast";
  }
  if (relative.endsWith(".e2e.test.ts")) {
    return "e2e";
  }
  if (
    relative === "src/gateway/gateway.test.ts" ||
    relative === "src/gateway/server.startup-matrix-migration.integration.test.ts" ||
    relative === "src/gateway/sessions-history-http.test.ts"
  ) {
    return "e2e";
  }
  if (relative === "extensions") {
    return "extensionFull";
  }
  if (relative.startsWith("extensions/")) {
    const extensionRoot = relative.split("/").slice(0, 2).join("/");
    const splitChannelShard = resolveSplitChannelExtensionShard(extensionRoot);
    if (splitChannelShard) {
      return splitChannelShard.kind;
    }
    if (isProviderOpenAiExtensionRoot(extensionRoot)) {
      return "extensionProviderOpenAi";
    }
    if (isQaExtensionRoot(extensionRoot)) {
      return "extensionQa";
    }
    if (isChannelSurfaceTestFile(relative)) {
      return "extensionChannel";
    }
    if (isAcpxExtensionRoot(extensionRoot)) {
      return "extensionAcpx";
    }
    if (isDiffsExtensionRoot(extensionRoot)) {
      return "extensionDiffs";
    }
    if (isBlueBubblesExtensionRoot(extensionRoot)) {
      return "extensionBlueBubbles";
    }
    if (isBrowserExtensionRoot(extensionRoot)) {
      return "extensionBrowser";
    }
    if (isFeishuExtensionRoot(extensionRoot)) {
      return "extensionFeishu";
    }
    if (isIrcExtensionRoot(extensionRoot)) {
      return "extensionIrc";
    }
    if (isMattermostExtensionRoot(extensionRoot)) {
      return "extensionMattermost";
    }
    if (isTelegramExtensionRoot(extensionRoot)) {
      return "extensionTelegram";
    }
    if (isVoiceCallExtensionRoot(extensionRoot)) {
      return "extensionVoiceCall";
    }
    if (isWhatsAppExtensionRoot(extensionRoot)) {
      return "extensionWhatsApp";
    }
    if (isZaloExtensionRoot(extensionRoot)) {
      return "extensionZalo";
    }
    if (isMatrixExtensionRoot(extensionRoot)) {
      return "extensionMatrix";
    }
    if (isMediaExtensionRoot(extensionRoot)) {
      return "extensionMedia";
    }
    if (isMemoryExtensionRoot(extensionRoot)) {
      return "extensionMemory";
    }
    if (isMsTeamsExtensionRoot(extensionRoot)) {
      return "extensionMsTeams";
    }
    if (isMessagingExtensionRoot(extensionRoot)) {
      return "extensionMessaging";
    }
    if (isMiscExtensionRoot(extensionRoot)) {
      return "extensionMisc";
    }
    return isProviderExtensionRoot(extensionRoot) ? "extensionProvider" : "extension";
  }
  const channelContractKind = resolveChannelContractTargetKind(relative);
  if (channelContractKind) {
    return channelContractKind;
  }
  if (relative.startsWith("src/plugins/contracts/")) {
    return "contractsPlugin";
  }
  if (isChannelSurfaceTestFile(relative)) {
    return "channel";
  }
  if (isBoundaryTestFile(relative)) {
    return "boundary";
  }
  if (
    relative.startsWith("test/") ||
    relative.startsWith("src/scripts/") ||
    relative === "src/config/doc-baseline.integration.test.ts" ||
    relative === "src/config/schema.base.generated.test.ts" ||
    relative === "src/config/schema.help.quality.test.ts"
  ) {
    return "tooling";
  }
  if (isBundledPluginDependentUnitTestFile(relative)) {
    return "bundled";
  }
  if (relative.startsWith("src/channels/")) {
    return "channel";
  }
  if (relative.startsWith("src/gateway/")) {
    return "gateway";
  }
  if (relative.startsWith("src/hooks/")) {
    return "hooks";
  }
  if (relative.startsWith("src/infra/")) {
    return "infra";
  }
  if (relative.startsWith("src/config/")) {
    return "runtimeConfig";
  }
  if (relative.startsWith("src/cron/")) {
    return "cron";
  }
  if (relative.startsWith("src/daemon/")) {
    return "daemon";
  }
  if (relative.startsWith("src/media-understanding/")) {
    return "mediaUnderstanding";
  }
  if (relative.startsWith("src/media/")) {
    return "media";
  }
  if (relative.startsWith("src/logging/")) {
    return "logging";
  }
  if (relative.startsWith("src/plugin-sdk/")) {
    return isPluginSdkLightTarget(relative) ? "pluginSdkLight" : "pluginSdk";
  }
  if (relative.startsWith("src/process/")) {
    return "process";
  }
  if (relative.startsWith("src/secrets/")) {
    return "secrets";
  }
  if (relative.startsWith("src/shared/")) {
    return "sharedCore";
  }
  if (relative.startsWith("src/tasks/")) {
    return "tasks";
  }
  if (relative.startsWith("src/tui/")) {
    return "tui";
  }
  if (relative.startsWith("src/acp/")) {
    return "acp";
  }
  if (relative.startsWith("src/cli/")) {
    return "cli";
  }
  if (relative.startsWith("src/commands/")) {
    return isCommandsLightTarget(relative) ? "commandLight" : "command";
  }
  if (relative.startsWith("src/auto-reply/")) {
    return "autoReply";
  }
  if (relative.startsWith("src/agents/")) {
    return "agent";
  }
  if (relative.startsWith("src/plugins/")) {
    return "plugin";
  }
  if (relative.startsWith("ui/src/")) {
    return "ui";
  }
  if (relative.startsWith("src/utils/")) {
    return "utils";
  }
  if (relative.startsWith("src/wizard/")) {
    return "wizard";
  }
  return "default";
}

function resolveLightLaneIncludePatterns(kind, targetArg, cwd) {
  const relative = toRepoRelativeTarget(targetArg, cwd);
  if (kind === "unitFast") {
    const includePattern = resolveUnitFastTestIncludePattern(relative);
    return includePattern ? [includePattern] : null;
  }
  if (kind === "pluginSdkLight") {
    const includePattern = resolvePluginSdkLightIncludePattern(relative);
    return includePattern ? [includePattern] : null;
  }
  if (kind === "commandLight") {
    const includePattern = resolveCommandsLightIncludePattern(relative);
    return includePattern ? [includePattern] : null;
  }
  return null;
}

function shouldUseWholeConfigTarget(kind, targetArg, cwd) {
  if (isVitestConfigTargetForKind(kind, targetArg, cwd)) {
    return true;
  }
  if (kind !== "ui") {
    return false;
  }
  const relative = toRepoRelativeTarget(targetArg, cwd);
  return relative.startsWith("ui/src/") && !relative.startsWith("ui/src/ui/");
}

function createVitestArgs(params) {
  return [
    "exec",
    "node",
    ...resolveVitestNodeArgs(params.env),
    resolveVitestCliEntry(),
    ...(params.watchMode ? [] : ["run"]),
    "--config",
    params.config,
    ...params.forwardedArgs,
  ];
}

export function parseTestProjectsArgs(args, cwd = process.cwd()) {
  const forwardedArgs = [];
  const targetArgs = [];
  let watchMode = false;

  for (const arg of args) {
    if (arg === "--") {
      continue;
    }
    if (arg === "--watch") {
      watchMode = true;
      continue;
    }
    if (isPathLikeTargetArg(arg, cwd)) {
      targetArgs.push(arg);
    }
    forwardedArgs.push(arg);
  }

  return { forwardedArgs, targetArgs, watchMode };
}

export function buildVitestRunPlans(
  args,
  cwd = process.cwd(),
  listChangedPaths = listChangedPathsFromGit,
) {
  const { forwardedArgs, targetArgs, watchMode } = parseTestProjectsArgs(args, cwd);
  const changedTargetArgs =
    targetArgs.length === 0 ? resolveChangedTargetArgs(args, cwd, listChangedPaths) : null;
  const activeTargetArgs = changedTargetArgs ?? targetArgs;
  const activeForwardedArgs =
    changedTargetArgs !== null ? stripChangedArgs(forwardedArgs) : forwardedArgs;
  if (changedTargetArgs !== null && activeTargetArgs.length === 0) {
    return [];
  }
  if (activeTargetArgs.length === 0) {
    return [
      {
        config: DEFAULT_VITEST_CONFIG,
        forwardedArgs: activeForwardedArgs,
        includePatterns: null,
        watchMode,
      },
    ];
  }

  const groupedTargets = new Map();
  for (const targetArg of activeTargetArgs) {
    const kind = classifyTarget(targetArg, cwd);
    const current = groupedTargets.get(kind) ?? [];
    current.push(targetArg);
    groupedTargets.set(kind, current);
  }

  if (watchMode && groupedTargets.size > 1) {
    throw new Error(
      "watch mode with mixed test suites is not supported; target one suite at a time or use a dedicated suite command",
    );
  }

  const nonTargetArgs = activeForwardedArgs.filter((arg) => !activeTargetArgs.includes(arg));
  const orderedKinds = [
    "unitFast",
    "default",
    "boundary",
    "tooling",
    "contractsChannelSurface",
    "contractsChannelConfig",
    "contractsChannelRegistry",
    "contractsChannelSession",
    "contractsPlugin",
    "bundled",
    "gateway",
    "gatewayCore",
    "gatewayClient",
    "gatewayMethods",
    "gatewayServer",
    "hooks",
    "infra",
    "runtimeConfig",
    "cron",
    "daemon",
    "media",
    "logging",
    "pluginSdkLight",
    "pluginSdk",
    "process",
    "secrets",
    "sharedCore",
    "tasks",
    "tui",
    "mediaUnderstanding",
    "acp",
    "cli",
    "commandLight",
    "command",
    "autoReply",
    "autoReplyCore",
    "autoReplyReply",
    "autoReplyTopLevel",
    "agent",
    "plugin",
    "ui",
    "unitSrc",
    "unitSecurity",
    "unitSupport",
    "unitUi",
    "utils",
    "wizard",
    "e2e",
    "extensionAcpx",
    "extensionDiffs",
    "extensionBlueBubbles",
    "extensionBrowser",
    "extensionDiscord",
    "extensionFeishu",
    "extensionImessage",
    "extensionIrc",
    "extensionLine",
    "extensionMattermost",
    "extensionChannel",
    "extensionTelegram",
    "extensionVoiceCall",
    "extensionWhatsApp",
    "extensionZalo",
    "extensionMatrix",
    "extensionMedia",
    "extensionMemory",
    "extensionMisc",
    "extensionMsTeams",
    "extensionMessaging",
    "extensionProviderOpenAi",
    "extensionProvider",
    "extensionQa",
    "extensionSignal",
    "extensionSlack",
    "extensionFull",
    "channel",
    "extension",
  ];
  const plans = [];
  for (const kind of orderedKinds) {
    const grouped = groupedTargets.get(kind);
    if (!grouped || grouped.length === 0) {
      continue;
    }
    if (kind === "extensionFull") {
      const configs = watchMode
        ? [FULL_EXTENSIONS_VITEST_CONFIG]
        : listFullExtensionVitestProjectConfigs();
      for (const config of configs) {
        plans.push({
          config,
          forwardedArgs: nonTargetArgs,
          includePatterns: null,
          watchMode,
        });
      }
      continue;
    }
    const config = VITEST_CONFIG_BY_KIND[kind] ?? DEFAULT_VITEST_CONFIG;
    const useCliTargetArgs =
      kind === "e2e" ||
      (kind === "default" &&
        grouped.every((targetArg) => isFileLikeTarget(toRepoRelativeTarget(targetArg, cwd))));
    const useWholeConfigTarget = grouped.some((targetArg) =>
      shouldUseWholeConfigTarget(kind, targetArg, cwd),
    );
    const includePatterns = useCliTargetArgs
      ? null
      : useWholeConfigTarget
        ? null
        : grouped.flatMap((targetArg) => {
            const lightLanePatterns = resolveLightLaneIncludePatterns(kind, targetArg, cwd);
            return lightLanePatterns ?? [toScopedIncludePattern(targetArg, cwd)];
          });
    const scopedTargetArgs = useCliTargetArgs ? grouped : [];
    plans.push({
      config,
      forwardedArgs: [...nonTargetArgs, ...scopedTargetArgs],
      includePatterns,
      watchMode,
    });
  }
  return plans;
}

export function buildFullSuiteVitestRunPlans(args, cwd = process.cwd()) {
  const { forwardedArgs, watchMode } = parseTestProjectsArgs(args, cwd);
  if (watchMode) {
    return [
      {
        config: "vitest.config.ts",
        forwardedArgs,
        includePatterns: null,
        watchMode,
      },
    ];
  }
  const parallelShardCount = Number.parseInt(process.env.OPENCLAW_TEST_PROJECTS_PARALLEL ?? "", 10);
  const expandToProjectConfigs =
    process.env.OPENCLAW_TEST_PROJECTS_LEAF_SHARDS === "1" ||
    (Number.isFinite(parallelShardCount) && parallelShardCount > 1) ||
    shouldUseLocalFullSuiteParallelByDefault(process.env);
  return fullSuiteVitestShards.flatMap((shard) => {
    if (
      process.env.OPENCLAW_TEST_SKIP_FULL_EXTENSIONS_SHARD === "1" &&
      shard.config === FULL_EXTENSIONS_VITEST_CONFIG
    ) {
      return [];
    }
    const expandShard = expandToProjectConfigs || shard.config === FULL_EXTENSIONS_VITEST_CONFIG;
    const configs = expandShard ? shard.projects : [shard.config];
    return configs.map((config) => ({
      config,
      forwardedArgs,
      includePatterns: null,
      watchMode: false,
    }));
  });
}

export function shouldUseLocalFullSuiteParallelByDefault(env = process.env) {
  if (hasConservativeVitestWorkerBudget(env)) {
    return false;
  }
  return (
    env.OPENCLAW_TEST_PROJECTS_SERIAL !== "1" && env.CI !== "true" && env.GITHUB_ACTIONS !== "true"
  );
}

function parsePositiveInt(value) {
  const parsed = Number.parseInt(value ?? "", 10);
  return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
}

function hasConservativeVitestWorkerBudget(env) {
  const workerBudget = parsePositiveInt(
    env.OPENCLAW_VITEST_MAX_WORKERS ?? env.OPENCLAW_TEST_WORKERS,
  );
  return workerBudget !== null && workerBudget <= 1;
}

export function resolveParallelFullSuiteConcurrency(specCount, env = process.env, hostInfo) {
  const override = parsePositiveInt(env.OPENCLAW_TEST_PROJECTS_PARALLEL);
  if (override !== null) {
    return Math.min(override, specCount);
  }
  if (env.OPENCLAW_TEST_PROJECTS_SERIAL === "1") {
    return 1;
  }
  if (isCiLikeEnv(env)) {
    return 1;
  }
  if (hasConservativeVitestWorkerBudget(env)) {
    return 1;
  }
  if (
    env.OPENCLAW_TEST_PROJECTS_LEAF_SHARDS !== "1" &&
    !shouldUseLocalFullSuiteParallelByDefault(env)
  ) {
    return 1;
  }
  return Math.min(resolveLocalFullSuiteProfile(env, hostInfo).shardParallelism, specCount);
}

function sanitizeVitestCachePathSegment(value) {
  return (
    value
      .replace(/[^a-zA-Z0-9._-]+/gu, "-")
      .replace(/^-+|-+$/gu, "")
      .slice(0, 180) || "default"
  );
}

export function applyParallelVitestCachePaths(specs, params = {}) {
  const baseEnv = params.env ?? process.env;
  if (baseEnv[FS_MODULE_CACHE_PATH_ENV_KEY]?.trim()) {
    return specs;
  }
  const cwd = params.cwd ?? process.cwd();
  return specs.map((spec, index) => {
    if (spec.env?.[FS_MODULE_CACHE_PATH_ENV_KEY]?.trim()) {
      return spec;
    }
    const cacheSegment = sanitizeVitestCachePathSegment(`${index}-${spec.config}`);
    return {
      ...spec,
      env: {
        ...spec.env,
        [FS_MODULE_CACHE_PATH_ENV_KEY]: path.join(
          cwd,
          "node_modules",
          ".experimental-vitest-cache",
          cacheSegment,
        ),
      },
    };
  });
}

export function applyDefaultMultiSpecVitestCachePaths(specs, params = {}) {
  if (specs.length <= 1 || specs.some((spec) => spec.watchMode)) {
    return specs;
  }
  return applyParallelVitestCachePaths(specs, params);
}

export function applyDefaultVitestNoOutputTimeout(specs, params = {}) {
  const baseEnv = params.env ?? process.env;
  if (Object.hasOwn(baseEnv, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY)) {
    return specs;
  }
  return specs.map((spec) => {
    if (spec.watchMode || Object.hasOwn(spec.env ?? {}, VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY)) {
      return spec;
    }
    return {
      ...spec,
      env: {
        ...spec.env,
        [VITEST_NO_OUTPUT_TIMEOUT_ENV_KEY]: DEFAULT_TEST_PROJECTS_VITEST_NO_OUTPUT_TIMEOUT_MS,
      },
    };
  });
}

export function shouldRetryVitestNoOutputTimeout(env = process.env) {
  const value = env[VITEST_NO_OUTPUT_RETRY_ENV_KEY]?.trim().toLowerCase();
  return !["0", "false", "no", "off"].includes(value ?? "");
}

export function createVitestRunSpecs(args, params = {}) {
  const cwd = params.cwd ?? process.cwd();
  const baseEnv = params.baseEnv ?? process.env;
  const plans = filterPlansForContractIncludeFile(buildVitestRunPlans(args, cwd), baseEnv);
  return plans.map((plan, index) => {
    const includeFilePath = plan.includePatterns
      ? path.join(
          params.tempDir ?? os.tmpdir(),
          `openclaw-vitest-include-${process.pid}-${Date.now()}-${index}.json`,
        )
      : null;
    return {
      config: plan.config,
      env: includeFilePath
        ? {
            ...baseEnv,
            [INCLUDE_FILE_ENV_KEY]: includeFilePath,
          }
        : baseEnv,
      includeFilePath,
      includePatterns: plan.includePatterns,
      pnpmArgs: createVitestArgs(plan),
      watchMode: plan.watchMode,
    };
  });
}

function loadIncludePatternsForSpecFilter(env) {
  const filePath = env[INCLUDE_FILE_ENV_KEY]?.trim();
  if (!filePath) {
    return null;
  }
  const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
  if (!Array.isArray(parsed)) {
    return [];
  }
  return parsed.filter((value) => typeof value === "string" && value.length > 0);
}

function includePatternMatchesConfig(candidate, configPatterns) {
  return configPatterns.some(
    (pattern) => path.matchesGlob(candidate, pattern) || path.matchesGlob(pattern, candidate),
  );
}

function filterPlansForContractIncludeFile(plans, env) {
  const includePatterns = loadIncludePatternsForSpecFilter(env);
  if (!includePatterns) {
    return plans;
  }
  return plans.filter((plan) => {
    const configPatterns = CHANNEL_CONTRACT_CONFIG_PATTERNS.get(plan.config);
    if (!configPatterns) {
      return true;
    }
    return includePatterns.some((candidate) =>
      includePatternMatchesConfig(candidate, configPatterns),
    );
  });
}

export function shouldAcquireLocalHeavyCheckLock(runSpecs, env = process.env) {
  if (env.OPENCLAW_TEST_PROJECTS_FORCE_LOCK === "1") {
    return true;
  }

  return !(
    runSpecs.length === 1 &&
    runSpecs[0]?.config === TOOLING_VITEST_CONFIG &&
    runSpecs[0]?.watchMode === false &&
    Array.isArray(runSpecs[0]?.includePatterns) &&
    runSpecs[0].includePatterns.length > 0
  );
}

export function writeVitestIncludeFile(filePath, includePatterns) {
  fs.writeFileSync(filePath, `${JSON.stringify(includePatterns, null, 2)}\n`);
}

export function buildVitestArgs(args, cwd = process.cwd()) {
  const [plan] = buildVitestRunPlans(args, cwd);
  if (!plan) {
    return createVitestArgs({
      config: DEFAULT_VITEST_CONFIG,
      forwardedArgs: [],
      watchMode: false,
    });
  }
  return createVitestArgs(plan);
}

[Dauer der Verarbeitung: 0.28 Sekunden, vorverarbeitet 2026-04-27]