@agent-native/dispatch 0.25.1 → 0.26.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.
Files changed (29) hide show
  1. package/dist/actions/provider-api-register.d.ts +11 -11
  2. package/dist/components/create-app-popover.d.ts +7 -2
  3. package/dist/components/create-app-popover.d.ts.map +1 -1
  4. package/dist/components/create-app-popover.js +4 -3
  5. package/dist/components/create-app-popover.js.map +1 -1
  6. package/dist/components/index.d.ts +1 -0
  7. package/dist/components/index.d.ts.map +1 -1
  8. package/dist/components/index.js +1 -0
  9. package/dist/components/index.js.map +1 -1
  10. package/dist/components/layout/Layout.d.ts.map +1 -1
  11. package/dist/components/layout/Layout.js +42 -2
  12. package/dist/components/layout/Layout.js.map +1 -1
  13. package/dist/components/simple-agents-panel.d.ts +4 -1
  14. package/dist/components/simple-agents-panel.d.ts.map +1 -1
  15. package/dist/components/simple-agents-panel.js +46 -13
  16. package/dist/components/simple-agents-panel.js.map +1 -1
  17. package/dist/components/workspace-app-host.d.ts +3 -1
  18. package/dist/components/workspace-app-host.d.ts.map +1 -1
  19. package/dist/components/workspace-app-host.js +11 -2
  20. package/dist/components/workspace-app-host.js.map +1 -1
  21. package/package.json +3 -3
  22. package/src/components/create-app-popover.spec.tsx +9 -1
  23. package/src/components/create-app-popover.tsx +9 -1
  24. package/src/components/index.ts +1 -0
  25. package/src/components/layout/Layout.app-chat.spec.ts +22 -0
  26. package/src/components/layout/Layout.tsx +72 -3
  27. package/src/components/simple-agents-panel.spec.tsx +81 -1
  28. package/src/components/simple-agents-panel.tsx +156 -71
  29. package/src/components/workspace-app-host.tsx +30 -1
@@ -1,3 +1,4 @@
1
+ import { type ReactNode } from "react";
1
2
  export declare function isPendingWorkspaceResourceApproval(result: unknown): boolean;
