@agent-native/core 0.12.18 → 0.12.20

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 (128) hide show
  1. package/dist/agent/default-model.d.ts +1 -20
  2. package/dist/agent/default-model.d.ts.map +1 -1
  3. package/dist/agent/default-model.js +1 -20
  4. package/dist/agent/default-model.js.map +1 -1
  5. package/dist/agent/engine/ai-sdk-engine.d.ts +2 -1
  6. package/dist/agent/engine/ai-sdk-engine.d.ts.map +1 -1
  7. package/dist/agent/engine/ai-sdk-engine.js +13 -38
  8. package/dist/agent/engine/ai-sdk-engine.js.map +1 -1
  9. package/dist/agent/engine/anthropic-engine.d.ts +1 -1
  10. package/dist/agent/engine/anthropic-engine.d.ts.map +1 -1
  11. package/dist/agent/engine/anthropic-engine.js +3 -11
  12. package/dist/agent/engine/anthropic-engine.js.map +1 -1
  13. package/dist/agent/engine/builder-engine.d.ts +2 -2
  14. package/dist/agent/engine/builder-engine.d.ts.map +1 -1
  15. package/dist/agent/engine/builder-engine.js +3 -21
  16. package/dist/agent/engine/builder-engine.js.map +1 -1
  17. package/dist/agent/model-config.d.ts +99 -0
  18. package/dist/agent/model-config.d.ts.map +1 -0
  19. package/dist/agent/model-config.js +112 -0
  20. package/dist/agent/model-config.js.map +1 -0
  21. package/dist/agent/production-agent.d.ts +1 -1
  22. package/dist/agent/production-agent.d.ts.map +1 -1
  23. package/dist/agent/production-agent.js +13 -1
  24. package/dist/agent/production-agent.js.map +1 -1
  25. package/dist/cli/create.d.ts +4 -1
  26. package/dist/cli/create.d.ts.map +1 -1
  27. package/dist/cli/create.js +19 -4
  28. package/dist/cli/create.js.map +1 -1
  29. package/dist/cli/index.js +1 -1
  30. package/dist/cli/index.js.map +1 -1
  31. package/dist/cli/workspace-dev.d.ts +3 -0
  32. package/dist/cli/workspace-dev.d.ts.map +1 -1
  33. package/dist/cli/workspace-dev.js +67 -27
  34. package/dist/cli/workspace-dev.js.map +1 -1
  35. package/dist/client/AgentPanel.d.ts +4 -0
  36. package/dist/client/AgentPanel.d.ts.map +1 -1
  37. package/dist/client/AgentPanel.js +34 -4
  38. package/dist/client/AgentPanel.js.map +1 -1
  39. package/dist/client/AssistantChat.d.ts +4 -0
  40. package/dist/client/AssistantChat.d.ts.map +1 -1
  41. package/dist/client/AssistantChat.js +10 -2
  42. package/dist/client/AssistantChat.js.map +1 -1
  43. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  44. package/dist/client/agent-chat-adapter.js +50 -8
  45. package/dist/client/agent-chat-adapter.js.map +1 -1
  46. package/dist/client/analytics.d.ts +4 -0
  47. package/dist/client/analytics.d.ts.map +1 -1
  48. package/dist/client/analytics.js +11 -2
  49. package/dist/client/analytics.js.map +1 -1
  50. package/dist/client/components/CodeRequiredDialog.d.ts.map +1 -1
  51. package/dist/client/components/CodeRequiredDialog.js +10 -9
  52. package/dist/client/components/CodeRequiredDialog.js.map +1 -1
  53. package/dist/client/composer/TiptapComposer.d.ts +5 -1
  54. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  55. package/dist/client/composer/TiptapComposer.js +19 -6
  56. package/dist/client/composer/TiptapComposer.js.map +1 -1
  57. package/dist/client/composer/pasted-text.d.ts.map +1 -1
  58. package/dist/client/composer/pasted-text.js +1 -1
  59. package/dist/client/composer/pasted-text.js.map +1 -1
  60. package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
  61. package/dist/client/resources/ResourcesPanel.js +5 -40
  62. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  63. package/dist/client/settings/AutomationsSection.d.ts.map +1 -1
  64. package/dist/client/settings/AutomationsSection.js +3 -30
  65. package/dist/client/settings/AutomationsSection.js.map +1 -1
  66. package/dist/client/terminal/AgentTerminal.d.ts.map +1 -1
  67. package/dist/client/terminal/AgentTerminal.js +44 -14
  68. package/dist/client/terminal/AgentTerminal.js.map +1 -1
  69. package/dist/client/use-chat-models.d.ts.map +1 -1
  70. package/dist/client/use-chat-models.js +41 -3
  71. package/dist/client/use-chat-models.js.map +1 -1
  72. package/dist/deploy/build.d.ts.map +1 -1
  73. package/dist/deploy/build.js +61 -6
  74. package/dist/deploy/build.js.map +1 -1
  75. package/dist/deploy/workspace-deploy.d.ts +1 -1
  76. package/dist/deploy/workspace-deploy.d.ts.map +1 -1
  77. package/dist/deploy/workspace-deploy.js +158 -7
  78. package/dist/deploy/workspace-deploy.js.map +1 -1
  79. package/dist/integrations/plugin.d.ts.map +1 -1
  80. package/dist/integrations/plugin.js +1 -2
  81. package/dist/integrations/plugin.js.map +1 -1
  82. package/dist/integrations/types.d.ts +1 -1
  83. package/dist/integrations/types.d.ts.map +1 -1
  84. package/dist/integrations/types.js.map +1 -1
  85. package/dist/integrations/webhook-handler.d.ts +2 -2
  86. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  87. package/dist/integrations/webhook-handler.js.map +1 -1
  88. package/dist/scripts/agent-engines/manage-agent-engine.js +1 -1
  89. package/dist/scripts/agent-engines/manage-agent-engine.js.map +1 -1
  90. package/dist/scripts/agent-engines/set-agent-engine.js +1 -1
  91. package/dist/scripts/agent-engines/set-agent-engine.js.map +1 -1
  92. package/dist/server/agent-chat-plugin.d.ts +1 -1
  93. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  94. package/dist/server/agent-chat-plugin.js +11 -7
  95. package/dist/server/agent-chat-plugin.js.map +1 -1
  96. package/dist/server/auth.d.ts +1 -0
  97. package/dist/server/auth.d.ts.map +1 -1
  98. package/dist/server/auth.js +49 -9
  99. package/dist/server/auth.js.map +1 -1
  100. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  101. package/dist/server/core-routes-plugin.js +4 -2
  102. package/dist/server/core-routes-plugin.js.map +1 -1
  103. package/dist/server/google-oauth.d.ts.map +1 -1
  104. package/dist/server/google-oauth.js +3 -9
  105. package/dist/server/google-oauth.js.map +1 -1
  106. package/dist/server/sentry-config.d.ts +5 -0
  107. package/dist/server/sentry-config.d.ts.map +1 -0
  108. package/dist/server/sentry-config.js +43 -0
  109. package/dist/server/sentry-config.js.map +1 -0
  110. package/dist/server/sentry-plugin.d.ts +1 -1
  111. package/dist/server/sentry-plugin.js +2 -2
  112. package/dist/server/sentry-plugin.js.map +1 -1
  113. package/dist/server/sentry.d.ts +4 -4
  114. package/dist/server/sentry.d.ts.map +1 -1
  115. package/dist/server/sentry.js +13 -13
  116. package/dist/server/sentry.js.map +1 -1
  117. package/dist/server/ssr-handler.d.ts.map +1 -1
  118. package/dist/server/ssr-handler.js +12 -2
  119. package/dist/server/ssr-handler.js.map +1 -1
  120. package/dist/templates/workspace-root/_gitignore +1 -0
  121. package/dist/usage/store.d.ts.map +1 -1
  122. package/dist/usage/store.js +5 -5
  123. package/dist/usage/store.js.map +1 -1
  124. package/docs/content/deployment.md +23 -3
  125. package/docs/content/multi-app-workspace.md +8 -2
  126. package/docs/content/observability.md +8 -8
  127. package/package.json +1 -1
  128. package/src/templates/workspace-root/_gitignore +1 -0
@@ -1,10 +1,11 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { agentNativePath } from "../api-path.js";
3
- import { useEffect, useState, useCallback, useRef } from "react";
3
+ import { useEffect, useState, useCallback } from "react";
4
4
  import { IconBolt, IconClock, IconLoader2, IconPlayerPlay, IconPlus, IconTrash, } from "@tabler/icons-react";
5
5
  import { sendToAgentChat } from "../agent-chat.js";
6
6
  import { PromptComposer } from "../composer/PromptComposer.js";
