fix(coding-agent): tighten skill discovery and edit diffs closes #2603
This commit is contained in:
@@ -106,6 +106,22 @@ Content`,
|
||||
expect(result.skills.some((r) => r.path === skillFile && r.enabled)).toBe(true);
|
||||
});
|
||||
|
||||
it("should auto-discover root markdown skills from .pi skill dirs", async () => {
|
||||
const skillFile = join(agentDir, "skills", "single-file.md");
|
||||
mkdirSync(join(agentDir, "skills"), { recursive: true });
|
||||
writeFileSync(
|
||||
skillFile,
|
||||
`---
|
||||
name: single-file
|
||||
description: A root markdown skill
|
||||
---
|
||||
Content`,
|
||||
);
|
||||
|
||||
const result = await packageManager.resolve();
|
||||
expect(result.skills.some((r) => r.path === skillFile && r.enabled)).toBe(true);
|
||||
});
|
||||
|
||||
it("should resolve project paths relative to .pi", async () => {
|
||||
const extDir = join(tempDir, ".pi", "extensions");
|
||||
mkdirSync(extDir, { recursive: true });
|
||||
@@ -232,6 +248,26 @@ Content`,
|
||||
expect(result.skills.some((r) => r.path === middleSkill && r.enabled)).toBe(true);
|
||||
});
|
||||
|
||||
it("should ignore root markdown files in .agents/skills", async () => {
|
||||
const agentsSkillsDir = join(tempDir, ".agents", "skills");
|
||||
mkdirSync(join(agentsSkillsDir, "nested-skill"), { recursive: true });
|
||||
const rootSkill = join(agentsSkillsDir, "root-file.md");
|
||||
const nestedSkill = join(agentsSkillsDir, "nested-skill", "SKILL.md");
|
||||
writeFileSync(rootSkill, "---\nname: root-file\ndescription: Root markdown file\n---\n");
|
||||
writeFileSync(nestedSkill, "---\nname: nested-skill\ndescription: Nested skill\n---\n");
|
||||
|
||||
const pm = new DefaultPackageManager({
|
||||
cwd: join(tempDir, "work"),
|
||||
agentDir,
|
||||
settingsManager,
|
||||
});
|
||||
mkdirSync(join(tempDir, "work"), { recursive: true });
|
||||
|
||||
const result = await pm.resolve();
|
||||
expect(result.skills.some((r) => r.path === rootSkill)).toBe(false);
|
||||
expect(result.skills.some((r) => r.path === nestedSkill && r.enabled)).toBe(true);
|
||||
});
|
||||
|
||||
it("should keep ~/.agents/skills user-scoped when cwd is under home in a non-git directory", async () => {
|
||||
const previousHome = process.env.HOME;
|
||||
process.env.HOME = tempDir;
|
||||
@@ -352,6 +388,19 @@ Content`,
|
||||
expect(result.extensions.some((r) => pathEndsWith(r.path, "main.ts") && r.enabled)).toBe(true);
|
||||
expect(result.themes.some((r) => pathEndsWith(r.path, "dark.json") && r.enabled)).toBe(true);
|
||||
});
|
||||
|
||||
it("should stop recursing when a package skill directory contains SKILL.md", async () => {
|
||||
const pkgDir = join(tempDir, "skill-root-pkg");
|
||||
mkdirSync(join(pkgDir, "skills", "root-skill", "nested-skill"), { recursive: true });
|
||||
const rootSkill = join(pkgDir, "skills", "root-skill", "SKILL.md");
|
||||
const nestedSkill = join(pkgDir, "skills", "root-skill", "nested-skill", "SKILL.md");
|
||||
writeFileSync(rootSkill, "---\nname: root-skill\ndescription: Root skill\n---\n");
|
||||
writeFileSync(nestedSkill, "---\nname: nested-skill\ndescription: Nested skill\n---\n");
|
||||
|
||||
const result = await packageManager.resolveExtensionSources([pkgDir]);
|
||||
expect(result.skills.some((r) => r.path === rootSkill && r.enabled)).toBe(true);
|
||||
expect(result.skills.some((r) => r.path === nestedSkill)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("progress callback", () => {
|
||||
|
||||
@@ -277,6 +277,29 @@ describe("Coding Agent Tools", () => {
|
||||
expect(result.details?.diff).toContain("GAMMA");
|
||||
});
|
||||
|
||||
it("should collapse large unchanged gaps in multi-edit diffs", async () => {
|
||||
const testFile = join(testDir, "edit-multi-large-gap.txt");
|
||||
const lines = Array.from({ length: 600 }, (_, i) => `line ${String(i + 1).padStart(3, "0")}`);
|
||||
writeFileSync(testFile, `${lines.join("\n")}\n`);
|
||||
|
||||
const result = await editTool.execute("test-call-8b", {
|
||||
path: testFile,
|
||||
edits: [
|
||||
{ oldText: "line 100\n", newText: "LINE 100\n" },
|
||||
{ oldText: "line 300\n", newText: "LINE 300\n" },
|
||||
{ oldText: "line 500\n", newText: "LINE 500\n" },
|
||||
],
|
||||
});
|
||||
|
||||
const diff = result.details?.diff ?? "";
|
||||
expect(diff).toContain("LINE 100");
|
||||
expect(diff).toContain("LINE 300");
|
||||
expect(diff).toContain("LINE 500");
|
||||
expect(diff).toContain("...");
|
||||
expect(diff).not.toContain("line 250");
|
||||
expect(diff.split("\n").length).toBeLessThan(50);
|
||||
});
|
||||
|
||||
it("should match edits against the original file, not incrementally", async () => {
|
||||
const testFile = join(testDir, "edit-multi-original.txt");
|
||||
writeFileSync(testFile, "foo\nbar\nbaz\n");
|
||||
|
||||
Reference in New Issue
Block a user