2
3
  export declare function handleAgentPackMutationSuccess(result: unknown, options: {
3
4
  appliedMessage: string;
@@ -5,5 +6,7 @@ export declare function handleAgentPackMutationSuccess(result: unknown, options:
5
6
  onApplied: () => void;
6
7
  notify?: (message: string) => void;
7
8
  }): void;
8
- export declare function SimpleAgentsPanel(): import("node_modules/@types/react/index.js").JSX.Element;
9
+ export declare function SimpleAgentsPanel({ title, }?: {
10
+ title?: ReactNode;
11
+ }): import("node_modules/@types/react/index.js").JSX.Element;
9
12
  //# sourceMappingURL=simple-agents-panel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"simple-agents-panel.d.ts","sourceRoot":"","sources":["../../src/components/simple-agents-panel.tsx"],"names":[],"mappings":"AAuGA,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,OAAO,WAQjE;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,OAAO,EACf,OAAO,EAAE;IACP,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,QASF;AAygCD,wBAAgB,iBAAiB,6DA+DhC"}
1
+ {"version":3,"file":"simple-agents-panel.d.ts","sourceRoot":"","sources":["../../src/components/simple-agents-panel.tsx"],"names":[],"mappings":"AAuBA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAqGf,wBAAgB,kCAAkC,CAAC,MAAM,EAAE,OAAO,WAQjE;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,OAAO,EACf,OAAO,EAAE;IACP,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACpC,QASF;AAkjCD,wBAAgB,iBAAiB,CAAC,EAChC,KAAK,GACN,GAAE;IACD,KAAK,CAAC,EAAE,SAAS,CAAC;CACd,4DA4EL"}
@@ -2,23 +2,42 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { navigateWithAgentChatViewTransition, sendToAgentChat, } from "@agent-native/core/client/agent-chat";
3
3
  import { useActionMutation, useActionQuery, } from "@agent-native/core/client/hooks";
4
4
  import { parseCustomAgentProfile } from "@agent-native/core/resources/metadata";
5
- import { IconAdjustmentsHorizontal, IconChevronDown, IconEdit, IconFileImport, IconFolder, IconLayoutGrid, IconMessageCircle, IconPlugConnected, IconPlus, IconTrash, IconUpload, IconUser, } from "@tabler/icons-react";
5
+ import { IconAdjustmentsHorizontal, IconChevronDown, IconDotsVertical, IconEdit, IconFileImport, IconFolder, IconLayoutGrid, IconMessageCircle, IconPlugConnected, IconPlus, IconTrash, IconUpload, } from "@tabler/icons-react";
6
6
  import { useEffect, useRef, useState, } from "react";
7
7
  import { useNavigate } from "react-router";
8
8
  import { toast } from "sonner";
9
9
  import { buildSimpleAgentContent, slugifyAgentName, } from "../lib/simple-agent-profile.js";
10
10
  import { ActionQueryError } from "./action-query-error.js";
11
+ import { AppIcon } from "./app-icon.js";
11
12
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "./ui/alert-dialog.js";
12
13
  import { Badge } from "./ui/badge.js";
13
14
  import { Button } from "./ui/button.js";
14
15
  import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "./ui/collapsible.js";
15
16
  import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from "./ui/dialog.js";
17
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from "./ui/dropdown-menu.js";
16
18
  import { Input } from "./ui/input.js";
17
19
  import { Label } from "./ui/label.js";
18
20
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "./ui/select.js";
19
21
  import { Skeleton } from "./ui/skeleton.js";
20
22
  import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs.js";
21
23
  import { Textarea } from "./ui/textarea.js";
24
+ const AGENT_ICON_KEYS = [
25
+ "brain",
26
+ "users",
27
+ "filetext",
28
+ "chartbar",
29
+ "route",
30
+ "listcheck",
31
+ "code",
32
+ "messagecircle",
33
+ ];
34
+ function agentIconKey(resource) {
35
+ let hash = 0;
36
+ for (const character of `${resource.id}:${resource.name}`) {
37
+ hash = (hash * 31 + character.charCodeAt(0)) | 0;
38
+ }
39
+ return AGENT_ICON_KEYS[Math.abs(hash) % AGENT_ICON_KEYS.length];
40
+ }
22
41
  export function isPendingWorkspaceResourceApproval(result) {
23
42
  if (!result || typeof result !== "object")
24
43
  return false;
@@ -57,9 +76,11 @@ function profileFields(resource) {
57
76
  scope: resource.scope,
58
77
  };
59
78
  }
60
- function AgentEditorDialog({ resource, trigger, onSaved }) {
79
+ function AgentEditorDialog({ resource, trigger, onSaved, open: controlledOpen, onOpenChange: controlledOnOpenChange, }) {
61
80
  const isEditing = Boolean(resource);
62
- const [open, setOpen] = useState(false);
81
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
82
+ const open = controlledOpen ?? uncontrolledOpen;
83
+ const setOpen = controlledOnOpenChange ?? setUncontrolledOpen;
63
84
  const [name, setName] = useState("");
64
85
  const [description, setDescription] = useState("");
65
86
  const [instructions, setInstructions] = useState("");
@@ -124,7 +145,7 @@ function AgentEditorDialog({ resource, trigger, onSaved }) {
124
145
  scope,
125
146
  });
126
147
  }
127
- return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [_jsx(DialogTrigger, { asChild: true, children: trigger || (_jsxs(Button, { children: [_jsx(IconPlus, { size: 16 }), "Create agent"] })) }), _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: isEditing ? "Manage agent" : "Create agent" }), _jsx(DialogDescription, { className: "sr-only", children: isEditing
148
+ return (_jsxs(Dialog, { open: open, onOpenChange: setOpen, children: [trigger ? (_jsx(DialogTrigger, { asChild: true, children: trigger })) : controlledOpen === undefined ? (_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { size: "sm", children: [_jsx(IconPlus, { size: 16 }), "Create agent"] }) })) : null, _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: isEditing ? "Manage agent" : "Create agent" }), _jsx(DialogDescription, { className: "sr-only", children: isEditing
128
149
  ? "Update this reusable agent profile."
129
150
  : "Create a reusable agent profile." })] }), _jsxs("div", { className: "flex flex-col gap-4 py-2", children: [_jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "simple-agent-name", children: "Name" }), _jsx(Input, { id: "simple-agent-name", value: name, onChange: (event) => setName(event.target.value), placeholder: "User Research" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "simple-agent-scope", children: "Availability" }), _jsxs(Select, { value: scope, onValueChange: (value) => setScope(value), children: [_jsx(SelectTrigger, { id: "simple-agent-scope", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All apps" }), _jsx(SelectItem, { value: "selected", children: "Selected apps" })] })] })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "simple-agent-description", children: "Description" }), _jsx(Input, { id: "simple-agent-description", value: description, onChange: (event) => setDescription(event.target.value), placeholder: "Synthesizes user research into clear insights" })] }), _jsxs(Collapsible, { open: advancedOpen, onOpenChange: setAdvancedOpen, children: [_jsx(CollapsibleTrigger, { asChild: true, children: _jsxs(Button, { type: "button", variant: "ghost", size: "sm", className: "group -ml-2 gap-1.5 text-muted-foreground", children: [_jsx(IconAdjustmentsHorizontal, { size: 15 }), "Advanced", _jsx(IconChevronDown, { className: "transition-transform group-data-[state=open]:rotate-180", size: 15 })] }) }), _jsx(CollapsibleContent, { className: "pt-3", children: _jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "simple-agent-model", children: "Model" }), _jsx(Input, { id: "simple-agent-model", value: model, onChange: (event) => setModel(event.target.value), placeholder: "inherit" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "simple-agent-tools", children: "Tools" }), _jsx(Input, { id: "simple-agent-tools", value: tools, onChange: (event) => setTools(event.target.value), placeholder: "inherit" })] })] }) })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "simple-agent-instructions", children: "Instructions" }), _jsx(Textarea, { id: "simple-agent-instructions", value: instructions, onChange: (event) => setInstructions(event.target.value), rows: 12, className: "font-mono text-sm", placeholder: "# Role\\n\\nDescribe how this agent should work." })] })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: save, disabled: !canSave, children: pending
130
151
  ? "Saving..."
@@ -132,8 +153,10 @@ function AgentEditorDialog({ resource, trigger, onSaved }) {
132
153
  ? "Save changes"
133
154
  : "Create agent" }) })] })] }));
