feat(FN-1968): add skill manifest previews to agent import
- Add SkillManifest support in core with parseSkillManifest and skills directory parsing/export wiring - Extend /api/agents/import responses with dry-run skill previews and skillsCount metadata - Show parsed package skills in AgentImportModal with dedicated preview UI and styles - Add parser, API route, and modal tests covering skill manifest parsing and preview rendering - Keep mission interview assertion generation explicit for milestone/slice fallbacks and update memory guidance for dashboard build resolution
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
parseCompanyManifest,
|
||||
parseProjectManifest,
|
||||
parseSingleAgentManifest,
|
||||
parseSkillManifest,
|
||||
parseTaskManifest,
|
||||
parseTeamManifest,
|
||||
parseYamlFrontmatter,
|
||||
@@ -185,6 +186,24 @@ schedule:
|
||||
expect(manifest.assignee).toBe("./agents/ceo/AGENTS.md");
|
||||
expect(manifest.schedule?.timezone).toBe("America/New_York");
|
||||
});
|
||||
|
||||
it("parses SKILL.md with instruction body", () => {
|
||||
const manifest = parseSkillManifest(`---
|
||||
name: review
|
||||
schema: agentcompanies/v1
|
||||
kind: skill
|
||||
---
|
||||
# review
|
||||
|
||||
Add skill instructions here.`);
|
||||
|
||||
expect(manifest).toEqual({
|
||||
name: "review",
|
||||
schema: "agentcompanies/v1",
|
||||
kind: "skill",
|
||||
instructionBody: "# review\n\nAdd skill instructions here.",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("directory parsing", () => {
|
||||
@@ -252,6 +271,43 @@ name: Solo Agent
|
||||
expect(pkg.teams).toEqual([]);
|
||||
});
|
||||
|
||||
it("parses skills from skills subdirectories", () => {
|
||||
const root = createTempDir();
|
||||
writeTextFile(
|
||||
join(root, "skills", "review", "SKILL.md"),
|
||||
`---
|
||||
name: review
|
||||
kind: skill
|
||||
---
|
||||
# review`,
|
||||
);
|
||||
writeTextFile(
|
||||
join(root, "skills", "strategy", "SKILL.md"),
|
||||
`---
|
||||
name: strategy
|
||||
kind: skill
|
||||
---
|
||||
# strategy`,
|
||||
);
|
||||
|
||||
const pkg = parseCompanyDirectory(root);
|
||||
expect(pkg.skills).toHaveLength(2);
|
||||
expect(pkg.skills?.map((skill) => skill.name)).toEqual(["review", "strategy"]);
|
||||
});
|
||||
|
||||
it("returns empty skills when skills directory is absent", () => {
|
||||
const root = createTempDir();
|
||||
writeTextFile(
|
||||
join(root, "agents", "solo", "AGENTS.md"),
|
||||
`---
|
||||
name: Solo Agent
|
||||
---`,
|
||||
);
|
||||
|
||||
const pkg = parseCompanyDirectory(root);
|
||||
expect(pkg.skills).toEqual([]);
|
||||
});
|
||||
|
||||
it("parses empty directory", () => {
|
||||
const root = createTempDir();
|
||||
const pkg = parseCompanyDirectory(root);
|
||||
@@ -261,6 +317,7 @@ name: Solo Agent
|
||||
teams: [],
|
||||
projects: [],
|
||||
tasks: [],
|
||||
skills: [],
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import type {
|
||||
AgentManifest,
|
||||
CompanyManifest,
|
||||
ProjectManifest,
|
||||
SkillManifest,
|
||||
TaskManifest,
|
||||
TeamManifest,
|
||||
} from "./agent-companies-types.js";
|
||||
@@ -344,6 +345,15 @@ export function parseTaskManifest(content: string): TaskManifest {
|
||||
return parseTypedManifest<TaskManifest>(content, "task");
|
||||
}
|
||||
|
||||
export function parseSkillManifest(content: string): SkillManifest {
|
||||
const { frontmatter, body } = parseYamlFrontmatter(content);
|
||||
requireName(frontmatter, "skill");
|
||||
return {
|
||||
...(frontmatter as unknown as SkillManifest),
|
||||
instructionBody: body,
|
||||
};
|
||||
}
|
||||
|
||||
function parseManifestFile<T>(filePath: string, parser: (content: string) => T): T {
|
||||
try {
|
||||
return parser(readFileSync(filePath, "utf-8"));
|
||||
@@ -443,6 +453,7 @@ export function parseCompanyDirectory(dirPath: string): AgentCompaniesPackage {
|
||||
parseProjectManifest,
|
||||
),
|
||||
tasks: parseManifestSubdirectories(resolvedPath, "tasks", "TASK.md", parseTaskManifest),
|
||||
skills: parseManifestSubdirectories(resolvedPath, "skills", "SKILL.md", parseSkillManifest),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -70,12 +70,17 @@ export interface TaskManifest extends AgentCompaniesFrontmatter {
|
||||
};
|
||||
}
|
||||
|
||||
export interface SkillManifest extends AgentCompaniesFrontmatter {
|
||||
instructionBody?: string;
|
||||
}
|
||||
|
||||
export interface AgentCompaniesPackage {
|
||||
company?: CompanyManifest;
|
||||
agents: AgentManifest[];
|
||||
teams: TeamManifest[];
|
||||
projects: ProjectManifest[];
|
||||
tasks: TaskManifest[];
|
||||
skills?: SkillManifest[];
|
||||
}
|
||||
|
||||
export interface AgentCompaniesImportResult {
|
||||
|
||||
@@ -482,6 +482,7 @@ export type {
|
||||
AgentManifest,
|
||||
ProjectManifest,
|
||||
TaskManifest,
|
||||
SkillManifest,
|
||||
SourceReference,
|
||||
} from "./agent-companies-types.js";
|
||||
|
||||
@@ -495,6 +496,7 @@ export {
|
||||
parseSingleAgentManifest,
|
||||
parseProjectManifest,
|
||||
parseTaskManifest,
|
||||
parseSkillManifest,
|
||||
parseCompanyDirectory,
|
||||
parseCompanyArchive,
|
||||
mapRoleToCapability,
|
||||
|
||||
Reference in New Issue
Block a user