@agent-native/core 0.24.10 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/composer/ComposerPlusMenu.d.ts.map +1 -1
- package/dist/client/composer/ComposerPlusMenu.js +138 -5
- package/dist/client/composer/ComposerPlusMenu.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +124 -8
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/server/onboarding-html.js +1 -1
- package/dist/server/onboarding-html.js.map +1 -1
- package/package.json +1 -1
|
@@ -38,7 +38,7 @@ function buildAgentResourceContent({ name, description, model, tools, body, }) {
|
|
|
38
38
|
];
|
|
39
39
|
return serializeFrontmatter(fields) + body.trim() + "\n";
|
|
40
40
|
}
|
|
41
|
-
function CreateMenu({ scope, onCreateFile, onCreateResource, onCreateMcpServer, canCreateOrgMcp, hasOrg, onCreated, }) {
|
|
41
|
+
function CreateMenu({ scope, onCreateFile, onCreateResource, onCreateMcpServer, canCreateOrgMcp, hasOrg, onCreated, showToast, }) {
|
|
42
42
|
const [open, setOpen] = useState(false);
|
|
43
43
|
const [view, setView] = useState("menu");
|
|
44
44
|
const [value, setValue] = useState("");
|
|
@@ -56,6 +56,33 @@ function CreateMenu({ scope, onCreateFile, onCreateResource, onCreateMcpServer,
|
|
|
56
56
|
const [mcpError, setMcpError] = useState(null);
|
|
57
57
|
const [mcpTestResult, setMcpTestResult] = useState(null);
|
|
58
58
|
const inputRef = useRef(null);
|
|
59
|
+
const skillFileInputRef = useRef(null);
|
|
60
|
+
const skillHoverTimerRef = useRef(null);
|
|
61
|
+
const [skillFlyoutOpen, setSkillFlyoutOpen] = useState(false);
|
|
62
|
+
const [skillFlyoutSide, setSkillFlyoutSide] = useState("right");
|
|
63
|
+
const skillFlyoutCloseTimerRef = useRef(null);
|
|
64
|
+
const openSkillFlyout = (rowEl) => {
|
|
65
|
+
if (skillFlyoutCloseTimerRef.current) {
|
|
66
|
+
window.clearTimeout(skillFlyoutCloseTimerRef.current);
|
|
67
|
+
skillFlyoutCloseTimerRef.current = null;
|
|
68
|
+
}
|
|
69
|
+
if (rowEl && typeof window !== "undefined") {
|
|
70
|
+
const rect = rowEl.getBoundingClientRect();
|
|
71
|
+
const FLYOUT_WIDTH = 248;
|
|
72
|
+
setSkillFlyoutSide(window.innerWidth - rect.right < FLYOUT_WIDTH ? "left" : "right");
|
|
73
|
+
}
|
|
74
|
+
setSkillFlyoutOpen(true);
|
|
75
|
+
};
|
|
76
|
+
const scheduleSkillFlyoutClose = () => {
|
|
77
|
+
if (skillFlyoutCloseTimerRef.current)
|
|
78
|
+
window.clearTimeout(skillFlyoutCloseTimerRef.current);
|
|
79
|
+
skillFlyoutCloseTimerRef.current = window.setTimeout(() => {
|
|
80
|
+
setSkillFlyoutOpen(false);
|
|
81
|
+
}, 160);
|
|
82
|
+
};
|
|
83
|
+
const [skillUploadSlug, setSkillUploadSlug] = useState("");
|
|
84
|
+
const [skillUploadContent, setSkillUploadContent] = useState("");
|
|
85
|
+
const [skillUploadFileName, setSkillUploadFileName] = useState("");
|
|
59
86
|
useEffect(() => {
|
|
60
87
|
if (open) {
|
|
61
88
|
setView("menu");
|
|
@@ -72,6 +99,10 @@ function CreateMenu({ scope, onCreateFile, onCreateResource, onCreateMcpServer,
|
|
|
72
99
|
setMcpError(null);
|
|
73
100
|
setMcpTestResult(null);
|
|
74
101
|
setMcpBusy(false);
|
|
102
|
+
setSkillUploadSlug("");
|
|
103
|
+
setSkillUploadContent("");
|
|
104
|
+
setSkillUploadFileName("");
|
|
105
|
+
setSkillFlyoutOpen(false);
|
|
75
106
|
}
|
|
76
107
|
}, [open, defaultMcpScope]);
|
|
77
108
|
useEffect(() => {
|
|
@@ -169,6 +200,38 @@ Keep the skill concise (under 500 lines) and actionable.`,
|
|
|
169
200
|
setOpen(false);
|
|
170
201
|
onCreated?.();
|
|
171
202
|
};
|
|
203
|
+
const handleUploadSkillFiles = async (files) => {
|
|
204
|
+
if (!files || files.length === 0)
|
|
205
|
+
return;
|
|
206
|
+
const file = files[0];
|
|
207
|
+
const text = await file.text();
|
|
208
|
+
const baseName = file.name.replace(/\.[^./]+$/, "");
|
|
209
|
+
const slug = slugifyName(baseName.toLowerCase() === "skill" ? "uploaded-skill" : baseName);
|
|
210
|
+
setSkillUploadSlug(slug);
|
|
211
|
+
setSkillUploadContent(text);
|
|
212
|
+
setSkillUploadFileName(file.name);
|
|
213
|
+
setView("skill-upload");
|
|
214
|
+
};
|
|
215
|
+
const saveUploadedSkill = () => {
|
|
216
|
+
const slug = slugifyName(skillUploadSlug || "uploaded-skill");
|
|
217
|
+
const path = `skills/${slug}/SKILL.md`;
|
|
218
|
+
const fileLabel = skillUploadFileName || `${slug}/SKILL.md`;
|
|
219
|
+
onCreateResource(path, skillUploadContent, "text/markdown", {
|
|
220
|
+
onSuccess: (resource) => {
|
|
221
|
+
showToast?.("ok", `Skill "${fileLabel}" added`, {
|
|
222
|
+
resourceId: resource.id,
|
|
223
|
+
});
|
|
224
|
+
},
|
|
225
|
+
onError: (err) => {
|
|
226
|
+
const msg = err instanceof Error && err.message
|
|
227
|
+
? err.message
|
|
228
|
+
: "Failed to save skill file";
|
|
229
|
+
showToast?.("err", msg);
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
setOpen(false);
|
|
233
|
+
onCreated?.();
|
|
234
|
+
};
|
|
172
235
|
const submitJob = (text = value) => {
|
|
173
236
|
const trimmed = text.trim();
|
|
174
237
|
if (!trimmed)
|
|
@@ -349,7 +412,8 @@ The result should be a reusable agent profile, not a one-off task response.`,
|
|
|
349
412
|
icon: _jsx(IconBulb, { className: "h-3.5 w-3.5" }),
|
|
350
413
|
label: "Create Skill",
|
|
351
414
|
desc: "Teach the agent a new ability",
|
|
352
|
-
action:
|
|
415
|
+
action: openSkillFlyout,
|
|
416
|
+
hoverAction: openSkillFlyout,
|
|
353
417
|
},
|
|
354
418
|
{
|
|
355
419
|
icon: _jsx(IconClock, { className: "h-3.5 w-3.5" }),
|
|
@@ -388,16 +452,51 @@ The result should be a reusable agent profile, not a one-off task response.`,
|
|
|
388
452
|
action: () => setView("mcp-server"),
|
|
389
453
|
},
|
|
390
454
|
];
|
|
391
|
-
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [
|
|
455
|
+
return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx("input", { ref: skillFileInputRef, type: "file", accept: ".md,text/markdown", multiple: true, className: "hidden", onChange: (e) => {
|
|
456
|
+
handleUploadSkillFiles(e.target.files);
|
|
457
|
+
e.target.value = "";
|
|
458
|
+
} }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", className: cn("flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50", open && "bg-accent/50 text-foreground"), children: _jsx(IconPlus, { className: "h-3.5 w-3.5" }) }) }) }), _jsx(TooltipContent, { children: "Create new..." })] }), _jsxs(PopoverContent, { align: "end", sideOffset: 6, collisionPadding: 8, className: cn("z-[260] p-0 text-[13px] leading-normal", view === "menu" || view === "file"
|
|
392
459
|
? "w-[260px]"
|
|
393
|
-
: "max-h-[70vh] w-[calc(100vw-24px)] max-w-[380px] overflow-y-auto"), children: [view === "menu" && (_jsx("div", { className: "py-1", children: menuItems.map((item) =>
|
|
460
|
+
: "max-h-[70vh] w-[calc(100vw-24px)] max-w-[380px] overflow-y-auto"), children: [view === "menu" && (_jsx("div", { className: "py-1", children: menuItems.map((item) => {
|
|
461
|
+
const isSkill = item.label === "Create Skill";
|
|
462
|
+
return (_jsxs("div", { className: "relative", onMouseEnter: (e) => {
|
|
463
|
+
if (isSkill) {
|
|
464
|
+
openSkillFlyout(e.currentTarget);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
if (!item.hoverAction)
|
|
468
|
+
return;
|
|
469
|
+
if (skillHoverTimerRef.current)
|
|
470
|
+
window.clearTimeout(skillHoverTimerRef.current);
|
|
471
|
+
skillHoverTimerRef.current = window.setTimeout(() => {
|
|
472
|
+
item.hoverAction?.();
|
|
473
|
+
}, 180);
|
|
474
|
+
}, onMouseLeave: () => {
|
|
475
|
+
if (isSkill) {
|
|
476
|
+
scheduleSkillFlyoutClose();
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (skillHoverTimerRef.current) {
|
|
480
|
+
window.clearTimeout(skillHoverTimerRef.current);
|
|
481
|
+
skillHoverTimerRef.current = null;
|
|
482
|
+
}
|
|
483
|
+
}, children: [_jsxs("button", { type: "button", onClick: item.action, className: cn("flex w-full items-center gap-2.5 px-3 py-2 text-left hover:bg-accent/50", isSkill && skillFlyoutOpen && "bg-accent/50"), children: [_jsx("span", { className: "text-muted-foreground", children: item.icon }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: item.label }), _jsx("div", { className: "mt-0.5 text-[10px] text-muted-foreground/60", children: item.desc })] }), isSkill && (_jsx("span", { className: "ml-auto text-muted-foreground/60", children: "\u203A" }))] }), isSkill && skillFlyoutOpen && (_jsxs("div", { role: "menu", onMouseEnter: () => openSkillFlyout(), onMouseLeave: scheduleSkillFlyoutClose, className: cn("absolute top-0 z-20 w-[240px] rounded-lg border border-border bg-popover py-1 shadow-md", skillFlyoutSide === "right"
|
|
484
|
+
? "left-full ml-1"
|
|
485
|
+
: "right-full mr-1"), children: [_jsxs("button", { type: "button", onClick: () => {
|
|
486
|
+
setSkillFlyoutOpen(false);
|
|
487
|
+
setView("skill");
|
|
488
|
+
}, className: "flex w-full items-center gap-2.5 px-3 py-2 text-left hover:bg-accent/50", children: [_jsx("span", { className: "text-muted-foreground", children: _jsx(IconBulb, { className: "h-3.5 w-3.5" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: "Create new skill" }), _jsx("div", { className: "mt-0.5 text-[10px] text-muted-foreground/60", children: "Describe a skill and let the agent draft it" })] })] }), _jsxs("button", { type: "button", onClick: () => {
|
|
489
|
+
setSkillFlyoutOpen(false);
|
|
490
|
+
skillFileInputRef.current?.click();
|
|
491
|
+
}, className: "flex w-full items-center gap-2.5 px-3 py-2 text-left hover:bg-accent/50", children: [_jsx("span", { className: "text-muted-foreground", children: _jsx(IconUpload, { className: "h-3.5 w-3.5" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: "Upload skill file" }), _jsx("div", { className: "mt-0.5 text-[10px] text-muted-foreground/60", children: "Import an existing SKILL.md file" })] })] })] }))] }, item.label));
|
|
492
|
+
}) })), view === "file" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1.5 block text-[11px] font-medium text-muted-foreground", children: "File path" }), _jsx("input", { ref: inputRef, value: value, onChange: (e) => setValue(e.target.value), onKeyDown: (e) => {
|
|
394
493
|
if (e.key === "Enter")
|
|
395
494
|
submitFile();
|
|
396
495
|
if (e.key === "Escape") {
|
|
397
496
|
e.stopPropagation();
|
|
398
497
|
setView("menu");
|
|
399
498
|
}
|
|
400
|
-
}, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "notes/ideas.md" }), _jsx("div", { className: "mt-2.5 flex justify-end", children: _jsx("button", { onClick: submitFile, disabled: !value.trim(), className: "rounded-md bg-accent px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent/80 disabled:opacity-40 disabled:pointer-events-none", children: "Create" }) })] })), view === "skill" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Create Skill" }), _jsx("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: "Describe what kind of skill you want and the agent will create it." }), _jsx(PromptComposer, { autoFocus: true, placeholder: "e.g. A skill that reviews PRs for security issues and OWASP top 10 vulnerabilities", draftScope: "resources:create-skill", onSubmit: (text) => submitSkill(text) })] })), view === "job" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Schedule Task" }), _jsx("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: "Describe what should happen and when." }), _jsx(PromptComposer, { autoFocus: true, placeholder: "e.g. Every weekday at 9am, check for overdue scorecards and send a Slack update", draftScope: "resources:create-job", onSubmit: (text) => submitJob(text) })] })), view === "agent-mode" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Create Agent" }), _jsx("p", { className: "mb-2 text-[10px] leading-relaxed text-muted-foreground/60", children: "Build a reusable sub-agent profile for this workspace." }), _jsxs("div", { className: "space-y-2", children: [_jsxs("button", { onClick: () => setView("agent-prompt"), className: "flex w-full items-start gap-2 rounded-md border border-border px-3 py-2 text-left hover:bg-accent/40", children: [_jsx(IconPencil, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsxs("div", { children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: "Describe It" }), _jsx("div", { className: "text-[10px] text-muted-foreground/60", children: "Let the agent draft the profile from a prompt." })] })] }), _jsxs("button", { onClick: () => setView("agent-form"), className: "flex w-full items-start gap-2 rounded-md border border-border px-3 py-2 text-left hover:bg-accent/40", children: [_jsx(IconMessageChatbot, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsxs("div", { children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: "Fill Form" }), _jsx("div", { className: "text-[10px] text-muted-foreground/60", children: "Set the fields manually and start with a markdown template." })] })] })] })] })), view === "agent-prompt" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Create Agent From Prompt" }), _jsxs("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: ["Describe the agent you want. It will be saved under", " ", _jsx("code", { children: "agents/" }), "."] }), _jsx(PromptComposer, { autoFocus: true, placeholder: "e.g. A design agent that critiques layouts, suggests UI direction, and prefers concise product reasoning", draftScope: "resources:create-agent", onSubmit: (text) => submitAgentPrompt(text) })] })), view === "agent-form" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-2 block text-[11px] font-semibold text-foreground", children: "Create Agent Manually" }), _jsxs("div", { className: "space-y-2", children: [_jsx("input", { value: agentName, onChange: (e) => setAgentName(e.target.value), className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Agent name" }), _jsx("input", { value: agentDescription, onChange: (e) => setAgentDescription(e.target.value), className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Short description" }), _jsx("label", { className: "block text-[11px] font-medium text-muted-foreground", children: "Model" }), _jsx("select", { value: agentModel, onChange: (e) => setAgentModel(e.target.value), className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none focus:ring-1 focus:ring-accent", children: AGENT_MODEL_OPTIONS.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) }), _jsx("label", { className: "block text-[11px] font-medium text-muted-foreground", children: "Instructions" }), _jsx("textarea", { value: agentInstructions, onChange: (e) => setAgentInstructions(e.target.value), rows: 8, className: "w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", style: {
|
|
499
|
+
}, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "notes/ideas.md" }), _jsx("div", { className: "mt-2.5 flex justify-end", children: _jsx("button", { onClick: submitFile, disabled: !value.trim(), className: "rounded-md bg-accent px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent/80 disabled:opacity-40 disabled:pointer-events-none", children: "Create" }) })] })), view === "skill" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Create Skill" }), _jsx("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: "Describe what kind of skill you want and the agent will create it." }), _jsx(PromptComposer, { autoFocus: true, placeholder: "e.g. A skill that reviews PRs for security issues and OWASP top 10 vulnerabilities", draftScope: "resources:create-skill", onSubmit: (text) => submitSkill(text) })] })), view === "skill-upload" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Upload skill file" }), _jsxs("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: ["Review the content from", " ", _jsx("span", { className: "font-mono", children: skillUploadFileName || "the selected file" }), " ", "before saving."] }), _jsx("label", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: "Skill name" }), _jsx("input", { value: skillUploadSlug, onChange: (e) => setSkillUploadSlug(e.target.value), className: "mb-2 w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[12px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "my-skill" }), _jsxs("p", { className: "mb-2 text-[10px] text-muted-foreground/60", children: ["Will be saved at", " ", _jsxs("span", { className: "font-mono", children: ["skills/", slugifyName(skillUploadSlug || "uploaded-skill"), "/SKILL.md"] })] }), _jsx("label", { className: "mb-1 block text-[10px] font-medium text-muted-foreground", children: "Content" }), _jsx("textarea", { value: skillUploadContent, onChange: (e) => setSkillUploadContent(e.target.value), rows: 14, className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 font-mono text-[11px] leading-relaxed text-foreground outline-none focus:ring-1 focus:ring-accent" }), _jsxs("div", { className: "mt-2.5 flex justify-end gap-2", children: [_jsx("button", { onClick: () => setView("menu"), className: "rounded-md px-3 py-1.5 text-[12px] font-medium text-muted-foreground hover:bg-accent/40", children: "Back" }), _jsx("button", { onClick: saveUploadedSkill, disabled: !skillUploadContent.trim() || !skillUploadSlug.trim(), className: "rounded-md bg-accent px-3 py-1.5 text-[12px] font-medium text-foreground hover:bg-accent/80 disabled:opacity-40 disabled:pointer-events-none", children: "Save" })] })] })), view === "job" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Schedule Task" }), _jsx("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: "Describe what should happen and when." }), _jsx(PromptComposer, { autoFocus: true, placeholder: "e.g. Every weekday at 9am, check for overdue scorecards and send a Slack update", draftScope: "resources:create-job", onSubmit: (text) => submitJob(text) })] })), view === "agent-mode" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Create Agent" }), _jsx("p", { className: "mb-2 text-[10px] leading-relaxed text-muted-foreground/60", children: "Build a reusable sub-agent profile for this workspace." }), _jsxs("div", { className: "space-y-2", children: [_jsxs("button", { onClick: () => setView("agent-prompt"), className: "flex w-full items-start gap-2 rounded-md border border-border px-3 py-2 text-left hover:bg-accent/40", children: [_jsx(IconPencil, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsxs("div", { children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: "Describe It" }), _jsx("div", { className: "text-[10px] text-muted-foreground/60", children: "Let the agent draft the profile from a prompt." })] })] }), _jsxs("button", { onClick: () => setView("agent-form"), className: "flex w-full items-start gap-2 rounded-md border border-border px-3 py-2 text-left hover:bg-accent/40", children: [_jsx(IconMessageChatbot, { className: "mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground" }), _jsxs("div", { children: [_jsx("div", { className: "text-[12px] font-medium text-foreground", children: "Fill Form" }), _jsx("div", { className: "text-[10px] text-muted-foreground/60", children: "Set the fields manually and start with a markdown template." })] })] })] })] })), view === "agent-prompt" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-1 block text-[11px] font-semibold text-foreground", children: "Create Agent From Prompt" }), _jsxs("p", { className: "mb-2 text-[10px] text-muted-foreground/60 leading-relaxed", children: ["Describe the agent you want. It will be saved under", " ", _jsx("code", { children: "agents/" }), "."] }), _jsx(PromptComposer, { autoFocus: true, placeholder: "e.g. A design agent that critiques layouts, suggests UI direction, and prefers concise product reasoning", draftScope: "resources:create-agent", onSubmit: (text) => submitAgentPrompt(text) })] })), view === "agent-form" && (_jsxs("div", { className: "p-3", children: [_jsx("label", { className: "mb-2 block text-[11px] font-semibold text-foreground", children: "Create Agent Manually" }), _jsxs("div", { className: "space-y-2", children: [_jsx("input", { value: agentName, onChange: (e) => setAgentName(e.target.value), className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Agent name" }), _jsx("input", { value: agentDescription, onChange: (e) => setAgentDescription(e.target.value), className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", placeholder: "Short description" }), _jsx("label", { className: "block text-[11px] font-medium text-muted-foreground", children: "Model" }), _jsx("select", { value: agentModel, onChange: (e) => setAgentModel(e.target.value), className: "w-full rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none focus:ring-1 focus:ring-accent", children: AGENT_MODEL_OPTIONS.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value))) }), _jsx("label", { className: "block text-[11px] font-medium text-muted-foreground", children: "Instructions" }), _jsx("textarea", { value: agentInstructions, onChange: (e) => setAgentInstructions(e.target.value), rows: 8, className: "w-full resize-y rounded-md border border-border bg-background px-2.5 py-1.5 text-[13px] text-foreground outline-none placeholder:text-muted-foreground/50 focus:ring-1 focus:ring-accent", style: {
|
|
401
500
|
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
|
|
402
501
|
lineHeight: 1.5,
|
|
403
502
|
} })] }), _jsx("div", { className: "mt-2.5 flex justify-end", children: _jsx("button", { onClick: submitAgentManual, disabled: !agentName.trim() ||
|
|
@@ -470,6 +569,14 @@ export function ResourcesPanel() {
|
|
|
470
569
|
const [selectedResourceId, setSelectedResourceId] = useState(null);
|
|
471
570
|
const [toolbarDeleteConfirmId, setToolbarDeleteConfirmId] = useState(null);
|
|
472
571
|
const [dragOver, setDragOver] = useState(false);
|
|
572
|
+
const [toast, setToast] = useState(null);
|
|
573
|
+
const toastTimerRef = useRef(null);
|
|
574
|
+
const showToast = useCallback((kind, message, opts) => {
|
|
575
|
+
setToast({ kind, message, resourceId: opts?.resourceId });
|
|
576
|
+
if (toastTimerRef.current)
|
|
577
|
+
window.clearTimeout(toastTimerRef.current);
|
|
578
|
+
toastTimerRef.current = window.setTimeout(() => setToast(null), opts?.durationMs ?? 5000);
|
|
579
|
+
}, []);
|
|
473
580
|
const [editorView, setEditorView] = useState(() => {
|
|
474
581
|
try {
|
|
475
582
|
const v = localStorage.getItem("resource-editor-view");
|
|
@@ -601,10 +708,14 @@ export function ResourcesPanel() {
|
|
|
601
708
|
},
|
|
602
709
|
});
|
|
603
710
|
}, [createResource, activeScope]);
|
|
604
|
-
const handleCreateResourceFromToolbar = useCallback((path, content, mimeType) => {
|
|
711
|
+
const handleCreateResourceFromToolbar = useCallback((path, content, mimeType, opts) => {
|
|
605
712
|
createResource.mutate({ path, content, mimeType, shared: activeScope === "shared" }, {
|
|
606
713
|
onSuccess: (data) => {
|
|
607
714
|
setSelectedResourceId(data.id);
|
|
715
|
+
opts?.onSuccess?.(data);
|
|
716
|
+
},
|
|
717
|
+
onError: (err) => {
|
|
718
|
+
opts?.onError?.(err);
|
|
608
719
|
},
|
|
609
720
|
});
|
|
610
721
|
}, [activeScope, createResource]);
|
|
@@ -696,7 +807,7 @@ export function ResourcesPanel() {
|
|
|
696
807
|
: "Delete resource", className: cn("flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground hover:text-destructive hover:bg-accent/50", toolbarDeleteConfirmId === selectedResourceId &&
|
|
697
808
|
"bg-destructive/10 text-destructive"), children: _jsx(IconTrash, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: toolbarDeleteConfirmId === selectedResourceId
|
|
698
809
|
? "Click again to delete"
|
|
699
|
-
: "Delete resource" })] }) }))] })] })) : (_jsxs("div", { className: "absolute top-1 right-1 z-10 flex items-center gap-1", children: [_jsx(CreateMenu, { scope: activeScope, onCreateFile: handleCreateFromToolbar, onCreateResource: handleCreateResourceFromToolbar, onCreateMcpServer: handleCreateMcpServer, canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrgForMcp }), _jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: () => fileInputRef.current?.click(), "aria-label": "Upload file", className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconUpload, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Upload file" })] }) }), _jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setShowAgentScratch((value) => !value), "aria-label": showAgentScratch
|
|
810
|
+
: "Delete resource" })] }) }))] })] })) : (_jsxs("div", { className: "absolute top-1 right-1 z-10 flex items-center gap-1", children: [_jsx(CreateMenu, { scope: activeScope, onCreateFile: handleCreateFromToolbar, onCreateResource: handleCreateResourceFromToolbar, onCreateMcpServer: handleCreateMcpServer, canCreateOrgMcp: canCreateOrgMcp, hasOrg: hasOrgForMcp, showToast: showToast }), _jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { onClick: () => fileInputRef.current?.click(), "aria-label": "Upload file", className: "flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconUpload, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Upload file" })] }) }), _jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setShowAgentScratch((value) => !value), "aria-label": showAgentScratch
|
|
700
811
|
? "Hide agent scratch files"
|
|
701
812
|
: "Show agent scratch files", className: cn("flex h-6 w-6 items-center justify-center rounded-md text-muted-foreground hover:text-foreground hover:bg-accent/50", showAgentScratch && "bg-accent/50 text-foreground"), children: _jsx(IconEye, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: showAgentScratch
|
|
702
813
|
? "Hide agent scratch files"
|
|
@@ -724,6 +835,11 @@ export function ResourcesPanel() {
|
|
|
724
835
|
? deleteResource.variables
|
|
725
836
|
: deleteMcpServer.isPending
|
|
726
837
|
? `mcp:${deleteMcpServer.variables.scope}:${deleteMcpServer.variables.id}`
|
|
727
|
-
: null, selectedId: selectedResourceId, onSelect: handleSelect, onCreateFile: (parentPath, name) => handleCreateFile(parentPath, name, "personal"), onCreateFolder: (parentPath, name) => handleCreateFolder(parentPath, name, "personal"), onDelete: handleDelete, onRename: handleRename, onDrop: handleUploadFiles, title: "Personal", titleTooltip: "Files visible only to you" })] })) })]
|
|
838
|
+
: null, selectedId: selectedResourceId, onSelect: handleSelect, onCreateFile: (parentPath, name) => handleCreateFile(parentPath, name, "personal"), onCreateFolder: (parentPath, name) => handleCreateFolder(parentPath, name, "personal"), onDelete: handleDelete, onRename: handleRename, onDrop: handleUploadFiles, title: "Personal", titleTooltip: "Files visible only to you" })] })) }), toast && (_jsx("div", { className: "pointer-events-none absolute bottom-3 left-1/2 z-[300] -translate-x-1/2", children: _jsxs("div", { role: "status", className: cn("pointer-events-auto flex max-w-[320px] items-center gap-3 rounded-md border px-3 py-2 text-[12px] shadow-md", toast.kind === "ok"
|
|
839
|
+
? "border-emerald-500/40 bg-emerald-500/10 text-emerald-600 dark:text-emerald-300"
|
|
840
|
+
: "border-red-500/40 bg-red-500/10 text-red-600 dark:text-red-300"), children: [_jsx("span", { className: "min-w-0 flex-1 truncate", children: toast.message }), toast.kind === "ok" && toast.resourceId && (_jsx("button", { type: "button", onClick: () => {
|
|
841
|
+
setSelectedResourceId(toast.resourceId);
|
|
842
|
+
setToast(null);
|
|
843
|
+
}, className: "shrink-0 rounded px-1.5 py-0.5 text-[11px] font-medium underline-offset-2 hover:underline", children: "View" })), _jsx("button", { type: "button", "aria-label": "Dismiss", onClick: () => setToast(null), className: "shrink-0 text-current/60 hover:text-current", children: "\u00D7" })] }) }))] }));
|
|
728
844
|
}
|
|
729
845
|
//# sourceMappingURL=ResourcesPanel.js.map
|