134
155
  }
135
- function AgentPackDialog({ resource, onChanged, trigger, }) {
136
- const [open, setOpen] = useState(false);
156
+ function AgentPackDialog({ resource, onChanged, trigger, open: controlledOpen, onOpenChange: controlledOnOpenChange, }) {
157
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
158
+ const open = controlledOpen ?? uncontrolledOpen;
159
+ const setOpen = controlledOnOpenChange ?? setUncontrolledOpen;
137
160
  const [selectedId, setSelectedId] = useState(resource.id);
138
161
  const [content, setContent] = useState(resource.content);
139
162
  const [addOpen, setAddOpen] = useState(false);
@@ -219,7 +242,7 @@ function AgentPackDialog({ resource, onChanged, trigger, }) {
219
242
  setOpen(nextOpen);
220
243
  if (!nextOpen)
221
244
  setAddOpen(false);
222
- }, children: [_jsx(DialogTrigger, { asChild: true, children: trigger || (_jsxs(Button, { variant: "ghost", size: "sm", children: [_jsx(IconFolder, { size: 15 }), "Pack"] })) }), _jsxs(DialogContent, { className: "max-w-4xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Agent pack" }), _jsx(DialogDescription, { className: "sr-only", children: "Edit the profile, reference files, context, and skills that belong to this agent." })] }), _jsxs("div", { className: "grid min-h-0 gap-4 md:grid-cols-[220px_minmax(0,1fr)]", children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Files" }), _jsxs(Dialog, { open: addOpen, onOpenChange: setAddOpen, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(IconPlus, { size: 14 }), "Add"] }) }), _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Add pack file" }), _jsx(DialogDescription, { className: "sr-only", children: "Add a text reference or agent-owned skill to this pack." })] }), _jsxs("div", { className: "flex flex-col gap-4 py-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "agent-pack-file-path", children: "Path" }), _jsx(Input, { id: "agent-pack-file-path", value: newPath, onChange: (event) => setNewPath(event.target.value), placeholder: "context/brief.md" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "agent-pack-file-kind", children: "Type" }), _jsxs(Select, { value: newKind, onValueChange: (value) => setNewKind(value), children: [_jsx(SelectTrigger, { id: "agent-pack-file-kind", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "agent-file", children: "Reference file" }), _jsx(SelectItem, { value: "skill", children: "Skill" })] })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "agent-pack-file-content", children: "Content" }), _jsx(Textarea, { id: "agent-pack-file-content", value: newContent, onChange: (event) => setNewContent(event.target.value), rows: 8, className: "font-mono text-sm" })] })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: addFile, disabled: !newPath.trim() || create.isPending, children: create.isPending ? "Adding..." : "Add file" }) })] })] })] }), query.isLoading ? (_jsx(Skeleton, { className: "h-24 w-full" })) : (_jsx("div", { className: "flex flex-col gap-1", children: files.map((file) => (_jsx(Button, { type: "button", variant: selected?.id === file.id ? "secondary" : "ghost", className: "h-auto w-full justify-start px-2 py-2 text-left", onClick: () => setSelectedId(file.id), children: _jsx("span", { className: "min-w-0 truncate text-xs", children: file.path.replace(`${query.data?.root || ""}/`, "") }) }, file.id))) }))] }), _jsxs("div", { className: "flex min-w-0 flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-medium", children: selected?.path || "Select a file" }), selected && selected.kind !== "agent" ? (_jsx(Badge, { variant: "outline", children: selected.kind === "skill" ? "Skill" : "Reference" })) : null] }), _jsxs("div", { className: "flex items-center gap-1", children: [selected && selected.kind !== "agent" ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", children: [_jsx(IconTrash, { size: 15 }), "Remove"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Remove this pack file?" }), _jsx(AlertDialogDescription, { children: "The file will no longer be available to this agent." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => remove.mutate({ id: selected.id }), disabled: remove.isPending, children: "Remove" })] })] })] })) : null, _jsx(Button, { size: "sm", onClick: () => selected && update.mutate({ id: selected.id, content }), disabled: !selected ||
245
+ }, children: [trigger ? (_jsx(DialogTrigger, { asChild: true, children: trigger })) : controlledOpen === undefined ? (_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", children: [_jsx(IconFolder, { size: 15 }), "Pack"] }) })) : null, _jsxs(DialogContent, { className: "max-w-4xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Agent pack" }), _jsx(DialogDescription, { className: "sr-only", children: "Edit the profile, reference files, context, and skills that belong to this agent." })] }), _jsxs("div", { className: "grid min-h-0 gap-4 md:grid-cols-[220px_minmax(0,1fr)]", children: [_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Files" }), _jsxs(Dialog, { open: addOpen, onOpenChange: setAddOpen, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(IconPlus, { size: 14 }), "Add"] }) }), _jsxs(DialogContent, { children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Add pack file" }), _jsx(DialogDescription, { className: "sr-only", children: "Add a text reference or agent-owned skill to this pack." })] }), _jsxs("div", { className: "flex flex-col gap-4 py-2", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "agent-pack-file-path", children: "Path" }), _jsx(Input, { id: "agent-pack-file-path", value: newPath, onChange: (event) => setNewPath(event.target.value), placeholder: "context/brief.md" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "agent-pack-file-kind", children: "Type" }), _jsxs(Select, { value: newKind, onValueChange: (value) => setNewKind(value), children: [_jsx(SelectTrigger, { id: "agent-pack-file-kind", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "agent-file", children: "Reference file" }), _jsx(SelectItem, { value: "skill", children: "Skill" })] })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "agent-pack-file-content", children: "Content" }), _jsx(Textarea, { id: "agent-pack-file-content", value: newContent, onChange: (event) => setNewContent(event.target.value), rows: 8, className: "font-mono text-sm" })] })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: addFile, disabled: !newPath.trim() || create.isPending, children: create.isPending ? "Adding..." : "Add file" }) })] })] })] }), query.isLoading ? (_jsx(Skeleton, { className: "h-24 w-full" })) : (_jsx("div", { className: "flex flex-col gap-1", children: files.map((file) => (_jsx(Button, { type: "button", variant: selected?.id === file.id ? "secondary" : "ghost", className: "h-auto w-full justify-start px-2 py-2 text-left", onClick: () => setSelectedId(file.id), children: _jsx("span", { className: "min-w-0 truncate text-xs", children: file.path.replace(`${query.data?.root || ""}/`, "") }) }, file.id))) }))] }), _jsxs("div", { className: "flex min-w-0 flex-col gap-3", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate text-sm font-medium", children: selected?.path || "Select a file" }), selected && selected.kind !== "agent" ? (_jsx(Badge, { variant: "outline", children: selected.kind === "skill" ? "Skill" : "Reference" })) : null] }), _jsxs("div", { className: "flex items-center gap-1", children: [selected && selected.kind !== "agent" ? (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "ghost", size: "sm", children: [_jsx(IconTrash, { size: 15 }), "Remove"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Remove this pack file?" }), _jsx(AlertDialogDescription, { children: "The file will no longer be available to this agent." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => remove.mutate({ id: selected.id }), disabled: remove.isPending, children: "Remove" })] })] })] })) : null, _jsx(Button, { size: "sm", onClick: () => selected && update.mutate({ id: selected.id, content }), disabled: !selected ||
223
246
  update.isPending ||
224
247
  content === selected.content, children: update.isPending ? "Saving..." : "Save file" })] })] }), _jsx(Textarea, { value: content, onChange: (event) => setContent(event.target.value), disabled: !selected, rows: 18, className: "min-h-[360px] font-mono text-sm" })] })] })] })] }));
