@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.
@@ -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: () => setView("skill"),
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: [_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"
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) => (_jsxs("button", { onClick: item.action, 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: item.icon }), _jsxs("div", { className: "min-w-0", 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 })] })] }, item.label))) })), 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) => {
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