From 2f6f5477c594bf7ce1b9e0b86afe447836c69099 Mon Sep 17 00:00:00 2001 From: GRayHook Date: Wed, 17 Jun 2026 17:35:51 +0700 Subject: [PATCH] =?UTF-8?q?Phase=2014:=20deferred=20reinject=20regression?= =?UTF-8?q?=20tests=20=E2=80=94=20loose,=20strict,=20missing=20disk?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test/reinject.test.ts gates B-002 defer-path filter and build behavior for requireRegistered and missing SKILL.md. Co-authored-by: Cursor --- test/reinject.test.ts | 81 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 test/reinject.test.ts diff --git a/test/reinject.test.ts b/test/reinject.test.ts new file mode 100644 index 0000000..8e2e7fc --- /dev/null +++ b/test/reinject.test.ts @@ -0,0 +1,81 @@ +import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { buildReinjectBlocks, tryConsumeDeferredReinject } from "../src/reinject"; +import { createDefaultSettings } from "../src/settings"; +import { createInitialState, trackSkill } from "../src/state"; + +const tempDirs: string[] = []; + +afterEach(() => { + for (const dir of tempDirs.splice(0)) { + rmSync(dir, { recursive: true, force: true }); + } +}); + +function tempSkillDir(name: string): { filePath: string; baseDir: string } { + const root = mkdtempSync(join(tmpdir(), "pi-skill-reinject-deferred-")); + tempDirs.push(root); + const baseDir = join(root, name); + mkdirSync(baseDir, { recursive: true }); + const filePath = join(baseDir, "SKILL.md"); + writeFileSync(filePath, "# skill\n", "utf8"); + return { filePath, baseDir }; +} + +function ctxWithNotify(): { ctx: never; notify: ReturnType } { + const notify = vi.fn(); + return { notify, ctx: { hasUI: true, ui: { notify } } as never }; +} + +describe("deferred reinject loose fallback", () => { + it("(a) unregistered on disk with requireRegistered=false → block + info notify", () => { + const { filePath, baseDir } = tempSkillDir("loose"); + const state = createInitialState(); + trackSkill(state, { name: "loose", filePath, baseDir, source: "slash" }); + state.pendingReinject = ["loose"]; + const { ctx, notify } = ctxWithNotify(); + + const result = tryConsumeDeferredReinject(state, createDefaultSettings(), [], ctx); + + expect(result?.message?.content).toContain(' { + const { filePath, baseDir } = tempSkillDir("strict"); + const state = createInitialState(); + trackSkill(state, { name: "strict", filePath, baseDir, source: "slash" }); + const settings = createDefaultSettings(); + settings.requireRegistered = true; + const { ctx, notify } = ctxWithNotify(); + + const blocks = buildReinjectBlocks(["strict"], state, settings, [], ctx); + + expect(blocks).toEqual([]); + expect(notify).toHaveBeenCalledWith( + 'skill-reinject: skipped "strict" — no longer registered', + "warning", + ); + }); + + it("(c) missing filePath on disk → skip + warn", () => { + const state = createInitialState(); + trackSkill(state, { + name: "missing", + filePath: "/no/such/SKILL.md", + baseDir: "/no/such", + source: "slash", + }); + const { ctx, notify } = ctxWithNotify(); + + const blocks = buildReinjectBlocks(["missing"], state, createDefaultSettings(), [], ctx); + + expect(blocks).toEqual([]); + expect(notify).toHaveBeenCalledWith( + 'skill-reinject: skipped "missing" — SKILL.md not found on disk', + "warning", + ); + }); +});