225
248
  }
@@ -321,7 +344,7 @@ function ImportAgentDialog({ onImported }) {
321
344
  setOpen(nextOpen);
322
345
  if (!nextOpen)
323
346
  reset();
324
- }, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", children: [_jsx(IconFileImport, { size: 16 }), "Import or connect"] }) }), _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Import an agent" }), _jsx(DialogDescription, { className: "sr-only", children: "Import a Claude or JSON agent definition, or connect an external agent endpoint." })] }), _jsxs(Tabs, { value: mode, onValueChange: (value) => setMode(value), children: [_jsxs(TabsList, { className: "w-full justify-start", children: [_jsx(TabsTrigger, { value: "file", children: "Agent file" }), _jsx(TabsTrigger, { value: "folder", children: "Agent folder" }), _jsx(TabsTrigger, { value: "endpoint", children: "Connect endpoint" })] }), _jsxs(TabsContent, { value: "file", className: "flex flex-col gap-4 py-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs(Button, { type: "button", variant: "outline", onClick: () => fileRef.current?.click(), children: [_jsx(IconUpload, { size: 16 }), "Choose file"] }), _jsx("input", { ref: fileRef, type: "file", accept: ".md,.markdown,.json,.txt", className: "hidden", onChange: (event) => void handleFile(event) }), _jsx("span", { className: "text-xs text-muted-foreground", children: fileName || "Claude .md or JSON agent definition" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "import-agent-source", children: "Definition" }), _jsx(Textarea, { id: "import-agent-source", value: source, onChange: (event) => setSource(event.target.value), rows: 12, className: "font-mono text-sm", placeholder: "Paste a Claude-style agent file or a JSON definition" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "import-agent-scope", children: "Availability" }), _jsxs(Select, { value: scope, onValueChange: (value) => setScope(value), children: [_jsx(SelectTrigger, { id: "import-agent-scope", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All apps" }), _jsx(SelectItem, { value: "selected", children: "Selected apps" })] })] })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: () => importAgent.mutate({
347
+ }, children: [_jsx(DialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", children: [_jsx(IconFileImport, { size: 16 }), "Import or connect"] }) }), _jsxs(DialogContent, { className: "max-w-2xl", children: [_jsxs(DialogHeader, { children: [_jsx(DialogTitle, { children: "Import an agent" }), _jsx(DialogDescription, { className: "sr-only", children: "Import a Claude or JSON agent definition, or connect an external agent endpoint." })] }), _jsxs(Tabs, { value: mode, onValueChange: (value) => setMode(value), children: [_jsxs(TabsList, { className: "w-full justify-start", children: [_jsx(TabsTrigger, { value: "file", children: "Agent file" }), _jsx(TabsTrigger, { value: "folder", children: "Agent folder" }), _jsx(TabsTrigger, { value: "endpoint", children: "Connect endpoint" })] }), _jsxs(TabsContent, { value: "file", className: "flex flex-col gap-4 py-4", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [_jsxs(Button, { type: "button", variant: "outline", onClick: () => fileRef.current?.click(), children: [_jsx(IconUpload, { size: 16 }), "Choose file"] }), _jsx("input", { ref: fileRef, type: "file", accept: ".md,.markdown,.json,.txt", className: "hidden", onChange: (event) => void handleFile(event) }), _jsx("span", { className: "text-xs text-muted-foreground", children: fileName || "Claude .md or JSON agent definition" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "import-agent-source", children: "Definition" }), _jsx(Textarea, { id: "import-agent-source", value: source, onChange: (event) => setSource(event.target.value), rows: 12, className: "font-mono text-sm", placeholder: "Paste a Claude-style agent file or a JSON definition" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { htmlFor: "import-agent-scope", children: "Availability" }), _jsxs(Select, { value: scope, onValueChange: (value) => setScope(value), children: [_jsx(SelectTrigger, { id: "import-agent-scope", children: _jsx(SelectValue, {}) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "all", children: "All apps" }), _jsx(SelectItem, { value: "selected", children: "Selected apps" })] })] })] }), _jsx(DialogFooter, { children: _jsx(Button, { onClick: () => importAgent.mutate({
325
348
  source,
326
349
  fileName: fileName || undefined,
327
350
  scope,
@@ -334,7 +357,10 @@ function ImportAgentDialog({ onImported }) {
334
357
  scope: "shared",
335
358
  }), disabled: !url.trim() || connect.isPending, children: [_jsx(IconPlugConnected, { size: 16 }), connect.isPending ? "Connecting..." : "Connect agent"] }) })] })] })] })] }));