7
7
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
8
+ import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
8
9
  function flattenJobs(nodes) {
9
10
  const items = [];
10
11
  for (const node of nodes) {
@@ -141,34 +142,6 @@ export function AutomationsSection() {
141
142
  }, [showToast]);
142
143
  const [newOpen, setNewOpen] = useState(false);
143
144
  const [newScope, setNewScope] = useState("personal");
144
- const newPopoverRef = useRef(null);
145
- const newButtonRef = useRef(null);
146
- // Close popover on outside click
147
- useEffect(() => {
148
- if (!newOpen)
149
- return;
150
- function handleClick(e) {
151
- if (newPopoverRef.current &&
152
- !newPopoverRef.current.contains(e.target) &&
153
- newButtonRef.current &&
154
- !newButtonRef.current.contains(e.target)) {
155
- setNewOpen(false);
156
- }
157
- }
158
- document.addEventListener("mousedown", handleClick);
159
- return () => document.removeEventListener("mousedown", handleClick);
160
- }, [newOpen]);
161
- // Close popover on Escape
162
- useEffect(() => {
163
- if (!newOpen)
164
- return;
165
- function handleKey(e) {
166
- if (e.key === "Escape")
167
- setNewOpen(false);
168
- }
169
- document.addEventListener("keydown", handleKey);
170
- return () => document.removeEventListener("keydown", handleKey);
171
- }, [newOpen]);
172
145
  const handleNewSubmit = useCallback((text) => {
173
146
  const trimmed = text.trim();
174
147
  if (!trimmed)
@@ -190,7 +163,7 @@ export function AutomationsSection() {
190
163
  if (loading) {
191
164
  return (_jsxs("div", { className: "flex items-center gap-1.5 text-[10px] text-muted-foreground", children: [_jsx(IconLoader2, { size: 10, className: "animate-spin" }), "Loading..."] }));
192
165
  }
193
- return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs("div", { className: "relative", children: [_jsxs("button", { ref: newButtonRef, type: "button", onClick: () => setNewOpen(!newOpen), className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40", children: [_jsx(IconPlus, { size: 10 }), "New Automation"] }), newOpen && (_jsxs("div", { ref: newPopoverRef, className: "absolute left-0 top-full mt-1.5 z-[220] w-[380px] rounded-lg border border-border bg-popover p-3 shadow-lg", children: [_jsx("p", { className: "px-1 pb-2 text-sm font-semibold text-foreground", children: "New automation" }), _jsx(PromptComposer, { autoFocus: true, placeholder: "Describe what you want to automate...", draftScope: "automations:create", onSubmit: handleNewSubmit }), _jsx("div", { className: "mt-2", children: _jsxs("select", { value: newScope, onChange: (e) => setNewScope(e.target.value), className: "w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-[12px] text-foreground", children: [_jsx("option", { value: "personal", children: "Personal" }), _jsx("option", { value: "organization", children: "Organization" })] }) })] }))] }), _jsxs("button", { type: "button", onClick: handleFireTestEvent, className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40", children: [_jsx(IconPlayerPlay, { size: 10 }), "Fire Test Event"] })] }), automations.length === 0 ? (_jsx("p", { className: "text-[10px] text-muted-foreground", children: "No automations yet. Click \"New Automation\" to create one, or ask the agent to set up a scheduled or event-triggered task." })) : (automations.map((item) => (_jsxs("div", { className: "rounded-md border border-border px-2.5 py-2 bg-accent/30", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-muted-foreground shrink-0", children: item.schedule ? (_jsx(IconClock, { size: 11 })) : (_jsx(IconBolt, { size: 11 })) }), _jsx("span", { className: "text-[11px] font-medium text-foreground truncate capitalize", children: item.name })] }), item.scheduleDescription && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5 ml-[17px]", children: item.scheduleDescription })), item.schedule && !item.scheduleDescription && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5 ml-[17px] font-mono", children: item.schedule }))] }), _jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [_jsx(StatusBadge, { status: item.lastStatus }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => handleToggle(item), disabled: togglingId === item.id, className: `rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${item.enabled
166
+ return (_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsxs(Popover, { open: newOpen, onOpenChange: setNewOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40", children: [_jsx(IconPlus, { size: 10 }), "New Automation"] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 6, collisionPadding: 8, className: "z-[260] w-[calc(100vw-24px)] max-w-[380px] p-3", children: [_jsx("p", { className: "px-1 pb-2 text-sm font-semibold text-foreground", children: "New automation" }), _jsx(PromptComposer, { autoFocus: true, placeholder: "Describe what you want to automate...", draftScope: "automations:create", onSubmit: handleNewSubmit }), _jsx("div", { className: "mt-2", children: _jsxs("select", { value: newScope, onChange: (e) => setNewScope(e.target.value), className: "w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-[12px] text-foreground", children: [_jsx("option", { value: "personal", children: "Personal" }), _jsx("option", { value: "organization", children: "Organization" })] }) })] })] }), automations.length > 0 && (_jsxs("button", { type: "button", onClick: handleFireTestEvent, className: "inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40", children: [_jsx(IconPlayerPlay, { size: 10 }), "Fire Test Event"] }))] }), automations.length === 0 ? (_jsx("p", { className: "text-[10px] text-muted-foreground", children: "No automations yet. Click \"New Automation\" to create one, or ask the agent to set up a scheduled or event-triggered task." })) : (automations.map((item) => (_jsxs("div", { className: "rounded-md border border-border px-2.5 py-2 bg-accent/30", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-muted-foreground shrink-0", children: item.schedule ? (_jsx(IconClock, { size: 11 })) : (_jsx(IconBolt, { size: 11 })) }), _jsx("span", { className: "text-[11px] font-medium text-foreground truncate capitalize", children: item.name })] }), item.scheduleDescription && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5 ml-[17px]", children: item.scheduleDescription })), item.schedule && !item.scheduleDescription && (_jsx("p", { className: "text-[10px] text-muted-foreground mt-0.5 ml-[17px] font-mono", children: item.schedule }))] }), _jsxs("div", { className: "flex items-center gap-1.5 shrink-0", children: [_jsx(StatusBadge, { status: item.lastStatus }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => handleToggle(item), disabled: togglingId === item.id, className: `rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${item.enabled
194
167
  ? "bg-green-500/15 text-green-500"
195
168
  : "bg-accent/60 text-muted-foreground"} hover:opacity-80 disabled:opacity-40`, children: togglingId === item.id ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : item.enabled ? ("On") : ("Off") }) }), _jsx(TooltipContent, { children: item.enabled ? "Disable" : "Enable" })] }), confirmDeleteId === item.id ? (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", onClick: () => handleDelete(item), disabled: deletingId === item.id, className: "rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40", children: deletingId === item.id ? (_jsx(IconLoader2, { size: 10, className: "animate-spin" })) : ("Confirm") }), _jsx("button", { type: "button", onClick: () => setConfirmDeleteId(null), className: "rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground", children: "Cancel" })] })) : (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setConfirmDeleteId(item.id), className: "text-muted-foreground hover:text-red-500 disabled:opacity-40", children: _jsx(IconTrash, { size: 12 }) }) }), _jsx(TooltipContent, { children: "Delete" })] }))] })] }), item.lastRun && (_jsxs("p", { className: "text-[10px] text-muted-foreground mt-1 ml-[17px]", children: ["Last run:", " ", new Date(item.lastRun).toLocaleString(undefined, {
196
169
  month: "short",
@@ -1 +1 @@
1
- {"version":3,"file":"AutomationsSection.js","sourceRoot":"","sources":["../../../src/client/settings/AutomationsSection.tsx"],"names":[],"mappings":"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","sourcesContent":["import { agentNativePath } from \"../api-path.js\";\nimport React, { useEffect, useState, useCallback, useRef } from \"react\";\nimport {\n IconBolt,\n IconClock,\n IconLoader2,\n IconPlayerPlay,\n IconPlus,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { sendToAgentChat } from \"../agent-chat.js\";\nimport { PromptComposer } from \"../composer/PromptComposer.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\n\ninterface TreeNode {\n name: string;\n path: string;\n type: \"file\" | \"folder\";\n kind?: string;\n children?: TreeNode[];\n resource?: {\n id: string;\n path: string;\n owner: string;\n mimeType: string;\n size: number;\n createdAt: number;\n updatedAt: number;\n };\n jobMeta?: {\n schedule?: string;\n scheduleDescription?: string;\n enabled?: boolean;\n lastStatus?: string;\n lastRun?: string;\n nextRun?: string;\n };\n}\n\ninterface AutomationItem {\n id: string;\n name: string;\n path: string;\n schedule?: string;\n scheduleDescription?: string;\n enabled: boolean;\n lastStatus?: string;\n lastRun?: string;\n nextRun?: string;\n}\n\nfunction flattenJobs(nodes: TreeNode[]): AutomationItem[] {\n const items: AutomationItem[] = [];\n for (const node of nodes) {\n if (node.type === \"folder\" && node.children) {\n items.push(...flattenJobs(node.children));\n }\n if (\n node.type === \"file\" &&\n node.kind === \"job\" &&\n node.resource &&\n node.jobMeta\n ) {\n const name = node.name.replace(/\\.md$/, \"\").replace(/-/g, \" \");\n items.push({\n id: node.resource.id,\n name,\n path: node.resource.path,\n schedule: node.jobMeta.schedule,\n scheduleDescription: node.jobMeta.scheduleDescription,\n enabled: node.jobMeta.enabled ?? false,\n lastStatus: node.jobMeta.lastStatus,\n lastRun: node.jobMeta.lastRun,\n nextRun: node.jobMeta.nextRun,\n });\n }\n }\n return items;\n}\n\nexport function AutomationsSection() {\n const [automations, setAutomations] = useState<AutomationItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [togglingId, setTogglingId] = useState<string | null>(null);\n const [deletingId, setDeletingId] = useState<string | null>(null);\n const [confirmDeleteId, setConfirmDeleteId] = useState<string | null>(null);\n const [toast, setToast] = useState<{\n kind: \"ok\" | \"err\";\n text: string;\n } | null>(null);\n const [reloadToken, setReloadToken] = useState(0);\n\n const showToast = useCallback(\n (kind: \"ok\" | \"err\", text: string, ms = 2500) => {\n setToast({ kind, text });\n setTimeout(() => setToast(null), ms);\n },\n [],\n );\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n fetch(agentNativePath(\"/_agent-native/resources/tree\"))\n .then(async (r) => {\n if (!r.ok) throw new Error(`Failed to load (${r.status})`);\n return (await r.json()) as { tree: TreeNode[] };\n })\n .then(({ tree }) => {\n if (cancelled) return;\n const jobsFolder = tree.find(\n (n) => n.name === \"jobs\" && n.type === \"folder\",\n );\n const items = jobsFolder?.children\n ? flattenJobs(jobsFolder.children)\n : [];\n setAutomations(items);\n setLoading(false);\n })\n .catch((err) => {\n if (cancelled) return;\n setError(err?.message ?? \"Failed to load\");\n setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [reloadToken]);\n\n const reload = useCallback(() => setReloadToken((t) => t + 1), []);\n\n const handleToggle = useCallback(\n async (item: AutomationItem) => {\n setTogglingId(item.id);\n try {\n const res = await fetch(\n agentNativePath(\n `/_agent-native/resources/${encodeURIComponent(item.id)}`,\n ),\n );\n if (!res.ok) {\n showToast(\"err\", \"Failed to read automation\");\n return;\n }\n const resource = await res.json();\n const content: string = resource.content ?? \"\";\n\n const newEnabled = !item.enabled;\n const updated = content.replace(\n /^(enabled:\\s*)(true|false)/m,\n `$1${newEnabled}`,\n );\n\n const putRes = await fetch(\n agentNativePath(\n `/_agent-native/resources/${encodeURIComponent(item.id)}`,\n ),\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content: updated }),\n },\n );\n if (!putRes.ok) {\n showToast(\"err\", \"Failed to update automation\");\n return;\n }\n showToast(\"ok\", newEnabled ? \"Enabled\" : \"Disabled\");\n reload();\n } finally {\n setTogglingId(null);\n }\n },\n [reload, showToast],\n );\n\n const handleDelete = useCallback(\n async (item: AutomationItem) => {\n setDeletingId(item.id);\n try {\n const res = await fetch(\n agentNativePath(\n `/_agent-native/resources/${encodeURIComponent(item.id)}`,\n ),\n {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n if (!res.ok) {\n showToast(\"err\", \"Failed to delete automation\");\n return;\n }\n showToast(\"ok\", \"Deleted\");\n setConfirmDeleteId(null);\n reload();\n } finally {\n setDeletingId(null);\n }\n },\n [reload, showToast],\n );\n\n const handleFireTestEvent = useCallback(async () => {\n showToast(\"ok\", \"Firing test event...\");\n try {\n const res = await fetch(\n agentNativePath(\"/_agent-native/automations/fire-test\"),\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ data: {} }),\n },\n );\n if (!res.ok) {\n showToast(\"err\", `Failed to fire event (${res.status})`);\n return;\n }\n showToast(\"ok\", \"Event fired\");\n } catch (err: any) {\n showToast(\"err\", err?.message ?? \"Failed to fire event\");\n }\n }, [showToast]);\n\n const [newOpen, setNewOpen] = useState(false);\n const [newScope, setNewScope] = useState<\"personal\" | \"organization\">(\n \"personal\",\n );\n const newPopoverRef = useRef<HTMLDivElement>(null);\n const newButtonRef = useRef<HTMLButtonElement>(null);\n\n // Close popover on outside click\n useEffect(() => {\n if (!newOpen) return;\n function handleClick(e: MouseEvent) {\n if (\n newPopoverRef.current &&\n !newPopoverRef.current.contains(e.target as Node) &&\n newButtonRef.current &&\n !newButtonRef.current.contains(e.target as Node)\n ) {\n setNewOpen(false);\n }\n }\n document.addEventListener(\"mousedown\", handleClick);\n return () => document.removeEventListener(\"mousedown\", handleClick);\n }, [newOpen]);\n\n // Close popover on Escape\n useEffect(() => {\n if (!newOpen) return;\n function handleKey(e: KeyboardEvent) {\n if (e.key === \"Escape\") setNewOpen(false);\n }\n document.addEventListener(\"keydown\", handleKey);\n return () => document.removeEventListener(\"keydown\", handleKey);\n }, [newOpen]);\n\n const handleNewSubmit = useCallback(\n (text: string) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:set-mode\", {\n detail: { mode: \"chat\" },\n }),\n );\n sendToAgentChat({\n message: trimmed,\n context: `The user wants to create a new automation. Scope: ${newScope}. Use manage-automations with action=define to create it. Ask clarifying questions if needed about what event to trigger on, conditions, and what actions to take.`,\n submit: true,\n newTab: true,\n });\n setNewOpen(false);\n },\n [newScope],\n );\n\n if (error) {\n return (\n <p className=\"text-[10px] text-red-500\">\n Failed to load automations: {error}\n </p>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-1.5 text-[10px] text-muted-foreground\">\n <IconLoader2 size={10} className=\"animate-spin\" />\n Loading...\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5\">\n <div className=\"relative\">\n <button\n ref={newButtonRef}\n type=\"button\"\n onClick={() => setNewOpen(!newOpen)}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40\"\n >\n <IconPlus size={10} />\n New Automation\n </button>\n {newOpen && (\n <div\n ref={newPopoverRef}\n className=\"absolute left-0 top-full mt-1.5 z-[220] w-[380px] rounded-lg border border-border bg-popover p-3 shadow-lg\"\n >\n <p className=\"px-1 pb-2 text-sm font-semibold text-foreground\">\n New automation\n </p>\n <PromptComposer\n autoFocus\n placeholder=\"Describe what you want to automate...\"\n draftScope=\"automations:create\"\n onSubmit={handleNewSubmit}\n />\n <div className=\"mt-2\">\n <select\n value={newScope}\n onChange={(e) =>\n setNewScope(e.target.value as \"personal\" | \"organization\")\n }\n className=\"w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-[12px] text-foreground\"\n >\n <option value=\"personal\">Personal</option>\n <option value=\"organization\">Organization</option>\n </select>\n </div>\n </div>\n )}\n </div>\n <button\n type=\"button\"\n onClick={handleFireTestEvent}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40\"\n >\n <IconPlayerPlay size={10} />\n Fire Test Event\n </button>\n </div>\n\n {automations.length === 0 ? (\n <p className=\"text-[10px] text-muted-foreground\">\n No automations yet. Click \"New Automation\" to create one, or ask the\n agent to set up a scheduled or event-triggered task.\n </p>\n ) : (\n automations.map((item) => (\n <div\n key={item.id}\n className=\"rounded-md border border-border px-2.5 py-2 bg-accent/30\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-muted-foreground shrink-0\">\n {item.schedule ? (\n <IconClock size={11} />\n ) : (\n <IconBolt size={11} />\n )}\n </span>\n <span className=\"text-[11px] font-medium text-foreground truncate capitalize\">\n {item.name}\n </span>\n </div>\n {item.scheduleDescription && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5 ml-[17px]\">\n {item.scheduleDescription}\n </p>\n )}\n {item.schedule && !item.scheduleDescription && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5 ml-[17px] font-mono\">\n {item.schedule}\n </p>\n )}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <StatusBadge status={item.lastStatus} />\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => handleToggle(item)}\n disabled={togglingId === item.id}\n className={`rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${\n item.enabled\n ? \"bg-green-500/15 text-green-500\"\n : \"bg-accent/60 text-muted-foreground\"\n } hover:opacity-80 disabled:opacity-40`}\n >\n {togglingId === item.id ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : item.enabled ? (\n \"On\"\n ) : (\n \"Off\"\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {item.enabled ? \"Disable\" : \"Enable\"}\n </TooltipContent>\n </Tooltip>\n {confirmDeleteId === item.id ? (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleDelete(item)}\n disabled={deletingId === item.id}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40\"\n >\n {deletingId === item.id ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Confirm\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteId(null)}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n ) : (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteId(item.id)}\n className=\"text-muted-foreground hover:text-red-500 disabled:opacity-40\"\n >\n <IconTrash size={12} />\n </button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n )}\n </div>\n </div>\n {item.lastRun && (\n <p className=\"text-[10px] text-muted-foreground mt-1 ml-[17px]\">\n Last run:{\" \"}\n {new Date(item.lastRun).toLocaleString(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n })}\n </p>\n )}\n </div>\n ))\n )}\n\n {toast && (\n <p\n className={`text-[10px] ${toast.kind === \"ok\" ? \"text-green-500\" : \"text-red-500\"}`}\n >\n {toast.text}\n </p>\n )}\n </div>\n );\n}\n\nfunction StatusBadge({ status }: { status?: string }) {\n if (!status) return null;\n\n const styles: Record<string, string> = {\n success: \"bg-green-500/15 text-green-500\",\n error: \"bg-red-500/15 text-red-500\",\n running: \"bg-blue-500/15 text-blue-500\",\n skipped: \"bg-accent/60 text-muted-foreground\",\n };\n\n return (\n <span\n className={`rounded-full px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${styles[status] ?? styles.skipped}`}\n >\n {status}\n </span>\n );\n}\n"]}
1
+ {"version":3,"file":"AutomationsSection.js","sourceRoot":"","sources":["../../../src/client/settings/AutomationsSection.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAc,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAChE,OAAO,EACL,QAAQ,EACR,SAAS,EACT,WAAW,EACX,cAAc,EACd,QAAQ,EACR,SAAS,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC/D,OAAO,EACL,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,6BAA6B,CAAC;AAuCrC,SAAS,WAAW,CAAC,KAAiB;IACpC,MAAM,KAAK,GAAqB,EAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC5C,CAAC;QACD,IACE,IAAI,CAAC,IAAI,KAAK,MAAM;YACpB,IAAI,CAAC,IAAI,KAAK,KAAK;YACnB,IAAI,CAAC,QAAQ;YACb,IAAI,CAAC,OAAO,EACZ,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC/D,KAAK,CAAC,IAAI,CAAC;gBACT,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;gBACpB,IAAI;gBACJ,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;gBACxB,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;gBAC/B,mBAAmB,EAAE,IAAI,CAAC,OAAO,CAAC,mBAAmB;gBACrD,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,KAAK;gBACtC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;gBACnC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;gBAC7B,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO;aAC9B,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAmB,EAAE,CAAC,CAAC;IACrE,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAClE,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAClE,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAC5E,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAGxB,IAAI,CAAC,CAAC;IAChB,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAElD,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,IAAkB,EAAE,IAAY,EAAE,EAAE,GAAG,IAAI,EAAE,EAAE;QAC9C,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACzB,UAAU,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;IACvC,CAAC,EACD,EAAE,CACH,CAAC;IAEF,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,UAAU,CAAC,IAAI,CAAC,CAAC;QACjB,KAAK,CAAC,eAAe,CAAC,+BAA+B,CAAC,CAAC;aACpD,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAChB,IAAI,CAAC,CAAC,CAAC,EAAE;gBAAE,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;YAC3D,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAyB,CAAC;QAClD,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YACjB,IAAI,SAAS;gBAAE,OAAO;YACtB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,CAChD,CAAC;YACF,MAAM,KAAK,GAAG,UAAU,EAAE,QAAQ;gBAChC,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC,QAAQ,CAAC;gBAClC,CAAC,CAAC,EAAE,CAAC;YACP,cAAc,CAAC,KAAK,CAAC,CAAC;YACtB,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACb,IAAI,SAAS;gBAAE,OAAO;YACtB,QAAQ,CAAC,GAAG,EAAE,OAAO,IAAI,gBAAgB,CAAC,CAAC;YAC3C,UAAU,CAAC,KAAK,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QACL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEnE,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,IAAoB,EAAE,EAAE;QAC7B,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CACb,4BAA4B,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC1D,CACF,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,SAAS,CAAC,KAAK,EAAE,2BAA2B,CAAC,CAAC;gBAC9C,OAAO;YACT,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YAClC,MAAM,OAAO,GAAW,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC;YAE/C,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC;YACjC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAC7B,6BAA6B,EAC7B,KAAK,UAAU,EAAE,CAClB,CAAC;YAEF,MAAM,MAAM,GAAG,MAAM,KAAK,CACxB,eAAe,CACb,4BAA4B,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC1D,EACD;gBACE,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;aAC3C,CACF,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;gBACf,SAAS,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YACD,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;YACrD,MAAM,EAAE,CAAC;QACX,CAAC;gBAAS,CAAC;YACT,aAAa,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,CAAC,CACpB,CAAC;IAEF,MAAM,YAAY,GAAG,WAAW,CAC9B,KAAK,EAAE,IAAoB,EAAE,EAAE;QAC7B,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CACb,4BAA4B,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAC1D,EACD;gBACE,MAAM,EAAE,QAAQ;gBAChB,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CACF,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,SAAS,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YACD,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YAC3B,kBAAkB,CAAC,IAAI,CAAC,CAAC;YACzB,MAAM,EAAE,CAAC;QACX,CAAC;gBAAS,CAAC;YACT,aAAa,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;IACH,CAAC,EACD,CAAC,MAAM,EAAE,SAAS,CAAC,CACpB,CAAC;IAEF,MAAM,mBAAmB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACjD,SAAS,CAAC,IAAI,EAAE,sBAAsB,CAAC,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CAAC,sCAAsC,CAAC,EACvD;gBACE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;aACnC,CACF,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,SAAS,CAAC,KAAK,EAAE,yBAAyB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;gBACzD,OAAO;YACT,CAAC;YACD,SAAS,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,IAAI,sBAAsB,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC;IAEhB,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CACtC,UAAU,CACX,CAAC;IAEF,MAAM,eAAe,GAAG,WAAW,CACjC,CAAC,IAAY,EAAE,EAAE;QACf,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,OAAO;QACrB,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,sBAAsB,EAAE;YACtC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;SACzB,CAAC,CACH,CAAC;QACF,eAAe,CAAC;YACd,OAAO,EAAE,OAAO;YAChB,OAAO,EAAE,qDAAqD,QAAQ,oKAAoK;YAC1O,MAAM,EAAE,IAAI;YACZ,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;QACH,UAAU,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC,EACD,CAAC,QAAQ,CAAC,CACX,CAAC;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CACL,aAAG,SAAS,EAAC,0BAA0B,6CACR,KAAK,IAChC,CACL,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,OAAO,CACL,eAAK,SAAS,EAAC,6DAA6D,aAC1E,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,cAAc,GAAG,kBAE9C,CACP,CAAC;IACJ,CAAC;IAED,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACxB,eAAK,SAAS,EAAC,2BAA2B,aACxC,MAAC,OAAO,IAAC,IAAI,EAAE,OAAO,EAAE,YAAY,EAAE,UAAU,aAC9C,KAAC,cAAc,IAAC,OAAO,kBACrB,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,8JAA8J,aAExK,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,GAAI,sBAEf,GACM,EACjB,MAAC,cAAc,IACb,KAAK,EAAC,OAAO,EACb,UAAU,EAAE,CAAC,EACb,gBAAgB,EAAE,CAAC,EACnB,SAAS,EAAC,gDAAgD,aAE1D,YAAG,SAAS,EAAC,iDAAiD,+BAE1D,EACJ,KAAC,cAAc,IACb,SAAS,QACT,WAAW,EAAC,uCAAuC,EACnD,UAAU,EAAC,oBAAoB,EAC/B,QAAQ,EAAE,eAAe,GACzB,EACF,cAAK,SAAS,EAAC,MAAM,YACnB,kBACE,KAAK,EAAE,QAAQ,EACf,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CACd,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,KAAoC,CAAC,EAE5D,SAAS,EAAC,4GAA4G,aAEtH,iBAAQ,KAAK,EAAC,UAAU,yBAAkB,EAC1C,iBAAQ,KAAK,EAAC,cAAc,6BAAsB,IAC3C,GACL,IACS,IACT,EACT,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,CACzB,kBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAC,8JAA8J,aAExK,KAAC,cAAc,IAAC,IAAI,EAAE,EAAE,GAAI,uBAErB,CACV,IACG,EAEL,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC1B,YAAG,SAAS,EAAC,mCAAmC,4IAG5C,CACL,CAAC,CAAC,CAAC,CACF,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CACxB,eAEE,SAAS,EAAC,0DAA0D,aAEpE,eAAK,SAAS,EAAC,yCAAyC,aACtD,eAAK,SAAS,EAAC,gBAAgB,aAC7B,eAAK,SAAS,EAAC,2BAA2B,aACxC,eAAM,SAAS,EAAC,gCAAgC,YAC7C,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CACf,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,CACxB,CAAC,CAAC,CAAC,CACF,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,GAAI,CACvB,GACI,EACP,eAAM,SAAS,EAAC,6DAA6D,YAC1E,IAAI,CAAC,IAAI,GACL,IACH,EACL,IAAI,CAAC,mBAAmB,IAAI,CAC3B,YAAG,SAAS,EAAC,oDAAoD,YAC9D,IAAI,CAAC,mBAAmB,GACvB,CACL,EACA,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,mBAAmB,IAAI,CAC7C,YAAG,SAAS,EAAC,8DAA8D,YACxE,IAAI,CAAC,QAAQ,GACZ,CACL,IACG,EACN,eAAK,SAAS,EAAC,oCAAoC,aACjD,KAAC,WAAW,IAAC,MAAM,EAAE,IAAI,CAAC,UAAU,GAAI,EACxC,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EACjC,QAAQ,EAAE,UAAU,KAAK,IAAI,CAAC,EAAE,EAChC,SAAS,EAAE,0EACT,IAAI,CAAC,OAAO;wDACV,CAAC,CAAC,gCAAgC;wDAClC,CAAC,CAAC,oCACN,uCAAuC,YAEtC,UAAU,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CACxB,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,cAAc,GAAG,CACnD,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CACjB,IAAI,CACL,CAAC,CAAC,CAAC,CACF,KAAK,CACN,GACM,GACM,EACjB,KAAC,cAAc,cACZ,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,GACrB,IACT,EACT,eAAe,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAC7B,eAAK,SAAS,EAAC,yBAAyB,aACtC,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,EACjC,QAAQ,EAAE,UAAU,KAAK,IAAI,CAAC,EAAE,EAChC,SAAS,EAAC,2IAA2I,YAEpJ,UAAU,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CACxB,KAAC,WAAW,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,cAAc,GAAG,CACnD,CAAC,CAAC,CAAC,CACF,SAAS,CACV,GACM,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EACvC,SAAS,EAAC,iIAAiI,uBAGpI,IACL,CACP,CAAC,CAAC,CAAC,CACF,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,EAC1C,SAAS,EAAC,8DAA8D,YAExE,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,GAChB,GACM,EACjB,KAAC,cAAc,yBAAwB,IAC/B,CACX,IACG,IACF,EACL,IAAI,CAAC,OAAO,IAAI,CACf,aAAG,SAAS,EAAC,kDAAkD,0BACnD,GAAG,EACZ,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,cAAc,CAAC,SAAS,EAAE;gCAChD,KAAK,EAAE,OAAO;gCACd,GAAG,EAAE,SAAS;gCACd,IAAI,EAAE,SAAS;gCACf,MAAM,EAAE,SAAS;6BAClB,CAAC,IACA,CACL,KAvGI,IAAI,CAAC,EAAE,CAwGR,CACP,CAAC,CACH,EAEA,KAAK,IAAI,CACR,YACE,SAAS,EAAE,eAAe,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,cAAc,EAAE,YAElF,KAAK,CAAC,IAAI,GACT,CACL,IACG,CACP,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,MAAM,EAAuB;IAClD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,MAAM,GAA2B;QACrC,OAAO,EAAE,gCAAgC;QACzC,KAAK,EAAE,4BAA4B;QACnC,OAAO,EAAE,8BAA8B;QACvC,OAAO,EAAE,oCAAoC;KAC9C,CAAC;IAEF,OAAO,CACL,eACE,SAAS,EAAE,+EAA+E,MAAM,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,YAE3H,MAAM,GACF,CACR,CAAC;AACJ,CAAC","sourcesContent":["import { agentNativePath } from \"../api-path.js\";\nimport React, { useEffect, useState, useCallback } from \"react\";\nimport {\n IconBolt,\n IconClock,\n IconLoader2,\n IconPlayerPlay,\n IconPlus,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { sendToAgentChat } from \"../agent-chat.js\";\nimport { PromptComposer } from \"../composer/PromptComposer.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../components/ui/popover.js\";\n\ninterface TreeNode {\n name: string;\n path: string;\n type: \"file\" | \"folder\";\n kind?: string;\n children?: TreeNode[];\n resource?: {\n id: string;\n path: string;\n owner: string;\n mimeType: string;\n size: number;\n createdAt: number;\n updatedAt: number;\n };\n jobMeta?: {\n schedule?: string;\n scheduleDescription?: string;\n enabled?: boolean;\n lastStatus?: string;\n lastRun?: string;\n nextRun?: string;\n };\n}\n\ninterface AutomationItem {\n id: string;\n name: string;\n path: string;\n schedule?: string;\n scheduleDescription?: string;\n enabled: boolean;\n lastStatus?: string;\n lastRun?: string;\n nextRun?: string;\n}\n\nfunction flattenJobs(nodes: TreeNode[]): AutomationItem[] {\n const items: AutomationItem[] = [];\n for (const node of nodes) {\n if (node.type === \"folder\" && node.children) {\n items.push(...flattenJobs(node.children));\n }\n if (\n node.type === \"file\" &&\n node.kind === \"job\" &&\n node.resource &&\n node.jobMeta\n ) {\n const name = node.name.replace(/\\.md$/, \"\").replace(/-/g, \" \");\n items.push({\n id: node.resource.id,\n name,\n path: node.resource.path,\n schedule: node.jobMeta.schedule,\n scheduleDescription: node.jobMeta.scheduleDescription,\n enabled: node.jobMeta.enabled ?? false,\n lastStatus: node.jobMeta.lastStatus,\n lastRun: node.jobMeta.lastRun,\n nextRun: node.jobMeta.nextRun,\n });\n }\n }\n return items;\n}\n\nexport function AutomationsSection() {\n const [automations, setAutomations] = useState<AutomationItem[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [togglingId, setTogglingId] = useState<string | null>(null);\n const [deletingId, setDeletingId] = useState<string | null>(null);\n const [confirmDeleteId, setConfirmDeleteId] = useState<string | null>(null);\n const [toast, setToast] = useState<{\n kind: \"ok\" | \"err\";\n text: string;\n } | null>(null);\n const [reloadToken, setReloadToken] = useState(0);\n\n const showToast = useCallback(\n (kind: \"ok\" | \"err\", text: string, ms = 2500) => {\n setToast({ kind, text });\n setTimeout(() => setToast(null), ms);\n },\n [],\n );\n\n useEffect(() => {\n let cancelled = false;\n setLoading(true);\n fetch(agentNativePath(\"/_agent-native/resources/tree\"))\n .then(async (r) => {\n if (!r.ok) throw new Error(`Failed to load (${r.status})`);\n return (await r.json()) as { tree: TreeNode[] };\n })\n .then(({ tree }) => {\n if (cancelled) return;\n const jobsFolder = tree.find(\n (n) => n.name === \"jobs\" && n.type === \"folder\",\n );\n const items = jobsFolder?.children\n ? flattenJobs(jobsFolder.children)\n : [];\n setAutomations(items);\n setLoading(false);\n })\n .catch((err) => {\n if (cancelled) return;\n setError(err?.message ?? \"Failed to load\");\n setLoading(false);\n });\n return () => {\n cancelled = true;\n };\n }, [reloadToken]);\n\n const reload = useCallback(() => setReloadToken((t) => t + 1), []);\n\n const handleToggle = useCallback(\n async (item: AutomationItem) => {\n setTogglingId(item.id);\n try {\n const res = await fetch(\n agentNativePath(\n `/_agent-native/resources/${encodeURIComponent(item.id)}`,\n ),\n );\n if (!res.ok) {\n showToast(\"err\", \"Failed to read automation\");\n return;\n }\n const resource = await res.json();\n const content: string = resource.content ?? \"\";\n\n const newEnabled = !item.enabled;\n const updated = content.replace(\n /^(enabled:\\s*)(true|false)/m,\n `$1${newEnabled}`,\n );\n\n const putRes = await fetch(\n agentNativePath(\n `/_agent-native/resources/${encodeURIComponent(item.id)}`,\n ),\n {\n method: \"PUT\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content: updated }),\n },\n );\n if (!putRes.ok) {\n showToast(\"err\", \"Failed to update automation\");\n return;\n }\n showToast(\"ok\", newEnabled ? \"Enabled\" : \"Disabled\");\n reload();\n } finally {\n setTogglingId(null);\n }\n },\n [reload, showToast],\n );\n\n const handleDelete = useCallback(\n async (item: AutomationItem) => {\n setDeletingId(item.id);\n try {\n const res = await fetch(\n agentNativePath(\n `/_agent-native/resources/${encodeURIComponent(item.id)}`,\n ),\n {\n method: \"DELETE\",\n headers: { \"Content-Type\": \"application/json\" },\n },\n );\n if (!res.ok) {\n showToast(\"err\", \"Failed to delete automation\");\n return;\n }\n showToast(\"ok\", \"Deleted\");\n setConfirmDeleteId(null);\n reload();\n } finally {\n setDeletingId(null);\n }\n },\n [reload, showToast],\n );\n\n const handleFireTestEvent = useCallback(async () => {\n showToast(\"ok\", \"Firing test event...\");\n try {\n const res = await fetch(\n agentNativePath(\"/_agent-native/automations/fire-test\"),\n {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ data: {} }),\n },\n );\n if (!res.ok) {\n showToast(\"err\", `Failed to fire event (${res.status})`);\n return;\n }\n showToast(\"ok\", \"Event fired\");\n } catch (err: any) {\n showToast(\"err\", err?.message ?? \"Failed to fire event\");\n }\n }, [showToast]);\n\n const [newOpen, setNewOpen] = useState(false);\n const [newScope, setNewScope] = useState<\"personal\" | \"organization\">(\n \"personal\",\n );\n\n const handleNewSubmit = useCallback(\n (text: string) => {\n const trimmed = text.trim();\n if (!trimmed) return;\n window.dispatchEvent(\n new CustomEvent(\"agent-panel:set-mode\", {\n detail: { mode: \"chat\" },\n }),\n );\n sendToAgentChat({\n message: trimmed,\n context: `The user wants to create a new automation. Scope: ${newScope}. Use manage-automations with action=define to create it. Ask clarifying questions if needed about what event to trigger on, conditions, and what actions to take.`,\n submit: true,\n newTab: true,\n });\n setNewOpen(false);\n },\n [newScope],\n );\n\n if (error) {\n return (\n <p className=\"text-[10px] text-red-500\">\n Failed to load automations: {error}\n </p>\n );\n }\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-1.5 text-[10px] text-muted-foreground\">\n <IconLoader2 size={10} className=\"animate-spin\" />\n Loading...\n </div>\n );\n }\n\n return (\n <div className=\"space-y-2\">\n <div className=\"flex items-center gap-1.5\">\n <Popover open={newOpen} onOpenChange={setNewOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40\"\n >\n <IconPlus size={10} />\n New Automation\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n sideOffset={6}\n collisionPadding={8}\n className=\"z-[260] w-[calc(100vw-24px)] max-w-[380px] p-3\"\n >\n <p className=\"px-1 pb-2 text-sm font-semibold text-foreground\">\n New automation\n </p>\n <PromptComposer\n autoFocus\n placeholder=\"Describe what you want to automate...\"\n draftScope=\"automations:create\"\n onSubmit={handleNewSubmit}\n />\n <div className=\"mt-2\">\n <select\n value={newScope}\n onChange={(e) =>\n setNewScope(e.target.value as \"personal\" | \"organization\")\n }\n className=\"w-full cursor-pointer rounded-md border border-input bg-background px-3 py-1.5 text-[12px] text-foreground\"\n >\n <option value=\"personal\">Personal</option>\n <option value=\"organization\">Organization</option>\n </select>\n </div>\n </PopoverContent>\n </Popover>\n {automations.length > 0 && (\n <button\n type=\"button\"\n onClick={handleFireTestEvent}\n className=\"inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[10px] font-medium text-muted-foreground hover:text-foreground hover:bg-accent/40\"\n >\n <IconPlayerPlay size={10} />\n Fire Test Event\n </button>\n )}\n </div>\n\n {automations.length === 0 ? (\n <p className=\"text-[10px] text-muted-foreground\">\n No automations yet. Click \"New Automation\" to create one, or ask the\n agent to set up a scheduled or event-triggered task.\n </p>\n ) : (\n automations.map((item) => (\n <div\n key={item.id}\n className=\"rounded-md border border-border px-2.5 py-2 bg-accent/30\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-muted-foreground shrink-0\">\n {item.schedule ? (\n <IconClock size={11} />\n ) : (\n <IconBolt size={11} />\n )}\n </span>\n <span className=\"text-[11px] font-medium text-foreground truncate capitalize\">\n {item.name}\n </span>\n </div>\n {item.scheduleDescription && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5 ml-[17px]\">\n {item.scheduleDescription}\n </p>\n )}\n {item.schedule && !item.scheduleDescription && (\n <p className=\"text-[10px] text-muted-foreground mt-0.5 ml-[17px] font-mono\">\n {item.schedule}\n </p>\n )}\n </div>\n <div className=\"flex items-center gap-1.5 shrink-0\">\n <StatusBadge status={item.lastStatus} />\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => handleToggle(item)}\n disabled={togglingId === item.id}\n className={`rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${\n item.enabled\n ? \"bg-green-500/15 text-green-500\"\n : \"bg-accent/60 text-muted-foreground\"\n } hover:opacity-80 disabled:opacity-40`}\n >\n {togglingId === item.id ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : item.enabled ? (\n \"On\"\n ) : (\n \"Off\"\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {item.enabled ? \"Disable\" : \"Enable\"}\n </TooltipContent>\n </Tooltip>\n {confirmDeleteId === item.id ? (\n <div className=\"flex items-center gap-1\">\n <button\n type=\"button\"\n onClick={() => handleDelete(item)}\n disabled={deletingId === item.id}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-red-500/15 text-red-500 hover:bg-red-500/25 disabled:opacity-40\"\n >\n {deletingId === item.id ? (\n <IconLoader2 size={10} className=\"animate-spin\" />\n ) : (\n \"Confirm\"\n )}\n </button>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteId(null)}\n className=\"rounded px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide bg-accent/60 text-muted-foreground hover:text-foreground\"\n >\n Cancel\n </button>\n </div>\n ) : (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setConfirmDeleteId(item.id)}\n className=\"text-muted-foreground hover:text-red-500 disabled:opacity-40\"\n >\n <IconTrash size={12} />\n </button>\n </TooltipTrigger>\n <TooltipContent>Delete</TooltipContent>\n </Tooltip>\n )}\n </div>\n </div>\n {item.lastRun && (\n <p className=\"text-[10px] text-muted-foreground mt-1 ml-[17px]\">\n Last run:{\" \"}\n {new Date(item.lastRun).toLocaleString(undefined, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n })}\n </p>\n )}\n </div>\n ))\n )}\n\n {toast && (\n <p\n className={`text-[10px] ${toast.kind === \"ok\" ? \"text-green-500\" : \"text-red-500\"}`}\n >\n {toast.text}\n </p>\n )}\n </div>\n );\n}\n\nfunction StatusBadge({ status }: { status?: string }) {\n if (!status) return null;\n\n const styles: Record<string, string> = {\n success: \"bg-green-500/15 text-green-500\",\n error: \"bg-red-500/15 text-red-500\",\n running: \"bg-blue-500/15 text-blue-500\",\n skipped: \"bg-accent/60 text-muted-foreground\",\n };\n\n return (\n <span\n className={`rounded-full px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide ${styles[status] ?? styles.skipped}`}\n >\n {status}\n </span>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"AgentTerminal.d.ts","sourceRoot":"","sources":["../../../src/client/terminal/AgentTerminal.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAc,EAKZ,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAIf,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AA6ED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,UAIvD;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,KAAK,EAAE,SAAS,EAChB,WAAkB,EAClB,KAAK,EACL,QAAa,EACb,SAAS,EACT,KAAK,EACL,kBAAkB,EAClB,oBAAoB,GACrB,EAAE,kBAAkB,2CA2TpB"}
1
+ {"version":3,"file":"AgentTerminal.d.ts","sourceRoot":"","sources":["../../../src/client/terminal/AgentTerminal.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAc,EAKZ,KAAK,aAAa,EACnB,MAAM,OAAO,CAAC;AAIf,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,6BAA6B;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CACnD;AA6ED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,UAIvD;AAED,wBAAgB,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,KAAK,EAAE,SAAS,EAChB,WAAkB,EAClB,KAAK,EACL,QAAa,EACb,SAAS,EACT,KAAK,EACL,kBAAkB,EAClB,oBAAoB,GACrB,EAAE,kBAAkB,2CAmWpB"}
@@ -141,53 +141,84 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
141
141
  term.loadAddon(fitAddon);
142
142
  term.loadAddon(webLinksAddon);
143
143
  term.open(container);
144
- requestAnimationFrame(() => {
145
- try {
146
- fitAddon.fit();
147
- }
148
- catch { }
149
- });
150
- // Resize observer for auto-fitting
151
- const resizeObserver = new ResizeObserver(() => {
144
+ let fitPending = false;
145
+ function fitAndResize() {
146
+ if (fitPending)
147
+ return;
148
+ fitPending = true;
152
149
  requestAnimationFrame(() => {
150
+ fitPending = false;
151
+ if (disposed ||
152
+ !container.isConnected ||
153
+ container.clientWidth <= 0 ||
154
+ container.clientHeight <= 0) {
155
+ return;
156
+ }
153
157
  try {
154
158
  fitAddon.fit();
155
159
  sendResize();
156
160
  }
157
161
  catch { }
158
162
  });
163
+ }
164
+ fitAndResize();
165
+ const initialFitTimers = [
166
+ setTimeout(fitAndResize, 50),
167
+ setTimeout(fitAndResize, 250),
168
+ ];
169
+ const handleVisibilityOrFocus = () => fitAndResize();
170
+ window.addEventListener("focus", handleVisibilityOrFocus);
171
+ document.addEventListener("visibilitychange", handleVisibilityOrFocus);
172
+ // Resize observer for auto-fitting
173
+ const resizeObserver = new ResizeObserver(() => {
174
+ fitAndResize();
159
175
  });
160
176
  resizeObserver.observe(container);
177
+ let terminalDisposed = false;
178
+ function disposeTerminal() {
179
+ if (terminalDisposed)
180
+ return;
181
+ terminalDisposed = true;
182
+ initialFitTimers.forEach(clearTimeout);
183
+ window.removeEventListener("focus", handleVisibilityOrFocus);
184
+ document.removeEventListener("visibilitychange", handleVisibilityOrFocus);
185
+ resizeObserver.disconnect();
186
+ term.dispose();
187
+ }
161
188
  // Discover WebSocket URL
162
189
  let wsUrl = wsUrlProp;
190
+ let resolvedCommand = command;
163
191
  if (!wsUrl) {
164
192
  try {
165
193
  const res = await fetch(agentNativePath("/_agent-native/agent-terminal-info"));
166
194
  const info = await res.json();
167
195
  if (!info.available) {
168
196
  setError(info.error || "Agent terminal not available");
197
+ disposeTerminal();
169
198
  return;
170
199
  }
171
200
  const protocol = location.protocol === "https:" ? "wss:" : "ws:";
172
201
  const host = formatWebSocketHostname(location.hostname);
173
202
  wsUrl = `${protocol}//${host}:${info.wsPort}/ws`;
174
- if (!command && info.command) {
175
- command = info.command;
203
+ if (!resolvedCommand && info.command) {
204
+ resolvedCommand = info.command;
176
205
  }
177
206
  }
178
207
  catch (err) {
179
208
  setError("Failed to discover terminal server");
209
+ disposeTerminal();
180
210
  return;
181
211
  }
182
212
  }
183
213
  // Build WebSocket URL with query params
184
214
  const qs = new URLSearchParams();
185
- if (command)
186
- qs.set("command", command);
215
+ if (resolvedCommand)
216
+ qs.set("command", resolvedCommand);
187
217
  if (flags)
188
218
  qs.set("flags", flags);
189
219
  const qsStr = qs.toString();
190
220
  const fullWsUrl = qsStr ? `${wsUrl}?${qsStr}` : wsUrl;
221
+ term.write(`\x1b[2m[terminal] Starting ${resolvedCommand || "CLI"}...\x1b[0m\r\n`);
191
222
  // Connect WebSocket
192
223
  let agentRunning = false;
193
224
  let idleTimer = null;
@@ -303,12 +334,11 @@ export function AgentTerminal({ command, flags, wsUrl: wsUrlProp, hideInFrame =
303
334
  connectionId++;
304
335
  if (idleTimer)
305
336
  clearTimeout(idleTimer);
306
- resizeObserver.disconnect();
337
+ disposeTerminal();
307
338
  if (ws) {
308
339
  ws.close();
309
340
  ws = null;
310
341
  }
311
- term.dispose();
312
342
  };
313
343
  }
314
344
  let cleanup;
@@ -1 +1 @@
1
- {"version":3,"file":"AgentTerminal.js","sourceRoot":"","sources":["../../../src/client/terminal/AgentTerminal.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n * AgentTerminal — Embeddable CLI terminal component\n *\n * Renders an xterm.js terminal connected to a PTY WebSocket server.\n * When running inside a frame, renders nothing (the frame manages the terminal).\n *\n * Usage:\n * import { AgentTerminal } from \"@agent-native/core/terminal\";\n * <AgentTerminal className=\"w-full h-[400px]\" />\n */\n\nimport React, {\n useRef,\n useEffect,\n useState,\n useCallback,\n type CSSProperties,\n} from \"react\";\nimport { agentNativePath } from \"../api-path.js\";\nimport { getFrameOrigin, isTrustedFrameMessage } from \"../frame.js\";\n\nexport interface AgentTerminalProps {\n /** CLI command to run. Default: 'builder' */\n command?: string;\n /** Additional CLI flags */\n flags?: string;\n /** Custom WebSocket URL (overrides auto-discovery) */\n wsUrl?: string;\n /** Hide when running inside frame. Default: true */\n hideInFrame?: boolean;\n /** Terminal theme overrides */\n theme?: Record<string, string>;\n /** Font size. Default: 12 */\n fontSize?: number;\n /** CSS class for the container */\n className?: string;\n /** Inline styles for the container */\n style?: CSSProperties;\n /** Callback when connection state changes */\n onConnectionChange?: (connected: boolean) => void;\n /** Callback when agent running state changes */\n onAgentRunningChange?: (running: boolean) => void;\n}\n\n// Inject xterm CSS once\nlet cssInjected = false;\nfunction injectXtermCss() {\n if (cssInjected || typeof document === \"undefined\") return;\n cssInjected = true;\n const style = document.createElement(\"style\");\n style.textContent = `\n .xterm { position: relative; user-select: none; }\n .xterm.focus, .xterm:focus { outline: none; }\n .xterm .xterm-helpers { position: absolute; top: 0; z-index: 5; }\n .xterm .xterm-helper-textarea {\n padding: 0; border: 0; margin: 0;\n position: absolute; opacity: 0; left: -9999em; top: 0;\n width: 0; height: 0; z-index: -5;\n white-space: nowrap; overflow: hidden; resize: none;\n }\n .xterm .composition-view { display: none; position: absolute; white-space: nowrap; z-index: 1; }\n .xterm .composition-view.active { display: block; }\n .xterm .xterm-viewport {\n background-color: #000; overflow-y: scroll;\n cursor: default; position: absolute; right: 0; left: 0; top: 0; bottom: 0;\n }\n .xterm .xterm-screen { position: relative; }\n .xterm .xterm-screen canvas { position: absolute; left: 0; top: 0; }\n .xterm .xterm-scroll-area { visibility: hidden; }\n .xterm-char-measure-element {\n display: inline-block; visibility: hidden; position: absolute; top: 0; left: -9999em;\n line-height: normal;\n }\n .xterm.enable-mouse-events { cursor: default; }\n .xterm.xterm-cursor-pointer, .xterm .xterm-cursor-pointer { cursor: pointer; }\n .xterm.column-select.focus { cursor: crosshair; }\n .xterm .xterm-accessibility:not(.debug),\n .xterm .xterm-message { position: absolute; left: 0; top: 0; bottom: 0; right: 0; z-index: 10; color: transparent; pointer-events: none; }\n .xterm .xterm-accessibility-tree:not(.debug) *::selection { color: transparent; }\n .xterm .xterm-accessibility-tree { user-select: text; white-space: pre; }\n .xterm .live-region { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }\n .xterm .xterm-dim { opacity: 0.5; }\n .xterm .xterm-underline-1 { text-decoration: underline; }\n .xterm .xterm-underline-2 { text-decoration: double underline; }\n .xterm .xterm-underline-3 { text-decoration: wavy underline; }\n .xterm .xterm-underline-4 { text-decoration: dotted underline; }\n .xterm .xterm-underline-5 { text-decoration: dashed underline; }\n .xterm .xterm-overline { text-decoration: overline; }\n .xterm .xterm-strikethrough { text-decoration: line-through; }\n .xterm .xterm-screen .xterm-decoration-container .xterm-decoration { z-index: 6; position: absolute; }\n .xterm .xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer { z-index: 7; }\n .xterm .xterm-decoration-overview-ruler { z-index: 8; position: absolute; top: 0; right: 0; pointer-events: none; }\n .xterm .xterm-decoration-top { z-index: 2; position: relative; }\n `;\n document.head.appendChild(style);\n}\n\nconst DEFAULT_THEME = {\n background: \"#111\",\n foreground: \"#e0e0e0\",\n cursor: \"#58a6ff\",\n selectionBackground: \"#264f78\",\n black: \"#484f58\",\n red: \"#ff7b72\",\n green: \"#3fb950\",\n yellow: \"#d29922\",\n blue: \"#58a6ff\",\n magenta: \"#bc8cff\",\n cyan: \"#39d353\",\n white: \"#b1bac4\",\n};\n\ninterface TerminalInfo {\n available: boolean;\n wsPort?: number;\n command?: string;\n error?: string;\n}\n\nexport function formatWebSocketHostname(hostname: string) {\n return hostname.includes(\":\") && !hostname.startsWith(\"[\")\n ? `[${hostname}]`\n : hostname;\n}\n\nexport function AgentTerminal({\n command,\n flags,\n wsUrl: wsUrlProp,\n hideInFrame = true,\n theme,\n fontSize = 12,\n className,\n style,\n onConnectionChange,\n onAgentRunningChange,\n}: AgentTerminalProps) {\n const termRef = useRef<HTMLDivElement>(null);\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [inFrame, setInFrame] = useState(false);\n\n // Check frame state after mount (postMessage is async)\n useEffect(() => {\n if (!hideInFrame) return;\n // Check immediately and also after a short delay for the postMessage to arrive\n const check = () => {\n if (getFrameOrigin()) setInFrame(true);\n };\n check();\n const timer = setTimeout(check, 500);\n return () => clearTimeout(timer);\n }, [hideInFrame]);\n\n // Notify parent of connection changes\n useEffect(() => {\n onConnectionChange?.(connected);\n }, [connected, onConnectionChange]);\n\n // Main terminal setup\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (hideInFrame && inFrame) return;\n\n const container = termRef.current;\n if (!container) return;\n\n let disposed = false;\n let ws: WebSocket | null = null;\n let cleanupMessageHandler: (() => void) | null = null;\n\n async function init() {\n // Dynamic imports for SSR safety\n const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all(\n [\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ],\n );\n\n if (disposed || !container) return;\n\n injectXtermCss();\n\n const term = new Terminal({\n cursorBlink: true,\n fontSize,\n fontFamily: \"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace\",\n theme: { ...DEFAULT_THEME, ...theme },\n });\n\n const fitAddon = new FitAddon();\n const webLinksAddon = new WebLinksAddon((_event, uri) => {\n window.open(uri, \"_blank\", \"noopener\");\n });\n\n term.loadAddon(fitAddon);\n term.loadAddon(webLinksAddon);\n term.open(container);\n\n requestAnimationFrame(() => {\n try {\n fitAddon.fit();\n } catch {}\n });\n\n // Resize observer for auto-fitting\n const resizeObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => {\n try {\n fitAddon.fit();\n sendResize();\n } catch {}\n });\n });\n resizeObserver.observe(container);\n\n // Discover WebSocket URL\n let wsUrl = wsUrlProp;\n if (!wsUrl) {\n try {\n const res = await fetch(\n agentNativePath(\"/_agent-native/agent-terminal-info\"),\n );\n const info: TerminalInfo = await res.json();\n if (!info.available) {\n setError(info.error || \"Agent terminal not available\");\n return;\n }\n const protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = formatWebSocketHostname(location.hostname);\n wsUrl = `${protocol}//${host}:${info.wsPort}/ws`;\n if (!command && info.command) {\n command = info.command;\n }\n } catch (err) {\n setError(\"Failed to discover terminal server\");\n return;\n }\n }\n\n // Build WebSocket URL with query params\n const qs = new URLSearchParams();\n if (command) qs.set(\"command\", command);\n if (flags) qs.set(\"flags\", flags);\n const qsStr = qs.toString();\n const fullWsUrl = qsStr ? `${wsUrl}?${qsStr}` : wsUrl;\n\n // Connect WebSocket\n let agentRunning = false;\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let connectionId = 0;\n\n function sendResize() {\n if (ws && ws.readyState === WebSocket.OPEN && term) {\n ws.send(\n JSON.stringify({\n type: \"resize\",\n cols: term.cols,\n rows: term.rows,\n }),\n );\n }\n }\n\n function notifyAgentRunning(running: boolean) {\n onAgentRunningChange?.(running);\n window.dispatchEvent(\n new CustomEvent(\"agentNative.chatRunning\", {\n detail: { isRunning: running },\n }),\n );\n }\n\n function connect(url: string) {\n const thisId = ++connectionId;\n\n if (ws) {\n ws.close();\n ws = null;\n }\n\n const socket = new WebSocket(url);\n socket.binaryType = \"arraybuffer\";\n ws = socket;\n\n socket.onopen = () => {\n setConnected(true);\n setError(null);\n socket.send(\n JSON.stringify({\n type: \"resize\",\n cols: term.cols,\n rows: term.rows,\n }),\n );\n };\n\n socket.onmessage = (event) => {\n const data =\n event.data instanceof ArrayBuffer\n ? new TextDecoder().decode(event.data)\n : event.data;\n\n // Check for setup-status JSON messages\n try {\n const msg = JSON.parse(data);\n if (msg.type === \"setup-status\") {\n if (msg.status === \"not-found\" || msg.status === \"failed\") {\n setError(msg.message);\n // Bump connectionId to suppress reconnect on close\n connectionId++;\n }\n return;\n }\n } catch {\n // Not JSON — regular terminal output\n }\n\n setError(null);\n term.write(data);\n\n // Idle detection — prompt or cursor visible means agent stopped\n if (data.includes(\"❯\") || data.includes(\"\\x1b[?25h\")) {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => {\n if (agentRunning) {\n agentRunning = false;\n notifyAgentRunning(false);\n }\n }, 600);\n } else if (agentRunning) {\n if (idleTimer) clearTimeout(idleTimer);\n }\n };\n\n socket.onclose = () => {\n setConnected(false);\n if (connectionId === thisId && !disposed) {\n term.write(\n \"\\r\\n\\x1b[31m[terminal] Connection closed. Reconnecting in 3s...\\x1b[0m\\r\\n\",\n );\n setTimeout(() => {\n if (connectionId === thisId && !disposed) {\n connect(url);\n }\n }, 3000);\n }\n };\n\n socket.onerror = () => socket.close();\n }\n\n // Terminal input → WebSocket\n term.onData((data) => {\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(data);\n }\n });\n\n // Chat bridge integration — listen for sendToAgentChat messages\n const messageHandler = (event: MessageEvent) => {\n if (!isTrustedFrameMessage(event)) return;\n if (event.data?.type === \"agentNative.submitChat\") {\n const message = event.data.data?.message;\n if (message && ws && ws.readyState === WebSocket.OPEN) {\n ws.send(message + \"\\r\");\n agentRunning = true;\n notifyAgentRunning(true);\n }\n }\n };\n window.addEventListener(\"message\", messageHandler);\n cleanupMessageHandler = () =>\n window.removeEventListener(\"message\", messageHandler);\n\n connect(fullWsUrl);\n\n // Store cleanup references\n return () => {\n disposed = true;\n connectionId++;\n if (idleTimer) clearTimeout(idleTimer);\n resizeObserver.disconnect();\n if (ws) {\n ws.close();\n ws = null;\n }\n term.dispose();\n };\n }\n\n let cleanup: (() => void) | undefined;\n init().then((fn) => {\n cleanup = fn;\n });\n\n return () => {\n disposed = true;\n cleanup?.();\n cleanupMessageHandler?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hideInFrame, inFrame, command, flags, wsUrlProp]);\n\n if (hideInFrame && inFrame) {\n return null;\n }\n\n const terminalBackground = theme?.background ?? DEFAULT_THEME.background;\n const mergedStyle = {\n ...style,\n background: terminalBackground,\n backgroundColor: terminalBackground,\n };\n\n return (\n <div\n ref={termRef}\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n padding: \"4px 12px\",\n position: \"relative\",\n ...mergedStyle,\n }}\n >\n {error && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"#111\",\n color: \"#ff7b72\",\n fontSize: \"13px\",\n fontFamily: \"monospace\",\n padding: \"20px\",\n textAlign: \"center\",\n zIndex: 1,\n }}\n >\n {error}\n </div>\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"AgentTerminal.js","sourceRoot":"","sources":["../../../src/client/terminal/AgentTerminal.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;AAEH,OAAc,EACZ,MAAM,EACN,SAAS,EACT,QAAQ,GAGT,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAyBpE,wBAAwB;AACxB,IAAI,WAAW,GAAG,KAAK,CAAC;AACxB,SAAS,cAAc;IACrB,IAAI,WAAW,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAC3D,WAAW,GAAG,IAAI,CAAC;IACnB,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CnB,CAAC;IACF,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,aAAa,GAAG;IACpB,UAAU,EAAE,MAAM;IAClB,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,SAAS;IACjB,mBAAmB,EAAE,SAAS;IAC9B,KAAK,EAAE,SAAS;IAChB,GAAG,EAAE,SAAS;IACd,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;CACjB,CAAC;AASF,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,OAAO,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC;QACxD,CAAC,CAAC,IAAI,QAAQ,GAAG;QACjB,CAAC,CAAC,QAAQ,CAAC;AACf,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAC5B,OAAO,EACP,KAAK,EACL,KAAK,EAAE,SAAS,EAChB,WAAW,GAAG,IAAI,EAClB,KAAK,EACL,QAAQ,GAAG,EAAE,EACb,SAAS,EACT,KAAK,EACL,kBAAkB,EAClB,oBAAoB,GACD;IACnB,MAAM,OAAO,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IAC7C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9C,uDAAuD;IACvD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,WAAW;YAAE,OAAO;QACzB,+EAA+E;QAC/E,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,IAAI,cAAc,EAAE;gBAAE,UAAU,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC,CAAC;QACF,KAAK,EAAE,CAAC;QACR,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACrC,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IACnC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IAElB,sCAAsC;IACtC,SAAS,CAAC,GAAG,EAAE;QACb,kBAAkB,EAAE,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC,EAAE,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAEpC,sBAAsB;IACtB,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QAC1C,IAAI,WAAW,IAAI,OAAO;YAAE,OAAO;QAEnC,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC;QAClC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,EAAE,GAAqB,IAAI,CAAC;QAChC,IAAI,qBAAqB,GAAwB,IAAI,CAAC;QAEtD,KAAK,UAAU,IAAI;YACjB,iCAAiC;YACjC,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CACvE;gBACE,MAAM,CAAC,cAAc,CAAC;gBACtB,MAAM,CAAC,kBAAkB,CAAC;gBAC1B,MAAM,CAAC,wBAAwB,CAAC;aACjC,CACF,CAAC;YAEF,IAAI,QAAQ,IAAI,CAAC,SAAS;gBAAE,OAAO;YAEnC,cAAc,EAAE,CAAC;YAEjB,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC;gBACxB,WAAW,EAAE,IAAI;gBACjB,QAAQ;gBACR,UAAU,EAAE,2DAA2D;gBACvE,KAAK,EAAE,EAAE,GAAG,aAAa,EAAE,GAAG,KAAK,EAAE;aACtC,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;YAChC,MAAM,aAAa,GAAG,IAAI,aAAa,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBACtD,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;YACzC,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YAC9B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAErB,IAAI,UAAU,GAAG,KAAK,CAAC;YACvB,SAAS,YAAY;gBACnB,IAAI,UAAU;oBAAE,OAAO;gBACvB,UAAU,GAAG,IAAI,CAAC;gBAClB,qBAAqB,CAAC,GAAG,EAAE;oBACzB,UAAU,GAAG,KAAK,CAAC;oBACnB,IACE,QAAQ;wBACR,CAAC,SAAS,CAAC,WAAW;wBACtB,SAAS,CAAC,WAAW,IAAI,CAAC;wBAC1B,SAAS,CAAC,YAAY,IAAI,CAAC,EAC3B,CAAC;wBACD,OAAO;oBACT,CAAC;oBACD,IAAI,CAAC;wBACH,QAAQ,CAAC,GAAG,EAAE,CAAC;wBACf,UAAU,EAAE,CAAC;oBACf,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACZ,CAAC,CAAC,CAAC;YACL,CAAC;YAED,YAAY,EAAE,CAAC;YACf,MAAM,gBAAgB,GAAG;gBACvB,UAAU,CAAC,YAAY,EAAE,EAAE,CAAC;gBAC5B,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC;aAC9B,CAAC;YAEF,MAAM,uBAAuB,GAAG,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC;YACrD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;YAC1D,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,uBAAuB,CAAC,CAAC;YAEvE,mCAAmC;YACnC,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,GAAG,EAAE;gBAC7C,YAAY,EAAE,CAAC;YACjB,CAAC,CAAC,CAAC;YACH,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAElC,IAAI,gBAAgB,GAAG,KAAK,CAAC;YAC7B,SAAS,eAAe;gBACtB,IAAI,gBAAgB;oBAAE,OAAO;gBAC7B,gBAAgB,GAAG,IAAI,CAAC;gBACxB,gBAAgB,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;gBACvC,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,uBAAuB,CAAC,CAAC;gBAC7D,QAAQ,CAAC,mBAAmB,CAC1B,kBAAkB,EAClB,uBAAuB,CACxB,CAAC;gBACF,cAAc,CAAC,UAAU,EAAE,CAAC;gBAC5B,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;YAED,yBAAyB;YACzB,IAAI,KAAK,GAAG,SAAS,CAAC;YACtB,IAAI,eAAe,GAAG,OAAO,CAAC;YAC9B,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CAAC,oCAAoC,CAAC,CACtD,CAAC;oBACF,MAAM,IAAI,GAAiB,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;oBAC5C,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;wBACpB,QAAQ,CAAC,IAAI,CAAC,KAAK,IAAI,8BAA8B,CAAC,CAAC;wBACvD,eAAe,EAAE,CAAC;wBAClB,OAAO;oBACT,CAAC;oBACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC;oBACjE,MAAM,IAAI,GAAG,uBAAuB,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;oBACxD,KAAK,GAAG,GAAG,QAAQ,KAAK,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;oBACjD,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;wBACrC,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC;oBACjC,CAAC;gBACH,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,QAAQ,CAAC,oCAAoC,CAAC,CAAC;oBAC/C,eAAe,EAAE,CAAC;oBAClB,OAAO;gBACT,CAAC;YACH,CAAC;YAED,wCAAwC;YACxC,MAAM,EAAE,GAAG,IAAI,eAAe,EAAE,CAAC;YACjC,IAAI,eAAe;gBAAE,EAAE,CAAC,GAAG,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YACxD,IAAI,KAAK;gBAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAClC,MAAM,KAAK,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;YAEtD,IAAI,CAAC,KAAK,CACR,8BAA8B,eAAe,IAAI,KAAK,gBAAgB,CACvE,CAAC;YAEF,oBAAoB;YACpB,IAAI,YAAY,GAAG,KAAK,CAAC;YACzB,IAAI,SAAS,GAAyC,IAAI,CAAC;YAC3D,IAAI,YAAY,GAAG,CAAC,CAAC;YAErB,SAAS,UAAU;gBACjB,IAAI,EAAE,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;oBACnD,EAAE,CAAC,IAAI,CACL,IAAI,CAAC,SAAS,CAAC;wBACb,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,IAAI,EAAE,IAAI,CAAC,IAAI;qBAChB,CAAC,CACH,CAAC;gBACJ,CAAC;YACH,CAAC;YAED,SAAS,kBAAkB,CAAC,OAAgB;gBAC1C,oBAAoB,EAAE,CAAC,OAAO,CAAC,CAAC;gBAChC,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,yBAAyB,EAAE;oBACzC,MAAM,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;iBAC/B,CAAC,CACH,CAAC;YACJ,CAAC;YAED,SAAS,OAAO,CAAC,GAAW;gBAC1B,MAAM,MAAM,GAAG,EAAE,YAAY,CAAC;gBAE9B,IAAI,EAAE,EAAE,CAAC;oBACP,EAAE,CAAC,KAAK,EAAE,CAAC;oBACX,EAAE,GAAG,IAAI,CAAC;gBACZ,CAAC;gBAED,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC;gBAClC,MAAM,CAAC,UAAU,GAAG,aAAa,CAAC;gBAClC,EAAE,GAAG,MAAM,CAAC;gBAEZ,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;oBACnB,YAAY,CAAC,IAAI,CAAC,CAAC;oBACnB,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACf,MAAM,CAAC,IAAI,CACT,IAAI,CAAC,SAAS,CAAC;wBACb,IAAI,EAAE,QAAQ;wBACd,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,IAAI,EAAE,IAAI,CAAC,IAAI;qBAChB,CAAC,CACH,CAAC;gBACJ,CAAC,CAAC;gBAEF,MAAM,CAAC,SAAS,GAAG,CAAC,KAAK,EAAE,EAAE;oBAC3B,MAAM,IAAI,GACR,KAAK,CAAC,IAAI,YAAY,WAAW;wBAC/B,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;wBACtC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;oBAEjB,uCAAuC;oBACvC,IAAI,CAAC;wBACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;wBAC7B,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;4BAChC,IAAI,GAAG,CAAC,MAAM,KAAK,WAAW,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gCAC1D,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gCACtB,mDAAmD;gCACnD,YAAY,EAAE,CAAC;4BACjB,CAAC;4BACD,OAAO;wBACT,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,qCAAqC;oBACvC,CAAC;oBAED,QAAQ,CAAC,IAAI,CAAC,CAAC;oBACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBAEjB,gEAAgE;oBAChE,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;wBACrD,IAAI,SAAS;4BAAE,YAAY,CAAC,SAAS,CAAC,CAAC;wBACvC,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;4BAC1B,IAAI,YAAY,EAAE,CAAC;gCACjB,YAAY,GAAG,KAAK,CAAC;gCACrB,kBAAkB,CAAC,KAAK,CAAC,CAAC;4BAC5B,CAAC;wBACH,CAAC,EAAE,GAAG,CAAC,CAAC;oBACV,CAAC;yBAAM,IAAI,YAAY,EAAE,CAAC;wBACxB,IAAI,SAAS;4BAAE,YAAY,CAAC,SAAS,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC,CAAC;gBAEF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;oBACpB,YAAY,CAAC,KAAK,CAAC,CAAC;oBACpB,IAAI,YAAY,KAAK,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;wBACzC,IAAI,CAAC,KAAK,CACR,4EAA4E,CAC7E,CAAC;wBACF,UAAU,CAAC,GAAG,EAAE;4BACd,IAAI,YAAY,KAAK,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;gCACzC,OAAO,CAAC,GAAG,CAAC,CAAC;4BACf,CAAC;wBACH,CAAC,EAAE,IAAI,CAAC,CAAC;oBACX,CAAC;gBACH,CAAC,CAAC;gBAEF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACxC,CAAC;YAED,6BAA6B;YAC7B,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;gBACnB,IAAI,EAAE,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;oBAC3C,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAChB,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,gEAAgE;YAChE,MAAM,cAAc,GAAG,CAAC,KAAmB,EAAE,EAAE;gBAC7C,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC;oBAAE,OAAO;gBAC1C,IAAI,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,wBAAwB,EAAE,CAAC;oBAClD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC;oBACzC,IAAI,OAAO,IAAI,EAAE,IAAI,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;wBACtD,EAAE,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;wBACxB,YAAY,GAAG,IAAI,CAAC;wBACpB,kBAAkB,CAAC,IAAI,CAAC,CAAC;oBAC3B,CAAC;gBACH,CAAC;YACH,CAAC,CAAC;YACF,MAAM,CAAC,gBAAgB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YACnD,qBAAqB,GAAG,GAAG,EAAE,CAC3B,MAAM,CAAC,mBAAmB,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;YAExD,OAAO,CAAC,SAAS,CAAC,CAAC;YAEnB,2BAA2B;YAC3B,OAAO,GAAG,EAAE;gBACV,QAAQ,GAAG,IAAI,CAAC;gBAChB,YAAY,EAAE,CAAC;gBACf,IAAI,SAAS;oBAAE,YAAY,CAAC,SAAS,CAAC,CAAC;gBACvC,eAAe,EAAE,CAAC;gBAClB,IAAI,EAAE,EAAE,CAAC;oBACP,EAAE,CAAC,KAAK,EAAE,CAAC;oBACX,EAAE,GAAG,IAAI,CAAC;gBACZ,CAAC;YACH,CAAC,CAAC;QACJ,CAAC;QAED,IAAI,OAAiC,CAAC;QACtC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE;YACjB,OAAO,GAAG,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,OAAO,GAAG,EAAE;YACV,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,EAAE,EAAE,CAAC;YACZ,qBAAqB,EAAE,EAAE,CAAC;QAC5B,CAAC,CAAC;QACF,uDAAuD;IACzD,CAAC,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;IAEtD,IAAI,WAAW,IAAI,OAAO,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,kBAAkB,GAAG,KAAK,EAAE,UAAU,IAAI,aAAa,CAAC,UAAU,CAAC;IACzE,MAAM,WAAW,GAAG;QAClB,GAAG,KAAK;QACR,UAAU,EAAE,kBAAkB;QAC9B,eAAe,EAAE,kBAAkB;KACpC,CAAC;IAEF,OAAO,CACL,cACE,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE;YACL,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,UAAU;YACnB,QAAQ,EAAE,UAAU;YACpB,GAAG,WAAW;SACf,YAEA,KAAK,IAAI,CACR,cACE,KAAK,EAAE;gBACL,QAAQ,EAAE,UAAU;gBACpB,KAAK,EAAE,CAAC;gBACR,OAAO,EAAE,MAAM;gBACf,UAAU,EAAE,QAAQ;gBACpB,cAAc,EAAE,QAAQ;gBACxB,eAAe,EAAE,MAAM;gBACvB,KAAK,EAAE,SAAS;gBAChB,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,WAAW;gBACvB,OAAO,EAAE,MAAM;gBACf,SAAS,EAAE,QAAQ;gBACnB,MAAM,EAAE,CAAC;aACV,YAEA,KAAK,GACF,CACP,GACG,CACP,CAAC;AACJ,CAAC","sourcesContent":["/**\n * AgentTerminal — Embeddable CLI terminal component\n *\n * Renders an xterm.js terminal connected to a PTY WebSocket server.\n * When running inside a frame, renders nothing (the frame manages the terminal).\n *\n * Usage:\n * import { AgentTerminal } from \"@agent-native/core/terminal\";\n * <AgentTerminal className=\"w-full h-[400px]\" />\n */\n\nimport React, {\n useRef,\n useEffect,\n useState,\n useCallback,\n type CSSProperties,\n} from \"react\";\nimport { agentNativePath } from \"../api-path.js\";\nimport { getFrameOrigin, isTrustedFrameMessage } from \"../frame.js\";\n\nexport interface AgentTerminalProps {\n /** CLI command to run. Default: 'builder' */\n command?: string;\n /** Additional CLI flags */\n flags?: string;\n /** Custom WebSocket URL (overrides auto-discovery) */\n wsUrl?: string;\n /** Hide when running inside frame. Default: true */\n hideInFrame?: boolean;\n /** Terminal theme overrides */\n theme?: Record<string, string>;\n /** Font size. Default: 12 */\n fontSize?: number;\n /** CSS class for the container */\n className?: string;\n /** Inline styles for the container */\n style?: CSSProperties;\n /** Callback when connection state changes */\n onConnectionChange?: (connected: boolean) => void;\n /** Callback when agent running state changes */\n onAgentRunningChange?: (running: boolean) => void;\n}\n\n// Inject xterm CSS once\nlet cssInjected = false;\nfunction injectXtermCss() {\n if (cssInjected || typeof document === \"undefined\") return;\n cssInjected = true;\n const style = document.createElement(\"style\");\n style.textContent = `\n .xterm { position: relative; user-select: none; }\n .xterm.focus, .xterm:focus { outline: none; }\n .xterm .xterm-helpers { position: absolute; top: 0; z-index: 5; }\n .xterm .xterm-helper-textarea {\n padding: 0; border: 0; margin: 0;\n position: absolute; opacity: 0; left: -9999em; top: 0;\n width: 0; height: 0; z-index: -5;\n white-space: nowrap; overflow: hidden; resize: none;\n }\n .xterm .composition-view { display: none; position: absolute; white-space: nowrap; z-index: 1; }\n .xterm .composition-view.active { display: block; }\n .xterm .xterm-viewport {\n background-color: #000; overflow-y: scroll;\n cursor: default; position: absolute; right: 0; left: 0; top: 0; bottom: 0;\n }\n .xterm .xterm-screen { position: relative; }\n .xterm .xterm-screen canvas { position: absolute; left: 0; top: 0; }\n .xterm .xterm-scroll-area { visibility: hidden; }\n .xterm-char-measure-element {\n display: inline-block; visibility: hidden; position: absolute; top: 0; left: -9999em;\n line-height: normal;\n }\n .xterm.enable-mouse-events { cursor: default; }\n .xterm.xterm-cursor-pointer, .xterm .xterm-cursor-pointer { cursor: pointer; }\n .xterm.column-select.focus { cursor: crosshair; }\n .xterm .xterm-accessibility:not(.debug),\n .xterm .xterm-message { position: absolute; left: 0; top: 0; bottom: 0; right: 0; z-index: 10; color: transparent; pointer-events: none; }\n .xterm .xterm-accessibility-tree:not(.debug) *::selection { color: transparent; }\n .xterm .xterm-accessibility-tree { user-select: text; white-space: pre; }\n .xterm .live-region { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }\n .xterm .xterm-dim { opacity: 0.5; }\n .xterm .xterm-underline-1 { text-decoration: underline; }\n .xterm .xterm-underline-2 { text-decoration: double underline; }\n .xterm .xterm-underline-3 { text-decoration: wavy underline; }\n .xterm .xterm-underline-4 { text-decoration: dotted underline; }\n .xterm .xterm-underline-5 { text-decoration: dashed underline; }\n .xterm .xterm-overline { text-decoration: overline; }\n .xterm .xterm-strikethrough { text-decoration: line-through; }\n .xterm .xterm-screen .xterm-decoration-container .xterm-decoration { z-index: 6; position: absolute; }\n .xterm .xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer { z-index: 7; }\n .xterm .xterm-decoration-overview-ruler { z-index: 8; position: absolute; top: 0; right: 0; pointer-events: none; }\n .xterm .xterm-decoration-top { z-index: 2; position: relative; }\n `;\n document.head.appendChild(style);\n}\n\nconst DEFAULT_THEME = {\n background: \"#111\",\n foreground: \"#e0e0e0\",\n cursor: \"#58a6ff\",\n selectionBackground: \"#264f78\",\n black: \"#484f58\",\n red: \"#ff7b72\",\n green: \"#3fb950\",\n yellow: \"#d29922\",\n blue: \"#58a6ff\",\n magenta: \"#bc8cff\",\n cyan: \"#39d353\",\n white: \"#b1bac4\",\n};\n\ninterface TerminalInfo {\n available: boolean;\n wsPort?: number;\n command?: string;\n error?: string;\n}\n\nexport function formatWebSocketHostname(hostname: string) {\n return hostname.includes(\":\") && !hostname.startsWith(\"[\")\n ? `[${hostname}]`\n : hostname;\n}\n\nexport function AgentTerminal({\n command,\n flags,\n wsUrl: wsUrlProp,\n hideInFrame = true,\n theme,\n fontSize = 12,\n className,\n style,\n onConnectionChange,\n onAgentRunningChange,\n}: AgentTerminalProps) {\n const termRef = useRef<HTMLDivElement>(null);\n const [connected, setConnected] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [inFrame, setInFrame] = useState(false);\n\n // Check frame state after mount (postMessage is async)\n useEffect(() => {\n if (!hideInFrame) return;\n // Check immediately and also after a short delay for the postMessage to arrive\n const check = () => {\n if (getFrameOrigin()) setInFrame(true);\n };\n check();\n const timer = setTimeout(check, 500);\n return () => clearTimeout(timer);\n }, [hideInFrame]);\n\n // Notify parent of connection changes\n useEffect(() => {\n onConnectionChange?.(connected);\n }, [connected, onConnectionChange]);\n\n // Main terminal setup\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n if (hideInFrame && inFrame) return;\n\n const container = termRef.current;\n if (!container) return;\n\n let disposed = false;\n let ws: WebSocket | null = null;\n let cleanupMessageHandler: (() => void) | null = null;\n\n async function init() {\n // Dynamic imports for SSR safety\n const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all(\n [\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n import(\"@xterm/addon-web-links\"),\n ],\n );\n\n if (disposed || !container) return;\n\n injectXtermCss();\n\n const term = new Terminal({\n cursorBlink: true,\n fontSize,\n fontFamily: \"'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, monospace\",\n theme: { ...DEFAULT_THEME, ...theme },\n });\n\n const fitAddon = new FitAddon();\n const webLinksAddon = new WebLinksAddon((_event, uri) => {\n window.open(uri, \"_blank\", \"noopener\");\n });\n\n term.loadAddon(fitAddon);\n term.loadAddon(webLinksAddon);\n term.open(container);\n\n let fitPending = false;\n function fitAndResize() {\n if (fitPending) return;\n fitPending = true;\n requestAnimationFrame(() => {\n fitPending = false;\n if (\n disposed ||\n !container.isConnected ||\n container.clientWidth <= 0 ||\n container.clientHeight <= 0\n ) {\n return;\n }\n try {\n fitAddon.fit();\n sendResize();\n } catch {}\n });\n }\n\n fitAndResize();\n const initialFitTimers = [\n setTimeout(fitAndResize, 50),\n setTimeout(fitAndResize, 250),\n ];\n\n const handleVisibilityOrFocus = () => fitAndResize();\n window.addEventListener(\"focus\", handleVisibilityOrFocus);\n document.addEventListener(\"visibilitychange\", handleVisibilityOrFocus);\n\n // Resize observer for auto-fitting\n const resizeObserver = new ResizeObserver(() => {\n fitAndResize();\n });\n resizeObserver.observe(container);\n\n let terminalDisposed = false;\n function disposeTerminal() {\n if (terminalDisposed) return;\n terminalDisposed = true;\n initialFitTimers.forEach(clearTimeout);\n window.removeEventListener(\"focus\", handleVisibilityOrFocus);\n document.removeEventListener(\n \"visibilitychange\",\n handleVisibilityOrFocus,\n );\n resizeObserver.disconnect();\n term.dispose();\n }\n\n // Discover WebSocket URL\n let wsUrl = wsUrlProp;\n let resolvedCommand = command;\n if (!wsUrl) {\n try {\n const res = await fetch(\n agentNativePath(\"/_agent-native/agent-terminal-info\"),\n );\n const info: TerminalInfo = await res.json();\n if (!info.available) {\n setError(info.error || \"Agent terminal not available\");\n disposeTerminal();\n return;\n }\n const protocol = location.protocol === \"https:\" ? \"wss:\" : \"ws:\";\n const host = formatWebSocketHostname(location.hostname);\n wsUrl = `${protocol}//${host}:${info.wsPort}/ws`;\n if (!resolvedCommand && info.command) {\n resolvedCommand = info.command;\n }\n } catch (err) {\n setError(\"Failed to discover terminal server\");\n disposeTerminal();\n return;\n }\n }\n\n // Build WebSocket URL with query params\n const qs = new URLSearchParams();\n if (resolvedCommand) qs.set(\"command\", resolvedCommand);\n if (flags) qs.set(\"flags\", flags);\n const qsStr = qs.toString();\n const fullWsUrl = qsStr ? `${wsUrl}?${qsStr}` : wsUrl;\n\n term.write(\n `\\x1b[2m[terminal] Starting ${resolvedCommand || \"CLI\"}...\\x1b[0m\\r\\n`,\n );\n\n // Connect WebSocket\n let agentRunning = false;\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let connectionId = 0;\n\n function sendResize() {\n if (ws && ws.readyState === WebSocket.OPEN && term) {\n ws.send(\n JSON.stringify({\n type: \"resize\",\n cols: term.cols,\n rows: term.rows,\n }),\n );\n }\n }\n\n function notifyAgentRunning(running: boolean) {\n onAgentRunningChange?.(running);\n window.dispatchEvent(\n new CustomEvent(\"agentNative.chatRunning\", {\n detail: { isRunning: running },\n }),\n );\n }\n\n function connect(url: string) {\n const thisId = ++connectionId;\n\n if (ws) {\n ws.close();\n ws = null;\n }\n\n const socket = new WebSocket(url);\n socket.binaryType = \"arraybuffer\";\n ws = socket;\n\n socket.onopen = () => {\n setConnected(true);\n setError(null);\n socket.send(\n JSON.stringify({\n type: \"resize\",\n cols: term.cols,\n rows: term.rows,\n }),\n );\n };\n\n socket.onmessage = (event) => {\n const data =\n event.data instanceof ArrayBuffer\n ? new TextDecoder().decode(event.data)\n : event.data;\n\n // Check for setup-status JSON messages\n try {\n const msg = JSON.parse(data);\n if (msg.type === \"setup-status\") {\n if (msg.status === \"not-found\" || msg.status === \"failed\") {\n setError(msg.message);\n // Bump connectionId to suppress reconnect on close\n connectionId++;\n }\n return;\n }\n } catch {\n // Not JSON — regular terminal output\n }\n\n setError(null);\n term.write(data);\n\n // Idle detection — prompt or cursor visible means agent stopped\n if (data.includes(\"❯\") || data.includes(\"\\x1b[?25h\")) {\n if (idleTimer) clearTimeout(idleTimer);\n idleTimer = setTimeout(() => {\n if (agentRunning) {\n agentRunning = false;\n notifyAgentRunning(false);\n }\n }, 600);\n } else if (agentRunning) {\n if (idleTimer) clearTimeout(idleTimer);\n }\n };\n\n socket.onclose = () => {\n setConnected(false);\n if (connectionId === thisId && !disposed) {\n term.write(\n \"\\r\\n\\x1b[31m[terminal] Connection closed. Reconnecting in 3s...\\x1b[0m\\r\\n\",\n );\n setTimeout(() => {\n if (connectionId === thisId && !disposed) {\n connect(url);\n }\n }, 3000);\n }\n };\n\n socket.onerror = () => socket.close();\n }\n\n // Terminal input → WebSocket\n term.onData((data) => {\n if (ws && ws.readyState === WebSocket.OPEN) {\n ws.send(data);\n }\n });\n\n // Chat bridge integration — listen for sendToAgentChat messages\n const messageHandler = (event: MessageEvent) => {\n if (!isTrustedFrameMessage(event)) return;\n if (event.data?.type === \"agentNative.submitChat\") {\n const message = event.data.data?.message;\n if (message && ws && ws.readyState === WebSocket.OPEN) {\n ws.send(message + \"\\r\");\n agentRunning = true;\n notifyAgentRunning(true);\n }\n }\n };\n window.addEventListener(\"message\", messageHandler);\n cleanupMessageHandler = () =>\n window.removeEventListener(\"message\", messageHandler);\n\n connect(fullWsUrl);\n\n // Store cleanup references\n return () => {\n disposed = true;\n connectionId++;\n if (idleTimer) clearTimeout(idleTimer);\n disposeTerminal();\n if (ws) {\n ws.close();\n ws = null;\n }\n };\n }\n\n let cleanup: (() => void) | undefined;\n init().then((fn) => {\n cleanup = fn;\n });\n\n return () => {\n disposed = true;\n cleanup?.();\n cleanupMessageHandler?.();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [hideInFrame, inFrame, command, flags, wsUrlProp]);\n\n if (hideInFrame && inFrame) {\n return null;\n }\n\n const terminalBackground = theme?.background ?? DEFAULT_THEME.background;\n const mergedStyle = {\n ...style,\n background: terminalBackground,\n backgroundColor: terminalBackground,\n };\n\n return (\n <div\n ref={termRef}\n className={className}\n style={{\n width: \"100%\",\n height: \"100%\",\n padding: \"4px 12px\",\n position: \"relative\",\n ...mergedStyle,\n }}\n >\n {error && (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n backgroundColor: \"#111\",\n color: \"#ff7b72\",\n fontSize: \"13px\",\n fontFamily: \"monospace\",\n padding: \"20px\",\n textAlign: \"center\",\n zIndex: 1,\n }}\n >\n {error}\n </div>\n )}\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-models.d.ts","sourceRoot":"","sources":["../../src/client/use-chat-models.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,gBAAgB,EAAE,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,eAAe,CAAC;IAChC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,UAAU,OAAO;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AA2BD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,UAAgC,GACjC,GAAE,OAAY,GAAG,mBAAmB,CAgMpC"}
1
+ {"version":3,"file":"use-chat-models.d.ts","sourceRoot":"","sources":["../../src/client/use-chat-models.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,eAAe,EACrB,MAAM,+BAA+B,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,eAAe,EAAE,gBAAgB,EAAE,CAAC;IACpC,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,eAAe,CAAC;IAChC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACvD,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,UAAU,OAAO;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AA2BD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAC5B,UAAgC,GACjC,GAAE,OAAY,GAAG,mBAAmB,CA8OpC"}
@@ -1,4 +1,4 @@
1
- import { useCallback, useEffect, useState } from "react";
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
2
  import { agentNativePath } from "./api-path.js";
3
3
  import { DEFAULT_MODEL } from "../agent/default-model.js";
4
4
  import { getReasoningEffortOptionsForModel, } from "../shared/reasoning-effort.js";
@@ -35,6 +35,18 @@ export function useChatModels({ storageKey = DEFAULT_STORAGE_KEY, } = {}) {
35
35
  const [selectedModel, setSelectedModel] = useState(initialPersisted.model ?? DEFAULT_MODEL);
36
36
  const [selectedEngine, setSelectedEngine] = useState(initialPersisted.engine ?? "");
37
37
  const [selectedEffort, setSelectedEffort] = useState(initialPersisted.effort ?? "auto");
38
+ const selectionRef = useRef({
39
+ selectedModel,
40
+ selectedEngine,
41
+ selectedEffort,
42
+ });
43
+ useEffect(() => {
44
+ selectionRef.current = {
45
+ selectedModel,
46
+ selectedEngine,
47
+ selectedEffort,
48
+ };
49
+ }, [selectedEffort, selectedEngine, selectedModel]);
38
50
  const onModelChange = useCallback((model, engine) => {
39
51
  const effortOptions = getReasoningEffortOptionsForModel(model);
40
52
  setSelectedModel(model);
@@ -161,11 +173,37 @@ export function useChatModels({ storageKey = DEFAULT_STORAGE_KEY, } = {}) {
161
173
  };
162
174
  });
163
175
  }
176
+ const nextDefaultModel = currentModel ?? DEFAULT_MODEL;
164
177
  setAvailableModels(groups);
165
- setDefaultModel(currentModel ?? DEFAULT_MODEL);
178
+ setDefaultModel(nextDefaultModel);
179
+ const selection = selectionRef.current;
180
+ const selectedGroup = groups.find((group) => group.models.includes(selection.selectedModel) &&
181
+ (!selection.selectedEngine ||
182
+ group.engine === selection.selectedEngine));
183
+ if (!selectedGroup) {
184
+ const defaultGroup = groups.find((group) => group.models.includes(nextDefaultModel)) ??
185
+ groups[0];
186
+ const nextModel = defaultGroup?.models.find((model) => model === nextDefaultModel) ??
187
+ defaultGroup?.models[0] ??
188
+ nextDefaultModel;
189
+ const nextEngine = defaultGroup?.engine ?? "";
190
+ const effortOptions = getReasoningEffortOptionsForModel(nextModel);
191
+ const nextEffort = selection.selectedEffort === "auto" ||
192
+ effortOptions.includes(selection.selectedEffort)
193
+ ? selection.selectedEffort
194
+ : "auto";
195
+ setSelectedModel(nextModel);
196
+ setSelectedEngine(nextEngine);
197
+ setSelectedEffort(nextEffort);
198
+ writePersisted(storageKey, {
199
+ model: nextModel,
200
+ engine: nextEngine,
201
+ effort: nextEffort,
202
+ });
203
+ }
166
204
  })
167
205
  .catch(() => { });
168
- }, []);
206
+ }, [storageKey]);
169
207
  useEffect(() => {
170
208
  refreshEngines();
171
209
  }, [refreshEngines]);
@@ -1 +1 @@
1
- {"version":3,"file":"use-chat-models.js","sourceRoot":"","sources":["../../src/client/use-chat-models.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useState } from \"react\";\nimport { agentNativePath } from \"./api-path.js\";\nimport { DEFAULT_MODEL } from \"../agent/default-model.js\";\nimport {\n getReasoningEffortOptionsForModel,\n type ReasoningEffort,\n} from \"../shared/reasoning-effort.js\";\n\nexport interface EngineModelGroup {\n engine: string;\n label: string;\n models: string[];\n configured: boolean;\n}\n\nexport interface UseChatModelsResult {\n availableModels: EngineModelGroup[];\n defaultModel: string;\n selectedModel: string;\n selectedEngine: string;\n selectedEffort: ReasoningEffort;\n onModelChange: (model: string, engine: string) => void;\n onEffortChange: (effort: ReasoningEffort) => void;\n refreshEngines: () => void;\n}\n\ninterface Options {\n /**\n * localStorage key used to persist the user's model + effort selection across\n * page loads. Pass `null` to disable persistence.\n */\n storageKey?: string | null;\n}\n\nconst DEFAULT_STORAGE_KEY = \"agent-native:chat-models:selection\";\n\ninterface PersistedSelection {\n model?: string;\n engine?: string;\n effort?: ReasoningEffort;\n}\n\nfunction readPersisted(key: string | null): PersistedSelection {\n if (!key || typeof window === \"undefined\") return {};\n try {\n const raw = window.localStorage.getItem(key);\n return raw ? (JSON.parse(raw) as PersistedSelection) : {};\n } catch {\n return {};\n }\n}\n\nfunction writePersisted(key: string | null, value: PersistedSelection) {\n if (!key || typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n } catch {}\n}\n\n/**\n * Fetches available engines/models from the agent server and exposes the same\n * model picker state that `MultiTabAssistantChat` wires up — for surfaces like\n * the Dispatch homepage hero composer that need an identical model picker\n * without mounting the full tabbed chat.\n */\nexport function useChatModels({\n storageKey = DEFAULT_STORAGE_KEY,\n}: Options = {}): UseChatModelsResult {\n const [availableModels, setAvailableModels] = useState<EngineModelGroup[]>(\n [],\n );\n const [defaultModel, setDefaultModel] = useState(DEFAULT_MODEL);\n\n const initialPersisted = readPersisted(storageKey);\n const [selectedModel, setSelectedModel] = useState<string>(\n initialPersisted.model ?? DEFAULT_MODEL,\n );\n const [selectedEngine, setSelectedEngine] = useState<string>(\n initialPersisted.engine ?? \"\",\n );\n const [selectedEffort, setSelectedEffort] = useState<ReasoningEffort>(\n initialPersisted.effort ?? \"auto\",\n );\n\n const onModelChange = useCallback(\n (model: string, engine: string) => {\n const effortOptions = getReasoningEffortOptionsForModel(model);\n setSelectedModel(model);\n setSelectedEngine(engine);\n setSelectedEffort((prevEffort) => {\n const next =\n prevEffort === \"auto\" || effortOptions.includes(prevEffort)\n ? prevEffort\n : \"auto\";\n writePersisted(storageKey, { model, engine, effort: next });\n return next;\n });\n },\n [storageKey],\n );\n\n const onEffortChange = useCallback(\n (effort: ReasoningEffort) => {\n setSelectedEffort(effort);\n writePersisted(storageKey, {\n model: selectedModel,\n engine: selectedEngine,\n effort,\n });\n },\n [selectedEngine, selectedModel, storageKey],\n );\n\n const refreshEngines = useCallback(() => {\n Promise.all([\n fetch(agentNativePath(\"/_agent-native/actions/manage-agent-engine\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action: \"list\" }),\n }).then((r) => (r.ok ? r.json() : null)),\n fetch(agentNativePath(\"/_agent-native/env-status\"))\n .then((r) => (r.ok ? r.json() : []))\n .catch(() => []),\n fetch(agentNativePath(\"/_agent-native/builder/status\"))\n .then((r) => (r.ok ? r.json() : null))\n .catch(() => null),\n ])\n .then(([enginesData, envKeys, builderStatus]) => {\n if (!enginesData?.engines) return;\n const configuredKeys = new Set(\n (envKeys as Array<{ key: string; configured: boolean }>)\n .filter((k) => k.configured)\n .map((k) => k.key),\n );\n const builderConnected = builderStatus?.configured === true;\n const currentEngineName: string | undefined =\n enginesData.current?.engine;\n const currentModel: string | undefined = enginesData.current?.model;\n\n let groups: EngineModelGroup[];\n\n if (builderConnected) {\n const builderEngine = enginesData.engines.find(\n (e: any) => e.name === \"builder\",\n );\n const builderModels: string[] = builderEngine?.supportedModels ?? [];\n const claude = builderModels.filter((m: string) =>\n m.startsWith(\"claude-\"),\n );\n const openai = builderModels.filter((m: string) =>\n m.startsWith(\"gpt-\"),\n );\n const gemini = builderModels.filter((m: string) =>\n m.startsWith(\"gemini-\"),\n );\n const other = builderModels.filter(\n (m: string) =>\n !m.startsWith(\"claude-\") &&\n !m.startsWith(\"gpt-\") &&\n !m.startsWith(\"gemini-\"),\n );\n\n groups = [\n ...(claude.length\n ? [\n {\n engine: \"builder\",\n label: \"Claude\",\n models: claude,\n configured: true,\n },\n ]\n : []),\n ...(openai.length\n ? [\n {\n engine: \"builder\",\n label: \"OpenAI\",\n models: openai,\n configured: true,\n },\n ]\n : []),\n ...(gemini.length\n ? [\n {\n engine: \"builder\",\n label: \"Gemini\",\n models: gemini,\n configured: true,\n },\n ]\n : []),\n ...(other.length\n ? [\n {\n engine: \"builder\",\n label: \"More\",\n models: other,\n configured: true,\n },\n ]\n : []),\n ];\n\n if (currentModel && !builderModels.includes(currentModel)) {\n const firstGroup = groups[0];\n if (firstGroup) firstGroup.models.unshift(currentModel);\n }\n } else {\n const allowedEngines = new Set([\n \"anthropic\",\n \"ai-sdk:openai\",\n \"ai-sdk:google\",\n ]);\n groups = enginesData.engines\n .filter((e: any) => allowedEngines.has(e.name))\n .map((e: any) => {\n const models = [...e.supportedModels];\n if (\n e.name === currentEngineName &&\n currentModel &&\n !models.includes(currentModel)\n ) {\n models.unshift(currentModel);\n }\n return {\n engine: e.name,\n label: e.label,\n models,\n configured:\n e.requiredEnvVars.length === 0 ||\n e.requiredEnvVars.some((v: string) =>\n configuredKeys.has(v),\n ) ||\n e.name === currentEngineName,\n };\n });\n }\n setAvailableModels(groups);\n setDefaultModel(currentModel ?? DEFAULT_MODEL);\n })\n .catch(() => {});\n }, []);\n\n useEffect(() => {\n refreshEngines();\n }, [refreshEngines]);\n\n return {\n availableModels,\n defaultModel,\n selectedModel,\n selectedEngine,\n selectedEffort,\n onModelChange,\n onEffortChange,\n refreshEngines,\n };\n}\n"]}
1
+ {"version":3,"file":"use-chat-models.js","sourceRoot":"","sources":["../../src/client/use-chat-models.ts"],"names":[],"mappings":"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","sourcesContent":["import { useCallback, useEffect, useRef, useState } from \"react\";\nimport { agentNativePath } from \"./api-path.js\";\nimport { DEFAULT_MODEL } from \"../agent/default-model.js\";\nimport {\n getReasoningEffortOptionsForModel,\n type ReasoningEffort,\n} from \"../shared/reasoning-effort.js\";\n\nexport interface EngineModelGroup {\n engine: string;\n label: string;\n models: string[];\n configured: boolean;\n}\n\nexport interface UseChatModelsResult {\n availableModels: EngineModelGroup[];\n defaultModel: string;\n selectedModel: string;\n selectedEngine: string;\n selectedEffort: ReasoningEffort;\n onModelChange: (model: string, engine: string) => void;\n onEffortChange: (effort: ReasoningEffort) => void;\n refreshEngines: () => void;\n}\n\ninterface Options {\n /**\n * localStorage key used to persist the user's model + effort selection across\n * page loads. Pass `null` to disable persistence.\n */\n storageKey?: string | null;\n}\n\nconst DEFAULT_STORAGE_KEY = \"agent-native:chat-models:selection\";\n\ninterface PersistedSelection {\n model?: string;\n engine?: string;\n effort?: ReasoningEffort;\n}\n\nfunction readPersisted(key: string | null): PersistedSelection {\n if (!key || typeof window === \"undefined\") return {};\n try {\n const raw = window.localStorage.getItem(key);\n return raw ? (JSON.parse(raw) as PersistedSelection) : {};\n } catch {\n return {};\n }\n}\n\nfunction writePersisted(key: string | null, value: PersistedSelection) {\n if (!key || typeof window === \"undefined\") return;\n try {\n window.localStorage.setItem(key, JSON.stringify(value));\n } catch {}\n}\n\n/**\n * Fetches available engines/models from the agent server and exposes the same\n * model picker state that `MultiTabAssistantChat` wires up — for surfaces like\n * the Dispatch homepage hero composer that need an identical model picker\n * without mounting the full tabbed chat.\n */\nexport function useChatModels({\n storageKey = DEFAULT_STORAGE_KEY,\n}: Options = {}): UseChatModelsResult {\n const [availableModels, setAvailableModels] = useState<EngineModelGroup[]>(\n [],\n );\n const [defaultModel, setDefaultModel] = useState(DEFAULT_MODEL);\n\n const initialPersisted = readPersisted(storageKey);\n const [selectedModel, setSelectedModel] = useState<string>(\n initialPersisted.model ?? DEFAULT_MODEL,\n );\n const [selectedEngine, setSelectedEngine] = useState<string>(\n initialPersisted.engine ?? \"\",\n );\n const [selectedEffort, setSelectedEffort] = useState<ReasoningEffort>(\n initialPersisted.effort ?? \"auto\",\n );\n const selectionRef = useRef({\n selectedModel,\n selectedEngine,\n selectedEffort,\n });\n\n useEffect(() => {\n selectionRef.current = {\n selectedModel,\n selectedEngine,\n selectedEffort,\n };\n }, [selectedEffort, selectedEngine, selectedModel]);\n\n const onModelChange = useCallback(\n (model: string, engine: string) => {\n const effortOptions = getReasoningEffortOptionsForModel(model);\n setSelectedModel(model);\n setSelectedEngine(engine);\n setSelectedEffort((prevEffort) => {\n const next =\n prevEffort === \"auto\" || effortOptions.includes(prevEffort)\n ? prevEffort\n : \"auto\";\n writePersisted(storageKey, { model, engine, effort: next });\n return next;\n });\n },\n [storageKey],\n );\n\n const onEffortChange = useCallback(\n (effort: ReasoningEffort) => {\n setSelectedEffort(effort);\n writePersisted(storageKey, {\n model: selectedModel,\n engine: selectedEngine,\n effort,\n });\n },\n [selectedEngine, selectedModel, storageKey],\n );\n\n const refreshEngines = useCallback(() => {\n Promise.all([\n fetch(agentNativePath(\"/_agent-native/actions/manage-agent-engine\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ action: \"list\" }),\n }).then((r) => (r.ok ? r.json() : null)),\n fetch(agentNativePath(\"/_agent-native/env-status\"))\n .then((r) => (r.ok ? r.json() : []))\n .catch(() => []),\n fetch(agentNativePath(\"/_agent-native/builder/status\"))\n .then((r) => (r.ok ? r.json() : null))\n .catch(() => null),\n ])\n .then(([enginesData, envKeys, builderStatus]) => {\n if (!enginesData?.engines) return;\n const configuredKeys = new Set(\n (envKeys as Array<{ key: string; configured: boolean }>)\n .filter((k) => k.configured)\n .map((k) => k.key),\n );\n const builderConnected = builderStatus?.configured === true;\n const currentEngineName: string | undefined =\n enginesData.current?.engine;\n const currentModel: string | undefined = enginesData.current?.model;\n\n let groups: EngineModelGroup[];\n\n if (builderConnected) {\n const builderEngine = enginesData.engines.find(\n (e: any) => e.name === \"builder\",\n );\n const builderModels: string[] = builderEngine?.supportedModels ?? [];\n const claude = builderModels.filter((m: string) =>\n m.startsWith(\"claude-\"),\n );\n const openai = builderModels.filter((m: string) =>\n m.startsWith(\"gpt-\"),\n );\n const gemini = builderModels.filter((m: string) =>\n m.startsWith(\"gemini-\"),\n );\n const other = builderModels.filter(\n (m: string) =>\n !m.startsWith(\"claude-\") &&\n !m.startsWith(\"gpt-\") &&\n !m.startsWith(\"gemini-\"),\n );\n\n groups = [\n ...(claude.length\n ? [\n {\n engine: \"builder\",\n label: \"Claude\",\n models: claude,\n configured: true,\n },\n ]\n : []),\n ...(openai.length\n ? [\n {\n engine: \"builder\",\n label: \"OpenAI\",\n models: openai,\n configured: true,\n },\n ]\n : []),\n ...(gemini.length\n ? [\n {\n engine: \"builder\",\n label: \"Gemini\",\n models: gemini,\n configured: true,\n },\n ]\n : []),\n ...(other.length\n ? [\n {\n engine: \"builder\",\n label: \"More\",\n models: other,\n configured: true,\n },\n ]\n : []),\n ];\n\n if (currentModel && !builderModels.includes(currentModel)) {\n const firstGroup = groups[0];\n if (firstGroup) firstGroup.models.unshift(currentModel);\n }\n } else {\n const allowedEngines = new Set([\n \"anthropic\",\n \"ai-sdk:openai\",\n \"ai-sdk:google\",\n ]);\n groups = enginesData.engines\n .filter((e: any) => allowedEngines.has(e.name))\n .map((e: any) => {\n const models = [...e.supportedModels];\n if (\n e.name === currentEngineName &&\n currentModel &&\n !models.includes(currentModel)\n ) {\n models.unshift(currentModel);\n }\n return {\n engine: e.name,\n label: e.label,\n models,\n configured:\n e.requiredEnvVars.length === 0 ||\n e.requiredEnvVars.some((v: string) =>\n configuredKeys.has(v),\n ) ||\n e.name === currentEngineName,\n };\n });\n }\n const nextDefaultModel = currentModel ?? DEFAULT_MODEL;\n setAvailableModels(groups);\n setDefaultModel(nextDefaultModel);\n\n const selection = selectionRef.current;\n const selectedGroup = groups.find(\n (group) =>\n group.models.includes(selection.selectedModel) &&\n (!selection.selectedEngine ||\n group.engine === selection.selectedEngine),\n );\n if (!selectedGroup) {\n const defaultGroup =\n groups.find((group) => group.models.includes(nextDefaultModel)) ??\n groups[0];\n const nextModel =\n defaultGroup?.models.find((model) => model === nextDefaultModel) ??\n defaultGroup?.models[0] ??\n nextDefaultModel;\n const nextEngine = defaultGroup?.engine ?? \"\";\n const effortOptions = getReasoningEffortOptionsForModel(nextModel);\n const nextEffort =\n selection.selectedEffort === \"auto\" ||\n effortOptions.includes(selection.selectedEffort)\n ? selection.selectedEffort\n : \"auto\";\n setSelectedModel(nextModel);\n setSelectedEngine(nextEngine);\n setSelectedEffort(nextEffort);\n writePersisted(storageKey, {\n model: nextModel,\n engine: nextEngine,\n effort: nextEffort,\n });\n }\n })\n .catch(() => {});\n }, [storageKey]);\n\n useEffect(() => {\n refreshEngines();\n }, [refreshEngines]);\n\n return {\n availableModels,\n defaultModel,\n selectedModel,\n selectedEngine,\n selectedEffort,\n onModelChange,\n onEffortChange,\n refreshEngines,\n };\n}\n"]}