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:
Fusion
2026-04-16 16:05:12 -07:00
committed by gsxdsm
parent 47f19676ae
commit fc33ea89ee
11 changed files with 259 additions and 10 deletions

View File

@@ -20,6 +20,11 @@ interface AgentPreview {
skills?: string[];
}
interface SkillPreview {
name: string;
description?: string;
}
/** Import result from the API */
interface ImportResult {
companyName?: string;
@@ -118,6 +123,7 @@ export function AgentImportModal({ isOpen, onClose, onImported, projectId }: Age
const [directoryAgents, setDirectoryAgents] = useState<DirectoryAgentInput[]>([]);
const [companyName, setCompanyName] = useState("Unknown");
const [agents, setAgents] = useState<AgentPreview[]>([]);
const [skills, setSkills] = useState<SkillPreview[]>([]);
const [isParsing, setIsParsing] = useState(false);
const [isImporting, setIsImporting] = useState(false);
const [parseError, setParseError] = useState<string | null>(null);
@@ -193,6 +199,7 @@ export function AgentImportModal({ isOpen, onClose, onImported, projectId }: Age
setDirectoryAgents([]);
setCompanyName("Unknown");
setAgents([]);
setSkills([]);
setIsParsing(false);
setIsImporting(false);
setParseError(null);
@@ -317,6 +324,7 @@ export function AgentImportModal({ isOpen, onClose, onImported, projectId }: Age
const data = await res.json() as {
companyName?: string;
agents?: AgentPreview[];
skills?: SkillPreview[];
created: string[];
skipped: string[];
errors: Array<{ name: string; error: string }>;
@@ -325,9 +333,11 @@ export function AgentImportModal({ isOpen, onClose, onImported, projectId }: Age
const previewAgents = (data.agents && data.agents.length > 0)
? data.agents
: data.created.map((name) => ({ name, role: "custom" }));
const previewSkills = Array.isArray(data.skills) ? data.skills : [];
setCompanyName(data.companyName ?? "Unknown");
setAgents(previewAgents);
setSkills(previewSkills);
setStep("preview");
} catch (err) {
setParseError(err instanceof Error ? err.message : "Failed to parse manifest");
@@ -628,6 +638,28 @@ export function AgentImportModal({ isOpen, onClose, onImported, projectId }: Age
<p className="agent-import-empty">No agents found in the manifest.</p>
)}
{skills.length > 0 && (
<div className="agent-import-skills-section">
<div className="agent-import-count">
<FileText size={14} />
<span>{skills.length} skill{skills.length !== 1 ? "s" : ""} found</span>
</div>
<div className="agent-import-skill-list">
{skills.map((skill, idx) => (
<div key={`${skill.name}-${idx}`} className="agent-import-skill-item">
<span className="agent-import-skill-icon"></span>
<div className="agent-import-skill-details">
<span className="agent-import-skill-name">{skill.name}</span>
{skill.description && (
<span className="agent-import-skill-description">{skill.description}</span>
)}
</div>
</div>
))}
</div>
</div>
)}
{importError && (
<p className="agent-dialog-error">
<AlertTriangle size={14} />