336
359
  }
337
- function DeleteAgentButton({ resource, onDeleted, }) {
360
+ function DeleteAgentButton({ resource, onDeleted, open: controlledOpen, onOpenChange: controlledOnOpenChange, }) {
361
+ const [uncontrolledOpen, setUncontrolledOpen] = useState(false);
362
+ const open = controlledOpen ?? uncontrolledOpen;
363
+ const setOpen = controlledOnOpenChange ?? setUncontrolledOpen;
338
364
  const remove = useActionMutation("delete-workspace-resource", {
339
365
  onSuccess: () => {
340
366
  toast.success("Agent removed");
@@ -342,10 +368,13 @@ function DeleteAgentButton({ resource, onDeleted, }) {
342
368
  },
343
369
  onError: (error) => toast.error(error.message),
344
370
  });
345
- return (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": `Remove ${resource.name}`, children: _jsx(IconTrash, { size: 16 }) }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsxs(AlertDialogTitle, { children: ["Remove ", resource.name, "?"] }), _jsx(AlertDialogDescription, { children: "This removes the reusable profile from the workspace apps." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => remove.mutate({ id: resource.id }), disabled: remove.isPending, children: "Remove" })] })] })] }));
371
+ return (_jsx(AlertDialog, { open: open, onOpenChange: setOpen, children: _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsxs(AlertDialogTitle, { children: ["Remove ", resource.name, "?"] }), _jsx(AlertDialogDescription, { children: "This removes the reusable profile from the workspace apps." })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => remove.mutate({ id: resource.id }), disabled: remove.isPending, children: "Remove" })] })] }) }));
346
372
  }
