





















@@ -1,4 +1,4 @@
1-import fsSync from "node:fs";
1+import fsSync, { type Dirent } from "node:fs";
22import fs from "node:fs/promises";
33import path from "node:path";
44import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
@@ -366,7 +366,18 @@ describe("resolvePluginSkillDirs", () => {
366366});
367367368368describe("publishPluginSkills", () => {
369-const { publishPluginSkills } = __testing;
369+const { isGeneratedPluginSkillEntry, publishPluginSkills, resolvePluginSkillLinkType } =
370+__testing;
371+372+function withPlatform<T>(platform: NodeJS.Platform, fn: () => T): T {
373+const originalPlatform = process.platform;
374+Object.defineProperty(process, "platform", { configurable: true, value: platform });
375+try {
376+return fn();
377+} finally {
378+Object.defineProperty(process, "platform", { configurable: true, value: originalPlatform });
379+}
380+}
370381371382async function writeSkillDir(
372383parentDir: string,
@@ -399,6 +410,12 @@ describe("publishPluginSkills", () => {
399410expect(fsSync.readlinkSync(linkB)).toBe(dirB);
400411});
401412413+it("uses junction links for plugin skill directories on Windows", async () => {
414+expect(resolvePluginSkillLinkType("win32")).toBe("junction");
415+expect(resolvePluginSkillLinkType("linux")).toBe("dir");
416+expect(resolvePluginSkillLinkType("darwin")).toBe("dir");
417+});
418+402419it("is idempotent: skips symlinks that already point to the same target", async () => {
403420const skillParent = await tempDirs.make("plugin-skills-");
404421const managedDir = await tempDirs.make("managed-skills-");
@@ -446,6 +463,37 @@ describe("publishPluginSkills", () => {
446463expect(fsSync.existsSync(path.join(managedDir, "stale-skill"))).toBe(false);
447464});
448465466+it("cleans up stale generated junction-like directories on Windows", async () => {
467+const skillParent = await tempDirs.make("plugin-skills-");
468+const managedDir = await tempDirs.make("managed-skills-");
469+470+const dir = await writeSkillDir(skillParent, "current-skill");
471+const staleDir = path.join(managedDir, "stale-skill");
472+await fs.mkdir(staleDir, { recursive: true });
473+474+await withPlatform("win32", async () => {
475+publishPluginSkills([dir], { pluginSkillsDir: managedDir });
476+});
477+478+expect(fsSync.existsSync(path.join(managedDir, "current-skill"))).toBe(true);
479+expect(fsSync.existsSync(staleDir)).toBe(false);
480+});
481+482+it("treats Windows directory entries as generated plugin skill entries", () => {
483+const directoryEntry = {
484+isDirectory: () => true,
485+isSymbolicLink: () => false,
486+} as Dirent;
487+const regularEntry = {
488+isDirectory: () => false,
489+isSymbolicLink: () => false,
490+} as Dirent;
491+492+expect(withPlatform("win32", () => isGeneratedPluginSkillEntry(directoryEntry))).toBe(true);
493+expect(withPlatform("linux", () => isGeneratedPluginSkillEntry(directoryEntry))).toBe(false);
494+expect(withPlatform("win32", () => isGeneratedPluginSkillEntry(regularEntry))).toBe(false);
495+});
496+449497it("cleans up broken symlinks (dangling)", async () => {
450498const skillParent = await tempDirs.make("plugin-skills-");
451499const managedDir = await tempDirs.make("managed-skills-");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。