mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 10:20:42 +00:00
test: optimize skills workspace fixtures
This commit is contained in:
@@ -2,6 +2,7 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { loadWorkspaceDotEnvFile } from "../infra/dotenv.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import {
|
||||
hasBinaryMock,
|
||||
@@ -216,4 +217,44 @@ describe("skills-install fallback edge cases", () => {
|
||||
envSnapshot.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it("blocks workspace dotenv UV_PYTHON from uv install execution", async () => {
|
||||
mockAvailableBinaries(["uv"]);
|
||||
runCommandWithTimeoutMock.mockResolvedValueOnce({
|
||||
code: 0,
|
||||
stdout: "ok",
|
||||
stderr: "",
|
||||
signal: null,
|
||||
killed: false,
|
||||
});
|
||||
|
||||
const workspaceEnvPath = path.join(workspaceDir, ".env");
|
||||
const envSnapshot = captureEnv(["UV_PYTHON"]);
|
||||
try {
|
||||
delete process.env.UV_PYTHON;
|
||||
await fs.writeFile(workspaceEnvPath, "UV_PYTHON=/tmp/attacker-python\n", "utf-8");
|
||||
|
||||
loadWorkspaceDotEnvFile(workspaceEnvPath, { quiet: true });
|
||||
expect(process.env.UV_PYTHON).toBeUndefined();
|
||||
|
||||
const result = await installSkill({
|
||||
workspaceDir,
|
||||
skillName: "py-tool",
|
||||
installId: "deps",
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
expect(runCommandWithTimeoutMock).toHaveBeenCalledWith(
|
||||
["uv", "tool", "install", "example-package"],
|
||||
expect.objectContaining({
|
||||
timeoutMs: 10_000,
|
||||
env: undefined,
|
||||
}),
|
||||
);
|
||||
} finally {
|
||||
envSnapshot.restore();
|
||||
await fs.rm(workspaceEnvPath, { force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it } from "vitest";
|
||||
import { loadWorkspaceDotEnvFile } from "../infra/dotenv.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { installSkill } from "./skills-install.js";
|
||||
|
||||
describe("workspace .env UV_PYTHON handling for uv skill installs", () => {
|
||||
let envSnapshot: ReturnType<typeof captureEnv> | undefined;
|
||||
|
||||
afterEach(async () => {
|
||||
envSnapshot?.restore();
|
||||
envSnapshot = undefined;
|
||||
});
|
||||
|
||||
it.runIf(process.platform !== "win32")(
|
||||
"does not propagate UV_PYTHON from workspace dotenv into uv tool install execution",
|
||||
async () => {
|
||||
const base = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-poc-uv-python-"));
|
||||
const cwdDir = path.join(base, "cwd");
|
||||
const binDir = path.join(base, "bin");
|
||||
const markerPath = path.join(base, "uv-python-marker.txt");
|
||||
const fakeUvPath = path.join(binDir, "uv");
|
||||
try {
|
||||
await fs.mkdir(cwdDir, { recursive: true });
|
||||
await fs.mkdir(binDir, { recursive: true });
|
||||
await fs.mkdir(path.join(cwdDir, "skills", "uv-skill"), { recursive: true });
|
||||
|
||||
await fs.writeFile(
|
||||
path.join(cwdDir, "skills", "uv-skill", "SKILL.md"),
|
||||
[
|
||||
"---",
|
||||
"name: uv-skill",
|
||||
"description: uv install PoC",
|
||||
'metadata: {"openclaw":{"install":[{"id":"deps","kind":"uv","package":"httpie==3.2.2"}]}}',
|
||||
"---",
|
||||
"",
|
||||
"# uv-skill",
|
||||
"",
|
||||
].join("\n"),
|
||||
"utf8",
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
fakeUvPath,
|
||||
[
|
||||
"#!/bin/sh",
|
||||
'printf "%s\\n" "$UV_PYTHON" > "$OPENCLAW_POC_MARKER_PATH"',
|
||||
"exit 0",
|
||||
"",
|
||||
].join("\n"),
|
||||
"utf8",
|
||||
);
|
||||
await fs.chmod(fakeUvPath, 0o755);
|
||||
|
||||
const attackerPython = path.join(base, "attacker-python");
|
||||
await fs.writeFile(path.join(cwdDir, ".env"), `UV_PYTHON=${attackerPython}\n`, "utf8");
|
||||
|
||||
envSnapshot = captureEnv(["PATH", "UV_PYTHON", "OPENCLAW_POC_MARKER_PATH"]);
|
||||
delete process.env.UV_PYTHON;
|
||||
process.env.OPENCLAW_POC_MARKER_PATH = markerPath;
|
||||
process.env.PATH = `${binDir}${path.delimiter}${process.env.PATH ?? ""}`;
|
||||
|
||||
loadWorkspaceDotEnvFile(path.join(cwdDir, ".env"), { quiet: true });
|
||||
expect(process.env.UV_PYTHON).toBeUndefined();
|
||||
|
||||
const result = await installSkill({
|
||||
workspaceDir: cwdDir,
|
||||
skillName: "uv-skill",
|
||||
installId: "deps",
|
||||
timeoutMs: 10_000,
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
await expect(fs.readFile(markerPath, "utf8")).resolves.toBe("\n");
|
||||
} finally {
|
||||
await fs.rm(base, { recursive: true, force: true });
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
@@ -6,9 +6,8 @@ import {
|
||||
resetGlobalHookRunner,
|
||||
} from "../plugins/hook-runner-global.js";
|
||||
import { createMockPluginRegistry } from "../plugins/hooks.test-helpers.js";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
|
||||
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
|
||||
import { setTempStateDir } from "./skills-install.download-test-utils.js";
|
||||
import { installSkill } from "./skills-install.js";
|
||||
import {
|
||||
runCommandWithTimeoutMock,
|
||||
@@ -47,25 +46,28 @@ metadata: {"openclaw":{"install":[{"id":"deps","kind":"node","package":"example-
|
||||
}
|
||||
|
||||
const workspaceSuite = createFixtureSuite("openclaw-skills-install-");
|
||||
let tempHome: TempHomeEnv;
|
||||
|
||||
beforeAll(async () => {
|
||||
tempHome = await createTempHomeEnv("openclaw-skills-install-home-");
|
||||
await workspaceSuite.setup();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
resetGlobalHookRunner();
|
||||
await workspaceSuite.cleanup();
|
||||
await tempHome.restore();
|
||||
});
|
||||
|
||||
async function withWorkspaceCase(
|
||||
run: (params: { workspaceDir: string; stateDir: string }) => Promise<void>,
|
||||
): Promise<void> {
|
||||
const workspaceDir = await workspaceSuite.createCaseDir("case");
|
||||
const stateDir = setTempStateDir(workspaceDir);
|
||||
await run({ workspaceDir, stateDir });
|
||||
const stateDir = path.join(workspaceDir, "state");
|
||||
const envSnapshot = captureEnv(["OPENCLAW_STATE_DIR"]);
|
||||
try {
|
||||
process.env.OPENCLAW_STATE_DIR = stateDir;
|
||||
await run({ workspaceDir, stateDir });
|
||||
} finally {
|
||||
envSnapshot.restore();
|
||||
}
|
||||
}
|
||||
|
||||
describe("installSkill code safety scanning", () => {
|
||||
|
||||
@@ -2,13 +2,13 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills.js";
|
||||
import { writeSkill } from "./skills.test-helpers.js";
|
||||
import {
|
||||
restoreMockSkillsHomeEnv,
|
||||
setMockSkillsHomeEnv,
|
||||
type SkillsHomeEnvSnapshot,
|
||||
} from "./skills/home-env.test-support.js";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills/workspace.js";
|
||||
|
||||
vi.mock("./skills/plugin-skills.js", () => ({
|
||||
resolvePluginSkillDirs: () => [],
|
||||
|
||||
@@ -2,36 +2,47 @@ import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { captureEnv } from "../test-utils/env.js";
|
||||
import { writeSkill } from "./skills.e2e-test-helpers.js";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills.js";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills/workspace.js";
|
||||
|
||||
describe("buildWorkspaceSkillsPrompt", () => {
|
||||
it("applies bundled allowlist without affecting workspace skills", async () => {
|
||||
const env = captureEnv(["HOME", "USERPROFILE", "OPENCLAW_HOME", "OPENCLAW_STATE_DIR"]);
|
||||
const workspaceDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-"));
|
||||
const bundledDir = path.join(workspaceDir, ".bundled");
|
||||
const bundledSkillDir = path.join(bundledDir, "peekaboo");
|
||||
const workspaceSkillDir = path.join(workspaceDir, "skills", "demo-skill");
|
||||
try {
|
||||
process.env.HOME = workspaceDir;
|
||||
process.env.USERPROFILE = workspaceDir;
|
||||
delete process.env.OPENCLAW_HOME;
|
||||
delete process.env.OPENCLAW_STATE_DIR;
|
||||
const bundledDir = path.join(workspaceDir, ".bundled");
|
||||
const bundledSkillDir = path.join(bundledDir, "peekaboo");
|
||||
const workspaceSkillDir = path.join(workspaceDir, "skills", "demo-skill");
|
||||
|
||||
await writeSkill({
|
||||
dir: bundledSkillDir,
|
||||
name: "peekaboo",
|
||||
description: "Capture UI",
|
||||
body: "# Peekaboo\n",
|
||||
});
|
||||
await writeSkill({
|
||||
dir: workspaceSkillDir,
|
||||
name: "demo-skill",
|
||||
description: "Workspace version",
|
||||
body: "# Workspace\n",
|
||||
});
|
||||
await writeSkill({
|
||||
dir: bundledSkillDir,
|
||||
name: "peekaboo",
|
||||
description: "Capture UI",
|
||||
body: "# Peekaboo\n",
|
||||
});
|
||||
await writeSkill({
|
||||
dir: workspaceSkillDir,
|
||||
name: "demo-skill",
|
||||
description: "Workspace version",
|
||||
body: "# Workspace\n",
|
||||
});
|
||||
|
||||
const prompt = buildWorkspaceSkillsPrompt(workspaceDir, {
|
||||
bundledSkillsDir: bundledDir,
|
||||
managedSkillsDir: path.join(workspaceDir, ".managed"),
|
||||
config: { skills: { allowBundled: ["missing-skill"] } },
|
||||
});
|
||||
const prompt = buildWorkspaceSkillsPrompt(workspaceDir, {
|
||||
bundledSkillsDir: bundledDir,
|
||||
managedSkillsDir: path.join(workspaceDir, ".managed"),
|
||||
config: { skills: { allowBundled: ["missing-skill"] } },
|
||||
});
|
||||
|
||||
expect(prompt).toContain("Workspace version");
|
||||
expect(prompt).not.toContain("peekaboo");
|
||||
expect(prompt).toContain("Workspace version");
|
||||
expect(prompt).not.toContain("peekaboo");
|
||||
} finally {
|
||||
env.restore();
|
||||
await fs.rm(workspaceDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,7 +4,7 @@ import path from "node:path";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
import { withEnv } from "../test-utils/env.js";
|
||||
import { writeSkill } from "./skills.e2e-test-helpers.js";
|
||||
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "./skills.js";
|
||||
import { buildWorkspaceSkillsPrompt, syncSkillsToWorkspace } from "./skills/workspace.js";
|
||||
|
||||
vi.mock("./skills/plugin-skills.js", () => ({
|
||||
resolvePluginSkillDirs: () => [],
|
||||
@@ -30,14 +30,12 @@ async function createCaseDir(prefix: string): Promise<string> {
|
||||
}
|
||||
|
||||
async function syncSourceSkillsToTarget(sourceWorkspace: string, targetWorkspace: string) {
|
||||
await withEnv({ HOME: sourceWorkspace, PATH: "" }, () =>
|
||||
syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
bundledSkillsDir: path.join(sourceWorkspace, ".bundled"),
|
||||
managedSkillsDir: path.join(sourceWorkspace, ".managed"),
|
||||
}),
|
||||
);
|
||||
await syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
bundledSkillsDir: path.join(sourceWorkspace, ".bundled"),
|
||||
managedSkillsDir: path.join(sourceWorkspace, ".managed"),
|
||||
});
|
||||
}
|
||||
|
||||
async function expectSyncedSkillConfinement(params: {
|
||||
@@ -89,8 +87,7 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
const buildPrompt = (
|
||||
workspaceDir: string,
|
||||
opts?: Parameters<typeof buildWorkspaceSkillsPrompt>[1],
|
||||
) =>
|
||||
withEnv({ HOME: workspaceDir, PATH: "" }, () => buildWorkspaceSkillsPrompt(workspaceDir, opts));
|
||||
) => withEnv({ HOME: workspaceDir }, () => buildWorkspaceSkillsPrompt(workspaceDir, opts));
|
||||
|
||||
const cloneSourceTemplate = async () => {
|
||||
const sourceWorkspace = await createCaseDir("source");
|
||||
@@ -114,15 +111,13 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
"export {}",
|
||||
);
|
||||
|
||||
await withEnv({ HOME: sourceWorkspace, PATH: "" }, () =>
|
||||
syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
config: { skills: { load: { extraDirs: [extraDir] } } },
|
||||
bundledSkillsDir: bundledDir,
|
||||
managedSkillsDir: managedDir,
|
||||
}),
|
||||
);
|
||||
await syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
config: { skills: { load: { extraDirs: [extraDir] } } },
|
||||
bundledSkillsDir: bundledDir,
|
||||
managedSkillsDir: managedDir,
|
||||
});
|
||||
|
||||
const prompt = buildPrompt(targetWorkspace, {
|
||||
bundledSkillsDir: path.join(targetWorkspace, ".bundled"),
|
||||
@@ -156,23 +151,21 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
description: "Dot variant",
|
||||
});
|
||||
|
||||
await withEnv({ HOME: sourceWorkspace, PATH: "" }, () =>
|
||||
syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
agentId: "alpha",
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
skills: ["foo_bar", "foo.dot"],
|
||||
},
|
||||
list: [{ id: "alpha", skills: ["foo_bar"] }],
|
||||
await syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
agentId: "alpha",
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
skills: ["foo_bar", "foo.dot"],
|
||||
},
|
||||
list: [{ id: "alpha", skills: ["foo_bar"] }],
|
||||
},
|
||||
bundledSkillsDir: path.join(sourceWorkspace, ".bundled"),
|
||||
managedSkillsDir: path.join(sourceWorkspace, ".managed"),
|
||||
}),
|
||||
);
|
||||
},
|
||||
bundledSkillsDir: path.join(sourceWorkspace, ".bundled"),
|
||||
managedSkillsDir: path.join(sourceWorkspace, ".managed"),
|
||||
});
|
||||
|
||||
const prompt = buildPrompt(targetWorkspace, {
|
||||
bundledSkillsDir: path.join(targetWorkspace, ".bundled"),
|
||||
@@ -329,31 +322,29 @@ describe("buildWorkspaceSkillsPrompt", () => {
|
||||
metadata: '{"openclaw":{"requires":{"anyBins":["missingbin","sandboxbin"]}}}',
|
||||
});
|
||||
|
||||
await withEnv({ HOME: sourceWorkspace, PATH: "" }, () =>
|
||||
syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
agentId: "alpha",
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
skills: ["remote-only"],
|
||||
},
|
||||
list: [{ id: "alpha" }],
|
||||
await syncSkillsToWorkspace({
|
||||
sourceWorkspaceDir: sourceWorkspace,
|
||||
targetWorkspaceDir: targetWorkspace,
|
||||
agentId: "alpha",
|
||||
config: {
|
||||
agents: {
|
||||
defaults: {
|
||||
skills: ["remote-only"],
|
||||
},
|
||||
list: [{ id: "alpha" }],
|
||||
},
|
||||
eligibility: {
|
||||
remote: {
|
||||
platforms: ["linux"],
|
||||
hasBin: () => false,
|
||||
hasAnyBin: (bins: string[]) => bins.includes("sandboxbin"),
|
||||
note: "sandbox",
|
||||
},
|
||||
},
|
||||
eligibility: {
|
||||
remote: {
|
||||
platforms: ["linux"],
|
||||
hasBin: () => false,
|
||||
hasAnyBin: (bins: string[]) => bins.includes("sandboxbin"),
|
||||
note: "sandbox",
|
||||
},
|
||||
bundledSkillsDir: path.join(sourceWorkspace, ".bundled"),
|
||||
managedSkillsDir: path.join(sourceWorkspace, ".managed"),
|
||||
}),
|
||||
);
|
||||
},
|
||||
bundledSkillsDir: path.join(sourceWorkspace, ".bundled"),
|
||||
managedSkillsDir: path.join(sourceWorkspace, ".managed"),
|
||||
});
|
||||
|
||||
expect(await pathExists(path.join(targetWorkspace, "skills", "remote-only", "SKILL.md"))).toBe(
|
||||
true,
|
||||
|
||||
@@ -5,12 +5,12 @@ import { withPathResolutionEnv } from "../test-utils/env.js";
|
||||
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
|
||||
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
|
||||
import { writeSkill } from "./skills.e2e-test-helpers.js";
|
||||
import { buildWorkspaceSkillSnapshot, buildWorkspaceSkillsPrompt } from "./skills.js";
|
||||
import {
|
||||
restoreMockSkillsHomeEnv,
|
||||
setMockSkillsHomeEnv,
|
||||
type SkillsHomeEnvSnapshot,
|
||||
} from "./skills/home-env.test-support.js";
|
||||
import { buildWorkspaceSkillSnapshot, buildWorkspaceSkillsPrompt } from "./skills/workspace.js";
|
||||
|
||||
vi.mock("./skills/plugin-skills.js", () => ({
|
||||
resolvePluginSkillDirs: () => [],
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills.js";
|
||||
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills/workspace.js";
|
||||
|
||||
describe("compactSkillPaths", () => {
|
||||
it("replaces home directory prefix with ~ in skill locations", () => {
|
||||
|
||||
@@ -6,13 +6,13 @@ import { resetLogger, setLoggerOverride } from "../logging/logger.js";
|
||||
import { loggingState } from "../logging/state.js";
|
||||
import { withPathResolutionEnv } from "../test-utils/env.js";
|
||||
import { writeSkill } from "./skills.e2e-test-helpers.js";
|
||||
import { loadWorkspaceSkillEntries } from "./skills.js";
|
||||
import {
|
||||
restoreMockSkillsHomeEnv,
|
||||
setMockSkillsHomeEnv,
|
||||
type SkillsHomeEnvSnapshot,
|
||||
} from "./skills/home-env.test-support.js";
|
||||
import { readSkillFrontmatterSafe } from "./skills/local-loader.js";
|
||||
import { loadWorkspaceSkillEntries } from "./skills/workspace.js";
|
||||
import { writePluginWithSkill } from "./test-helpers/skill-plugin-fixtures.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveSkillsPromptForRun } from "./skills.js";
|
||||
import { createCanonicalFixtureSkill } from "./skills.test-helpers.js";
|
||||
import type { SkillEntry } from "./skills/types.js";
|
||||
import { resolveSkillsPromptForRun } from "./skills/workspace.js";
|
||||
|
||||
describe("resolveSkillsPromptForRun", () => {
|
||||
it("prefers snapshot prompt when available", () => {
|
||||
|
||||
@@ -12,20 +12,19 @@ import { withPathResolutionEnv } from "../test-utils/env.js";
|
||||
import { createFixtureSuite } from "../test-utils/fixture-suite.js";
|
||||
import { createTempHomeEnv, type TempHomeEnv } from "../test-utils/temp-home.js";
|
||||
import { writeSkill } from "./skills.e2e-test-helpers.js";
|
||||
import { buildWorkspaceSkillCommandSpecs } from "./skills/command-specs.js";
|
||||
import {
|
||||
applySkillEnvOverrides,
|
||||
applySkillEnvOverridesFromSnapshot,
|
||||
buildWorkspaceSkillCommandSpecs,
|
||||
buildWorkspaceSkillsPrompt,
|
||||
type SkillEntry,
|
||||
type SkillSnapshot,
|
||||
} from "./skills.js";
|
||||
import { getActiveSkillEnvKeys } from "./skills/env-overrides.js";
|
||||
getActiveSkillEnvKeys,
|
||||
} from "./skills/env-overrides.js";
|
||||
import {
|
||||
restoreMockSkillsHomeEnv,
|
||||
setMockSkillsHomeEnv,
|
||||
type SkillsHomeEnvSnapshot,
|
||||
} from "./skills/home-env.test-support.js";
|
||||
import type { SkillEntry, SkillSnapshot } from "./skills/types.js";
|
||||
import { buildWorkspaceSkillsPrompt } from "./skills/workspace.js";
|
||||
|
||||
vi.mock("./skills/plugin-skills.js", () => ({
|
||||
resolvePluginSkillDirs: () => [],
|
||||
|
||||
Reference in New Issue
Block a user