347
373
  function AgentRow({ resource, onDeleted, onSaved, }) {
348
374
  const navigate = useNavigate();
375
+ const [packOpen, setPackOpen] = useState(false);
376
+ const [editorOpen, setEditorOpen] = useState(false);
377
+ const [deleteOpen, setDeleteOpen] = useState(false);
349
378
  const packQuery = useActionQuery("list-agent-pack", { agentId: resource.id }, { enabled: false });
350
379
  const promote = useActionMutation("start-workspace-app-creation", {
351
380
  onSuccess: (result) => {
@@ -392,14 +421,18 @@ function AgentRow({ resource, onDeleted, onSaved, }) {
392
421
  resourceIds: [resource.id, ...pack.data.files.map((file) => file.id)],
393
422
  });
394
423
  }
395
- return (_jsxs("div", { className: "flex items-start gap-3 rounded-xl border bg-card px-4 py-3", children: [_jsx("div", { className: "flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary", children: _jsx(IconUser, { size: 18 }) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: resource.name }), _jsx(Badge, { variant: "outline", children: resource.scope === "all" ? "All apps" : "Selected apps" })] }), resource.description ? (_jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: resource.description })) : null, _jsx("div", { className: "mt-1 font-mono text-[11px] text-muted-foreground/70", children: resource.path })] }), _jsxs("div", { className: "flex shrink-0 flex-wrap items-center justify-end gap-1", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: chat, "aria-label": `Chat with ${resource.name}`, children: [_jsx(IconMessageCircle, { size: 15 }), "Chat"] }), _jsxs(Button, { variant: "ghost", size: "sm", onClick: () => void buildApp(), disabled: promote.isPending, "aria-label": `Build an app for ${resource.name}`, children: [_jsx(IconLayoutGrid, { size: 15 }), promote.isPending ? "Starting..." : "Build app"] }), _jsx(AgentPackDialog, { resource: resource, onChanged: onSaved, trigger: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": `Manage files for ${resource.name}`, children: _jsx(IconFolder, { size: 16 }) }) }), _jsx(AgentEditorDialog, { resource: resource, onSaved: onSaved, trigger: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": `Edit ${resource.name}`, children: _jsx(IconEdit, { size: 16 }) }) }), _jsx(DeleteAgentButton, { resource: resource, onDeleted: onDeleted })] })] }));
424
+ return (_jsxs("div", { className: "flex min-w-0 items-start gap-3 rounded-2xl border bg-card px-4 py-4", children: [_jsx(AppIcon, { id: resource.id, name: resource.name, icon: agentIconKey(resource), size: "sm" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-sm font-medium text-foreground", children: resource.name }), _jsx(Badge, { variant: "outline", children: resource.scope === "all" ? "All apps" : "Selected apps" })] }), resource.description ? (_jsx("div", { className: "mt-1 text-sm text-muted-foreground", children: resource.description })) : null] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: chat, "aria-label": `Chat with ${resource.name}`, children: [_jsx(IconMessageCircle, { size: 15 }), "Chat"] }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", "aria-label": `More actions for ${resource.name}`, title: "More actions", children: _jsx(IconDotsVertical, { size: 16 }) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-48", children: [_jsxs(DropdownMenuItem, { onSelect: () => {
425
+ void buildApp();
426
+ }, disabled: promote.isPending, children: [_jsx(IconLayoutGrid, { className: "me-2 size-4" }), promote.isPending ? "Starting..." : "Build app"] }), _jsxs(DropdownMenuItem, { onSelect: () => setPackOpen(true), children: [_jsx(IconFolder, { className: "me-2 size-4" }), "Manage files"] }), _jsxs(DropdownMenuItem, { onSelect: () => setEditorOpen(true), children: [_jsx(IconEdit, { className: "me-2 size-4" }), "Edit"] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { className: "text-destructive focus:text-destructive", onSelect: () => setDeleteOpen(true), children: [_jsx(IconTrash, { className: "me-2 size-4" }), "Remove"] })] })] }), _jsx(AgentPackDialog, { resource: resource, onChanged: onSaved, open: packOpen, onOpenChange: setPackOpen }), _jsx(AgentEditorDialog, { resource: resource, onSaved: onSaved, open: editorOpen, onOpenChange: setEditorOpen }), _jsx(DeleteAgentButton, { resource: resource, onDeleted: onDeleted, open: deleteOpen, onOpenChange: setDeleteOpen })] })] }));
396
427
  }
397
- export function SimpleAgentsPanel() {
428
+ export function SimpleAgentsPanel({ title, } = {}) {
398
429
  const query = useActionQuery("list-workspace-resources", { kind: "agent" });
399
430
  const agents = query.data ?? [];
431
+ const refreshAgents = () => void query.refetch();
432
+ const importAction = _jsx(ImportAgentDialog, { onImported: refreshAgents });
400
433
  if (query.isError) {
401
434
  return (_jsx(ActionQueryError, { error: query.error, onRetry: () => void query.refetch() }));
402
435
  }
403
- return (_jsxs("section", { className: "flex flex-col gap-4", children: [_jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [_jsx(ImportAgentDialog, { onImported: () => void query.refetch() }), _jsx(AgentEditorDialog, { onSaved: () => void query.refetch() })] }), query.isLoading && agents.length === 0 ? (_jsx("div", { className: "flex flex-col gap-3", children: [0, 1, 2].map((item) => (_jsxs("div", { className: "rounded-xl border bg-card px-4 py-3", children: [_jsx(Skeleton, { className: "h-4 w-1/3" }), _jsx(Skeleton, { className: "mt-2 h-3 w-2/3" })] }, item))) })) : agents.length > 0 ? (_jsx("div", { className: "flex flex-col gap-2", children: agents.map((agent) => (_jsx(AgentRow, { resource: agent, onDeleted: () => void query.refetch(), onSaved: () => void query.refetch() }, agent.id))) })) : (_jsxs("div", { className: "rounded-xl border border-dashed px-6 py-14 text-center", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "No agents yet" }), _jsxs("div", { className: "mt-4 flex flex-wrap justify-center gap-2", children: [_jsx(AgentEditorDialog, { onSaved: () => void query.refetch(), trigger: _jsxs(Button, { children: [_jsx(IconPlus, { size: 16 }), "Create an agent"] }) }), _jsx(ImportAgentDialog, { onImported: () => void query.refetch() })] })] }))] }));
436
+ return (_jsxs("section", { className: "flex flex-col gap-4", children: [title || agents.length > 0 ? (_jsxs("div", { className: `flex flex-wrap items-center gap-3 ${title ? "justify-between" : "justify-end"}`, children: [title ? (_jsx("h2", { className: "text-base font-medium text-foreground", children: title })) : null, agents.length > 0 ? (_jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [importAction, _jsx(AgentEditorDialog, { onSaved: refreshAgents })] })) : null] })) : null, query.isLoading && agents.length === 0 ? (_jsx("div", { className: "grid gap-3 md:grid-cols-2", children: [0, 1, 2].map((item) => (_jsxs("div", { className: "rounded-2xl border bg-card px-4 py-4", children: [_jsx(Skeleton, { className: "h-4 w-1/3" }), _jsx(Skeleton, { className: "mt-2 h-3 w-2/3" })] }, item))) })) : agents.length > 0 ? (_jsx("div", { className: "grid gap-3 md:grid-cols-2", children: agents.map((agent) => (_jsx(AgentRow, { resource: agent, onDeleted: () => void query.refetch(), onSaved: () => void query.refetch() }, agent.id))) })) : (_jsxs("div", { className: "rounded-2xl border border-dashed bg-card px-4 py-12 text-center", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "No agents yet" }), _jsxs("div", { className: "mt-4 flex flex-wrap justify-center gap-2", children: [_jsx(AgentEditorDialog, { onSaved: refreshAgents, trigger: _jsxs(Button, { size: "sm", children: [_jsx(IconPlus, { size: 16 }), "Create an agent"] }) }), importAction] })] }))] }));
404
437
  }
405
438
  //# sourceMappingURL=simple-agents-panel.js.map