@agent-native/core 0.32.2 → 0.32.18

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 (241) hide show
  1. package/README.md +3 -1
  2. package/dist/agent/run-store.d.ts.map +1 -1
  3. package/dist/agent/run-store.js +48 -10
  4. package/dist/agent/run-store.js.map +1 -1
  5. package/dist/agent/thread-data-builder.d.ts +12 -0
  6. package/dist/agent/thread-data-builder.d.ts.map +1 -1
  7. package/dist/agent/thread-data-builder.js +104 -6
  8. package/dist/agent/thread-data-builder.js.map +1 -1
  9. package/dist/cli/app-skill.js +2 -2
  10. package/dist/cli/app-skill.js.map +1 -1
  11. package/dist/cli/code-agent-executor.d.ts.map +1 -1
  12. package/dist/cli/code-agent-executor.js +6 -1
  13. package/dist/cli/code-agent-executor.js.map +1 -1
  14. package/dist/cli/code-agent-output-smoother.d.ts +7 -0
  15. package/dist/cli/code-agent-output-smoother.d.ts.map +1 -0
  16. package/dist/cli/code-agent-output-smoother.js +111 -0
  17. package/dist/cli/code-agent-output-smoother.js.map +1 -0
  18. package/dist/cli/connect.d.ts.map +1 -1
  19. package/dist/cli/connect.js +5 -0
  20. package/dist/cli/connect.js.map +1 -1
  21. package/dist/cli/migrate.d.ts.map +1 -1
  22. package/dist/cli/migrate.js +17 -42
  23. package/dist/cli/migrate.js.map +1 -1
  24. package/dist/cli/skills.d.ts +23 -2
  25. package/dist/cli/skills.d.ts.map +1 -1
  26. package/dist/cli/skills.js +405 -41
  27. package/dist/cli/skills.js.map +1 -1
  28. package/dist/cli/templates-meta.d.ts.map +1 -1
  29. package/dist/cli/templates-meta.js +7 -105
  30. package/dist/cli/templates-meta.js.map +1 -1
  31. package/dist/client/AgentPanel.d.ts.map +1 -1
  32. package/dist/client/AgentPanel.js +41 -7
  33. package/dist/client/AgentPanel.js.map +1 -1
  34. package/dist/client/AgentTaskCard.d.ts.map +1 -1
  35. package/dist/client/AgentTaskCard.js +0 -28
  36. package/dist/client/AgentTaskCard.js.map +1 -1
  37. package/dist/client/AssistantChat.d.ts +8 -23
  38. package/dist/client/AssistantChat.d.ts.map +1 -1
  39. package/dist/client/AssistantChat.js +359 -205
  40. package/dist/client/AssistantChat.js.map +1 -1
  41. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  42. package/dist/client/MultiTabAssistantChat.js +254 -14
  43. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  44. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  45. package/dist/client/agent-chat-adapter.js +14 -9
  46. package/dist/client/agent-chat-adapter.js.map +1 -1
  47. package/dist/client/agent-chat.d.ts +24 -0
  48. package/dist/client/agent-chat.d.ts.map +1 -1
  49. package/dist/client/agent-chat.js +73 -0
  50. package/dist/client/agent-chat.js.map +1 -1
  51. package/dist/client/assistant-ui-recovery.d.ts +34 -0
  52. package/dist/client/assistant-ui-recovery.d.ts.map +1 -0
  53. package/dist/client/assistant-ui-recovery.js +122 -0
  54. package/dist/client/assistant-ui-recovery.js.map +1 -0
  55. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  56. package/dist/client/composer/PromptComposer.js +7 -1
  57. package/dist/client/composer/PromptComposer.js.map +1 -1
  58. package/dist/client/composer/TiptapComposer.d.ts +7 -1
  59. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  60. package/dist/client/composer/TiptapComposer.js +22 -2
  61. package/dist/client/composer/TiptapComposer.js.map +1 -1
  62. package/dist/client/frame-protocol.d.ts +6 -2
  63. package/dist/client/frame-protocol.d.ts.map +1 -1
  64. package/dist/client/frame-protocol.js.map +1 -1
  65. package/dist/client/index.d.ts +2 -1
  66. package/dist/client/index.d.ts.map +1 -1
  67. package/dist/client/index.js +2 -1
  68. package/dist/client/index.js.map +1 -1
  69. package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
  70. package/dist/client/org/OrgSwitcher.js +2 -1
  71. package/dist/client/org/OrgSwitcher.js.map +1 -1
  72. package/dist/client/progress/RunsTray.d.ts +13 -3
  73. package/dist/client/progress/RunsTray.d.ts.map +1 -1
  74. package/dist/client/progress/RunsTray.js +105 -36
  75. package/dist/client/progress/RunsTray.js.map +1 -1
  76. package/dist/client/route-warmup.d.ts +61 -0
  77. package/dist/client/route-warmup.d.ts.map +1 -0
  78. package/dist/client/route-warmup.js +456 -0
  79. package/dist/client/route-warmup.js.map +1 -0
  80. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  81. package/dist/client/settings/SettingsPanel.js +2 -1
  82. package/dist/client/settings/SettingsPanel.js.map +1 -1
  83. package/dist/client/settings/useBuilderStatus.d.ts +5 -0
  84. package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
  85. package/dist/client/settings/useBuilderStatus.js +10 -4
  86. package/dist/client/settings/useBuilderStatus.js.map +1 -1
  87. package/dist/client/use-action.d.ts +1 -0
  88. package/dist/client/use-action.d.ts.map +1 -1
  89. package/dist/client/use-action.js +22 -4
  90. package/dist/client/use-action.js.map +1 -1
  91. package/dist/code-agents/background-run.d.ts +2 -0
  92. package/dist/code-agents/background-run.d.ts.map +1 -1
  93. package/dist/code-agents/background-run.js.map +1 -1
  94. package/dist/db/client.d.ts +1 -1
  95. package/dist/db/client.d.ts.map +1 -1
  96. package/dist/db/client.js +25 -1
  97. package/dist/db/client.js.map +1 -1
  98. package/dist/deploy/build.d.ts +4 -0
  99. package/dist/deploy/build.d.ts.map +1 -1
  100. package/dist/deploy/build.js +171 -14
  101. package/dist/deploy/build.js.map +1 -1
  102. package/dist/deploy/immutable-assets.d.ts +1 -0
  103. package/dist/deploy/immutable-assets.d.ts.map +1 -1
  104. package/dist/deploy/immutable-assets.js +1 -0
  105. package/dist/deploy/immutable-assets.js.map +1 -1
  106. package/dist/index.browser.d.ts +1 -1
  107. package/dist/index.browser.d.ts.map +1 -1
  108. package/dist/index.browser.js +1 -1
  109. package/dist/index.browser.js.map +1 -1
  110. package/dist/index.d.ts +1 -1
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +1 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/mcp/connect-route.d.ts.map +1 -1
  115. package/dist/mcp/connect-route.js +118 -82
  116. package/dist/mcp/connect-route.js.map +1 -1
  117. package/dist/progress/routes.d.ts.map +1 -1
  118. package/dist/progress/routes.js +1 -0
  119. package/dist/progress/routes.js.map +1 -1
  120. package/dist/progress/store.d.ts +13 -0
  121. package/dist/progress/store.d.ts.map +1 -1
  122. package/dist/progress/store.js +18 -0
  123. package/dist/progress/store.js.map +1 -1
  124. package/dist/progress/types.d.ts +2 -0
  125. package/dist/progress/types.d.ts.map +1 -1
  126. package/dist/progress/types.js.map +1 -1
  127. package/dist/scripts/db/wipe-leaked-builder-keys.d.ts +2 -2
  128. package/dist/scripts/db/wipe-leaked-builder-keys.d.ts.map +1 -1
  129. package/dist/scripts/db/wipe-leaked-builder-keys.js +14 -3
  130. package/dist/scripts/db/wipe-leaked-builder-keys.js.map +1 -1
  131. package/dist/server/action-routes.d.ts +1 -0
  132. package/dist/server/action-routes.d.ts.map +1 -1
  133. package/dist/server/action-routes.js +36 -2
  134. package/dist/server/action-routes.js.map +1 -1
  135. package/dist/server/agent-chat-plugin.d.ts +5 -0
  136. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  137. package/dist/server/agent-chat-plugin.js +131 -26
  138. package/dist/server/agent-chat-plugin.js.map +1 -1
  139. package/dist/server/agent-discovery.d.ts.map +1 -1
  140. package/dist/server/agent-discovery.js +14 -1
  141. package/dist/server/agent-discovery.js.map +1 -1
  142. package/dist/server/agent-teams-run-queue.d.ts +80 -0
  143. package/dist/server/agent-teams-run-queue.d.ts.map +1 -0
  144. package/dist/server/agent-teams-run-queue.js +208 -0
  145. package/dist/server/agent-teams-run-queue.js.map +1 -0
  146. package/dist/server/agent-teams.d.ts +67 -0
  147. package/dist/server/agent-teams.d.ts.map +1 -1
  148. package/dist/server/agent-teams.js +607 -180
  149. package/dist/server/agent-teams.js.map +1 -1
  150. package/dist/server/auth-marketing.d.ts.map +1 -1
  151. package/dist/server/auth-marketing.js +0 -64
  152. package/dist/server/auth-marketing.js.map +1 -1
  153. package/dist/server/auth.d.ts.map +1 -1
  154. package/dist/server/auth.js +67 -14
  155. package/dist/server/auth.js.map +1 -1
  156. package/dist/server/builder-browser.d.ts +12 -2
  157. package/dist/server/builder-browser.d.ts.map +1 -1
  158. package/dist/server/builder-browser.js +24 -0
  159. package/dist/server/builder-browser.js.map +1 -1
  160. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  161. package/dist/server/core-routes-plugin.js +66 -5
  162. package/dist/server/core-routes-plugin.js.map +1 -1
  163. package/dist/server/credential-provider.d.ts +10 -0
  164. package/dist/server/credential-provider.d.ts.map +1 -1
  165. package/dist/server/credential-provider.js +82 -3
  166. package/dist/server/credential-provider.js.map +1 -1
  167. package/dist/server/csrf.d.ts.map +1 -1
  168. package/dist/server/csrf.js +3 -0
  169. package/dist/server/csrf.js.map +1 -1
  170. package/dist/server/index.d.ts +1 -0
  171. package/dist/server/index.d.ts.map +1 -1
  172. package/dist/server/index.js +1 -0
  173. package/dist/server/index.js.map +1 -1
  174. package/dist/server/onboarding-html.d.ts +1 -0
  175. package/dist/server/onboarding-html.d.ts.map +1 -1
  176. package/dist/server/onboarding-html.js +14 -1
  177. package/dist/server/onboarding-html.js.map +1 -1
  178. package/dist/server/self-dispatch.d.ts +44 -0
  179. package/dist/server/self-dispatch.d.ts.map +1 -0
  180. package/dist/server/self-dispatch.js +113 -0
  181. package/dist/server/self-dispatch.js.map +1 -0
  182. package/dist/server/social-og-image.d.ts +14 -0
  183. package/dist/server/social-og-image.d.ts.map +1 -0
  184. package/dist/server/social-og-image.js +251 -0
  185. package/dist/server/social-og-image.js.map +1 -0
  186. package/dist/server/ssr-handler.d.ts +1 -1
  187. package/dist/server/ssr-handler.d.ts.map +1 -1
  188. package/dist/server/ssr-handler.js +27 -11
  189. package/dist/server/ssr-handler.js.map +1 -1
  190. package/dist/shared/cache-control.d.ts +7 -0
  191. package/dist/shared/cache-control.d.ts.map +1 -1
  192. package/dist/shared/cache-control.js +7 -0
  193. package/dist/shared/cache-control.js.map +1 -1
  194. package/dist/shared/index.d.ts +1 -1
  195. package/dist/shared/index.d.ts.map +1 -1
  196. package/dist/shared/index.js +1 -1
  197. package/dist/shared/index.js.map +1 -1
  198. package/dist/shared/route-warmup-config.d.ts +28 -0
  199. package/dist/shared/route-warmup-config.d.ts.map +1 -0
  200. package/dist/shared/route-warmup-config.js +58 -0
  201. package/dist/shared/route-warmup-config.js.map +1 -0
  202. package/dist/shared/social-meta.d.ts +5 -0
  203. package/dist/shared/social-meta.d.ts.map +1 -1
  204. package/dist/shared/social-meta.js +36 -2
  205. package/dist/shared/social-meta.js.map +1 -1
  206. package/dist/shared/streaming-text-smoothing.d.ts +12 -0
  207. package/dist/shared/streaming-text-smoothing.d.ts.map +1 -0
  208. package/dist/shared/streaming-text-smoothing.js +52 -0
  209. package/dist/shared/streaming-text-smoothing.js.map +1 -0
  210. package/dist/styles/agent-native.css +4 -4
  211. package/dist/templates/default/AGENTS.md +9 -4
  212. package/dist/templates/default/DEVELOPING.md +15 -1
  213. package/dist/templates/workspace-core/AGENTS.md +7 -3
  214. package/dist/templates/workspace-root/AGENTS.md +7 -3
  215. package/dist/vite/client.d.ts +13 -0
  216. package/dist/vite/client.d.ts.map +1 -1
  217. package/dist/vite/client.js +26 -0
  218. package/dist/vite/client.js.map +1 -1
  219. package/dist/vite/index.d.ts +1 -0
  220. package/dist/vite/index.d.ts.map +1 -1
  221. package/dist/vite/index.js.map +1 -1
  222. package/docs/content/client.md +62 -1
  223. package/docs/content/code-agents-ui.md +6 -13
  224. package/docs/content/context-awareness.md +186 -21
  225. package/docs/content/deployment.md +8 -11
  226. package/docs/content/dispatch.md +1 -1
  227. package/docs/content/external-agents.md +32 -2
  228. package/docs/content/migration-workbench.md +4 -21
  229. package/docs/content/multi-app-workspace.md +1 -1
  230. package/docs/content/recurring-jobs.md +1 -1
  231. package/docs/content/security.md +0 -1
  232. package/docs/content/sharing.md +1 -3
  233. package/docs/content/skills-guide.md +12 -10
  234. package/docs/content/template-assets.md +21 -1
  235. package/docs/content/template-design.md +23 -5
  236. package/docs/content/template-dispatch.md +1 -1
  237. package/package.json +2 -1
  238. package/src/templates/default/AGENTS.md +9 -4
  239. package/src/templates/default/DEVELOPING.md +15 -1
  240. package/src/templates/workspace-core/AGENTS.md +7 -3
  241. package/src/templates/workspace-root/AGENTS.md +7 -3
@@ -1,21 +1,27 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { agentNativePath } from "../api-path.js";
3
- import { useCallback, useEffect, useRef, useState } from "react";
4
- import { IconLoader2, IconCheck, IconX, IconClock } from "@tabler/icons-react";
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
4
+ import { IconAlertCircle, IconCheck, IconClock, IconExternalLink, IconLoader2, IconX, } from "@tabler/icons-react";
5
5
  import { usePausingInterval } from "../use-pausing-interval.js";
6
+ import { cn } from "../utils.js";
7
+ import { Popover, PopoverContent, PopoverTrigger, } from "../components/ui/popover.js";
8
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "../components/ui/tooltip.js";
6
9
  /**
7
- * Header-bar progress indicator. Shows a spinner icon with a count badge
8
- * when runs are active; opens a dropdown with live progress bars for each.
10
+ * Header-bar progress indicator. Shows a spinner icon or labeled Runs pill
11
+ * with a count badge when runs are active; opens a popover with live progress.
9
12
  * Same inline-header pattern as <NotificationsBell /> — drop it into the
10
13
  * header, no floating overlay over the main content.
11
14
  */
12
- export function RunsTray({ pollMs = 3000, limit = 5, hideWhenIdle = true, className, }) {
15
+ export function RunsTray({ pollMs = 3000, limit = 5, hideWhenIdle = true, showRecent, triggerVariant = "icon", onOpenThread, align = "end", className, }) {
13
16
  const [runs, setRuns] = useState([]);
14
17
  const [open, setOpen] = useState(false);
15
- const menuRef = useRef(null);
18
+ const includeRecent = showRecent ?? !hideWhenIdle;
16
19
  const refresh = useCallback(async () => {
17
20
  try {
18
- const res = await fetch(agentNativePath(`/_agent-native/runs?active=true&limit=${limit}`));
21
+ const query = new URLSearchParams({ limit: String(limit) });
22
+ if (!includeRecent)
23
+ query.set("active", "true");
24
+ const res = await fetch(agentNativePath(`/_agent-native/runs?${query.toString()}`));
19
25
  if (!res.ok)
20
26
  return;
21
27
  const rows = (await res.json());
@@ -24,7 +30,7 @@ export function RunsTray({ pollMs = 3000, limit = 5, hideWhenIdle = true, classN
24
30
  catch {
25
31
  // best-effort
26
32
  }
27
- }, [limit]);
33
+ }, [includeRecent, limit]);
28
34
  useEffect(() => {
29
35
  refresh();
30
36
  }, [refresh]);
@@ -43,31 +49,99 @@ export function RunsTray({ pollMs = 3000, limit = 5, hideWhenIdle = true, classN
43
49
  refresh();
44
50
  }
45
51
  }, [refresh]);
46
- useEffect(() => {
47
- if (!open)
48
- return;
49
- const onDocClick = (e) => {
50
- if (menuRef.current && !menuRef.current.contains(e.target)) {
51
- setOpen(false);
52
- }
53
- };
54
- document.addEventListener("mousedown", onDocClick);
55
- return () => document.removeEventListener("mousedown", onDocClick);
56
- }, [open]);
57
- // Close the dropdown when the last active run finishes.
58
- useEffect(() => {
59
- if (runs.length === 0 && open)
60
- setOpen(false);
61
- }, [runs.length, open]);
62
52
  const hasRuns = runs.length > 0;
53
+ const activeCount = useMemo(() => runs.filter((run) => run.status === "running").length, [runs]);
54
+ const failedCount = useMemo(() => runs.filter((run) => run.status === "failed").length, [runs]);
63
55
  if (!hasRuns && hideWhenIdle)
64
56
  return null;
65
- return (_jsxs("div", { ref: menuRef, className: "an-runs-tray relative inline-flex" + (className ? ` ${className}` : ""), children: [_jsxs("button", { type: "button", "aria-label": hasRuns
66
- ? `${runs.length} active run${runs.length > 1 ? "s" : ""}`
67
- : "No active runs", "aria-expanded": open, onClick: () => setOpen((v) => !v), className: "an-runs-tray__trigger relative inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/40 hover:text-foreground", children: [_jsx(IconLoader2, { size: 18, className: hasRuns ? "animate-spin text-primary" : "", "aria-hidden": true }), hasRuns ? (_jsx("span", { "aria-hidden": true, className: "an-runs-tray__badge absolute -right-0.5 -top-0.5 rounded-full bg-primary px-1 text-[10px] leading-[14px] font-medium text-primary-foreground", children: runs.length > 9 ? "9+" : runs.length })) : null] }), open && hasRuns ? (_jsxs("div", { role: "menu", className: "an-runs-tray__menu absolute right-0 top-full z-50 mt-2 w-80 rounded-md border border-border bg-popover text-popover-foreground shadow-lg", children: [_jsxs("div", { className: "border-b border-border px-3 py-2 text-sm font-medium", children: [runs.length, " active run", runs.length > 1 ? "s" : ""] }), _jsx("div", { className: "max-h-96 divide-y divide-border overflow-y-auto", children: runs.map((r) => (_jsx(RunRow, { run: r, onDismiss: dismissRun }, r.id))) })] })) : null] }));
57
+ const triggerLabel = activeCount > 0
58
+ ? `${activeCount} active run${activeCount > 1 ? "s" : ""}`
59
+ : failedCount > 0
60
+ ? `${failedCount} failed run${failedCount > 1 ? "s" : ""}`
61
+ : hasRuns
62
+ ? "Recent runs"
63
+ : "No recent runs";
64
+ const TriggerIcon = activeCount > 0
65
+ ? IconLoader2
66
+ : failedCount > 0
67
+ ? IconAlertCircle
68
+ : IconClock;
69
+ const triggerTone = activeCount > 0
70
+ ? "text-primary"
71
+ : failedCount > 0
72
+ ? "text-destructive"
73
+ : "text-muted-foreground";
74
+ const terminalCount = runs.length - activeCount;
75
+ return (_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": triggerLabel, "aria-expanded": open, className: cn("an-runs-tray__trigger relative inline-flex shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/40 hover:text-foreground", triggerVariant === "pill"
76
+ ? "h-7 min-w-[68px] gap-1.5 border border-border/70 bg-background px-2 text-[11px] font-medium"
77
+ : "h-8 w-8", open && "bg-accent/50 text-foreground", className), children: [_jsx(TriggerIcon, { size: triggerVariant === "pill" ? 14 : 18, className: cn(triggerTone, activeCount > 0 && "animate-spin"), "aria-hidden": true }), triggerVariant === "pill" ? (_jsx("span", { className: "leading-none", children: "Runs" })) : null, activeCount > 0 ? (_jsx("span", { "aria-hidden": true, className: cn("an-runs-tray__badge rounded-full bg-primary text-[10px] font-medium leading-[14px] text-primary-foreground", triggerVariant === "pill"
78
+ ? "min-w-4 px-1"
79
+ : "absolute -right-0.5 -top-0.5 px-1"), children: activeCount > 9 ? "9+" : activeCount })) : failedCount > 0 ? (_jsx("span", { "aria-hidden": true, className: cn("rounded-full bg-destructive text-[10px] font-medium leading-[14px] text-destructive-foreground", triggerVariant === "pill"
80
+ ? "min-w-4 px-1"
81
+ : "absolute -right-0.5 -top-0.5 px-1"), children: failedCount > 9 ? "9+" : failedCount })) : null] }) }) }), _jsx(TooltipContent, { children: triggerLabel })] }) }), _jsxs(PopoverContent, { align: align, sideOffset: 8, className: "an-runs-tray__menu w-80 max-w-[calc(100vw-24px)] p-0", children: [_jsxs("div", { className: "border-b border-border px-3 py-2", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Agent runs" }), _jsx("div", { className: "mt-0.5 text-[11px] text-muted-foreground", children: activeCount > 0
82
+ ? `${activeCount} running${terminalCount > 0 ? ` · ${terminalCount} recent` : ""}`
83
+ : hasRuns
84
+ ? `${runs.length} recent run${runs.length > 1 ? "s" : ""}`
85
+ : "No tracked work yet" })] }), hasRuns ? (_jsx("div", { className: "max-h-96 divide-y divide-border overflow-y-auto", children: runs.map((run) => (_jsx(RunRow, { run: run, onDismiss: dismissRun, onOpenThread: onOpenThread }, run.id))) })) : (_jsxs("div", { className: "px-3 py-6 text-center", children: [_jsx(IconClock, { size: 22, className: "mx-auto text-muted-foreground/50", "aria-hidden": true }), _jsx("div", { className: "mt-2 text-sm font-medium text-foreground", children: "No recent runs" }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: "Background agent work will appear here while it runs and after it finishes." })] }))] })] }));
86
+ }
87
+ function getRunThreadId(run) {
88
+ const metadata = run.metadata ?? {};
89
+ const direct = typeof metadata.threadId === "string"
90
+ ? metadata.threadId
91
+ : typeof metadata.thread_id === "string"
92
+ ? metadata.thread_id
93
+ : undefined;
94
+ if (direct?.trim())
95
+ return direct.trim();
96
+ const surfaceUrl = typeof metadata.surfaceUrl === "string" ? metadata.surfaceUrl : undefined;
97
+ const match = surfaceUrl?.match(/^agent-native:\/\/threads\/(.+)$/);
98
+ return match?.[1] ? decodeURIComponent(match[1]) : undefined;
68
99
  }
69
- function RunRow({ run, onDismiss, }) {
70
- return (_jsxs("div", { className: "flex flex-col gap-1 px-3 py-2 text-sm", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "truncate font-medium text-foreground", children: run.title }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [_jsx(StatusGlyph, { status: run.status }), _jsx("button", { type: "button", "aria-label": `Dismiss ${run.title}`, className: "inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground", onClick: () => onDismiss(run.id), children: _jsx(IconX, { size: 13, "aria-hidden": true }) })] })] }), run.step ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: run.step })) : null, run.percent != null ? (_jsx("div", { className: "mt-0.5 h-1 w-full overflow-hidden rounded bg-muted", children: _jsx("div", { className: "h-full bg-primary transition-all", style: { width: `${run.percent}%` } }) })) : (_jsx("div", { className: "mt-0.5 h-1 w-full overflow-hidden rounded bg-muted", children: _jsx("div", { className: "h-full w-1/3 animate-pulse bg-primary/60" }) }))] }));
100
+ function formatRunTime(run) {
101
+ const when = run.completedAt ?? run.updatedAt ?? run.startedAt;
102
+ const timestamp = Date.parse(when);
103
+ if (!Number.isFinite(timestamp))
104
+ return "";
105
+ const diffMs = Date.now() - timestamp;
106
+ const prefix = run.status === "running" ? "Updated" : "Finished";
107
+ if (diffMs < 30_000)
108
+ return `${prefix} just now`;
109
+ const minutes = Math.floor(diffMs / 60_000);
110
+ if (minutes < 60)
111
+ return `${prefix} ${minutes}m ago`;
112
+ const hours = Math.floor(minutes / 60);
113
+ if (hours < 24)
114
+ return `${prefix} ${hours}h ago`;
115
+ return `${prefix} ${new Date(timestamp).toLocaleDateString([], {
116
+ month: "short",
117
+ day: "numeric",
118
+ })}`;
119
+ }
120
+ function RunRow({ run, onDismiss, onOpenThread, }) {
121
+ const threadId = getRunThreadId(run);
122
+ const isRunning = run.status === "running";
123
+ return (_jsxs("div", { className: "flex flex-col gap-1.5 px-3 py-2.5 text-sm", children: [_jsxs("div", { className: "flex items-start justify-between gap-2", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate font-medium text-foreground", children: run.title }), run.step ? (_jsx("div", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: run.step })) : null] }), _jsx(StatusPill, { status: run.status })] }), run.percent != null || isRunning ? (_jsx("div", { className: "h-1 w-full overflow-hidden rounded bg-muted", children: run.percent != null ? (_jsx("div", { className: cn("h-full transition-all", run.status === "failed"
124
+ ? "bg-destructive"
125
+ : run.status === "cancelled"
126
+ ? "bg-muted-foreground/50"
127
+ : "bg-primary"), style: { width: `${run.percent}%` } })) : (_jsx("div", { className: "h-full w-1/3 animate-pulse bg-primary/60" })) })) : null, _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "min-w-0 truncate text-[10px] text-muted-foreground/70", children: formatRunTime(run) }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", children: [threadId && onOpenThread ? (_jsxs("button", { type: "button", className: "inline-flex h-6 items-center gap-1 rounded px-1.5 text-[11px] font-medium text-muted-foreground hover:bg-accent/60 hover:text-foreground", onClick: () => onOpenThread(threadId, run), children: ["Open", _jsx(IconExternalLink, { size: 12, "aria-hidden": true })] })) : null, !isRunning ? (_jsx("button", { type: "button", "aria-label": `Hide ${run.title}`, className: "inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground", onClick: () => onDismiss(run.id), children: _jsx(IconX, { size: 13, "aria-hidden": true }) })) : null] })] })] }));
128
+ }
129
+ const STATUS_COPY = {
130
+ running: "Running",
131
+ succeeded: "Done",
132
+ failed: "Failed",
133
+ cancelled: "Stopped",
134
+ };
135
+ const STATUS_PILL_STYLES = {
136
+ running: "bg-primary/10 text-primary",
137
+ succeeded: "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
138
+ failed: "bg-destructive/10 text-destructive",
139
+ cancelled: "bg-muted text-muted-foreground",
140
+ };
141
+ function StatusPill({ status }) {
142
+ const { Icon, className } = STATUS_GLYPHS[status];
143
+ const spinClass = status === "running" ? " animate-spin" : "";
144
+ return (_jsxs("span", { className: cn("inline-flex h-5 shrink-0 items-center gap-1 rounded-md px-1.5 text-[10px] font-medium", STATUS_PILL_STYLES[status]), children: [_jsx(Icon, { size: 12, className: `${className}${spinClass}`, "aria-hidden": true }), STATUS_COPY[status]] }));
71
145
  }
72
146
  // dark: variants only where there's no semantic token for the colour
73
147
  // (e.g. success green isn't in shadcn's default palette).
@@ -75,14 +149,9 @@ const STATUS_GLYPHS = {
75
149
  running: { Icon: IconLoader2, className: "text-primary" },
76
150
  succeeded: {
77
151
  Icon: IconCheck,
78
- className: "text-green-600 dark:text-green-400",
152
+ className: "text-emerald-600 dark:text-emerald-400",
79
153
  },
80
- failed: { Icon: IconX, className: "text-destructive" },
154
+ failed: { Icon: IconAlertCircle, className: "text-destructive" },
81
155
  cancelled: { Icon: IconClock, className: "text-muted-foreground" },
82
156
  };
83
- function StatusGlyph({ status }) {
84
- const { Icon, className } = STATUS_GLYPHS[status];
85
- const spinClass = status === "running" ? " animate-spin" : "";
86
- return _jsx(Icon, { size: 14, className: `${className}${spinClass}`, "aria-hidden": true });
87
- }
88
157
  //# sourceMappingURL=RunsTray.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"RunsTray.js","sourceRoot":"","sources":["../../../src/client/progress/RunsTray.tsx"],"names":[],"mappings":"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","sourcesContent":["import { agentNativePath } from \"../api-path.js\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { IconLoader2, IconCheck, IconX, IconClock } from \"@tabler/icons-react\";\nimport { usePausingInterval } from \"../use-pausing-interval.js\";\nimport type { AgentRun, ProgressStatus } from \"../../progress/types.js\";\n\ntype AgentRunDto = AgentRun;\n\ninterface RunsTrayProps {\n /** Poll interval in ms. 0 disables. Default 3000. */\n pollMs?: number;\n /** Max runs to show in the dropdown. Default 5. */\n limit?: number;\n /** Hide the trigger entirely when no active runs. Default true. */\n hideWhenIdle?: boolean;\n className?: string;\n}\n\n/**\n * Header-bar progress indicator. Shows a spinner icon with a count badge\n * when runs are active; opens a dropdown with live progress bars for each.\n * Same inline-header pattern as <NotificationsBell /> — drop it into the\n * header, no floating overlay over the main content.\n */\nexport function RunsTray({\n pollMs = 3000,\n limit = 5,\n hideWhenIdle = true,\n className,\n}: RunsTrayProps) {\n const [runs, setRuns] = useState<AgentRunDto[]>([]);\n const [open, setOpen] = useState(false);\n const menuRef = useRef<HTMLDivElement | null>(null);\n\n const refresh = useCallback(async () => {\n try {\n const res = await fetch(\n agentNativePath(`/_agent-native/runs?active=true&limit=${limit}`),\n );\n if (!res.ok) return;\n const rows = (await res.json()) as AgentRunDto[];\n setRuns(rows);\n } catch {\n // best-effort\n }\n }, [limit]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n usePausingInterval(refresh, pollMs);\n\n const dismissRun = useCallback(\n async (runId: string) => {\n setRuns((current) => current.filter((run) => run.id !== runId));\n try {\n const res = await fetch(\n agentNativePath(`/_agent-native/runs/${runId}`),\n {\n method: \"DELETE\",\n headers: { \"X-Agent-Native-CSRF\": \"1\" },\n },\n );\n if (!res.ok) throw new Error(`Dismiss failed (${res.status})`);\n } catch {\n refresh();\n }\n },\n [refresh],\n );\n\n useEffect(() => {\n if (!open) return;\n const onDocClick = (e: MouseEvent) => {\n if (menuRef.current && !menuRef.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", onDocClick);\n return () => document.removeEventListener(\"mousedown\", onDocClick);\n }, [open]);\n\n // Close the dropdown when the last active run finishes.\n useEffect(() => {\n if (runs.length === 0 && open) setOpen(false);\n }, [runs.length, open]);\n\n const hasRuns = runs.length > 0;\n if (!hasRuns && hideWhenIdle) return null;\n\n return (\n <div\n ref={menuRef}\n className={\n \"an-runs-tray relative inline-flex\" + (className ? ` ${className}` : \"\")\n }\n >\n <button\n type=\"button\"\n aria-label={\n hasRuns\n ? `${runs.length} active run${runs.length > 1 ? \"s\" : \"\"}`\n : \"No active runs\"\n }\n aria-expanded={open}\n onClick={() => setOpen((v) => !v)}\n className=\"an-runs-tray__trigger relative inline-flex h-8 w-8 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/40 hover:text-foreground\"\n >\n <IconLoader2\n size={18}\n className={hasRuns ? \"animate-spin text-primary\" : \"\"}\n aria-hidden\n />\n {hasRuns ? (\n <span\n aria-hidden\n className=\"an-runs-tray__badge absolute -right-0.5 -top-0.5 rounded-full bg-primary px-1 text-[10px] leading-[14px] font-medium text-primary-foreground\"\n >\n {runs.length > 9 ? \"9+\" : runs.length}\n </span>\n ) : null}\n </button>\n {open && hasRuns ? (\n <div\n role=\"menu\"\n className=\"an-runs-tray__menu absolute right-0 top-full z-50 mt-2 w-80 rounded-md border border-border bg-popover text-popover-foreground shadow-lg\"\n >\n <div className=\"border-b border-border px-3 py-2 text-sm font-medium\">\n {runs.length} active run{runs.length > 1 ? \"s\" : \"\"}\n </div>\n <div className=\"max-h-96 divide-y divide-border overflow-y-auto\">\n {runs.map((r) => (\n <RunRow key={r.id} run={r} onDismiss={dismissRun} />\n ))}\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n\nfunction RunRow({\n run,\n onDismiss,\n}: {\n run: AgentRunDto;\n onDismiss: (runId: string) => void;\n}) {\n return (\n <div className=\"flex flex-col gap-1 px-3 py-2 text-sm\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate font-medium text-foreground\">\n {run.title}\n </span>\n <div className=\"flex shrink-0 items-center gap-1\">\n <StatusGlyph status={run.status} />\n <button\n type=\"button\"\n aria-label={`Dismiss ${run.title}`}\n className=\"inline-flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n onClick={() => onDismiss(run.id)}\n >\n <IconX size={13} aria-hidden />\n </button>\n </div>\n </div>\n {run.step ? (\n <span className=\"truncate text-xs text-muted-foreground\">\n {run.step}\n </span>\n ) : null}\n {run.percent != null ? (\n <div className=\"mt-0.5 h-1 w-full overflow-hidden rounded bg-muted\">\n <div\n className=\"h-full bg-primary transition-all\"\n style={{ width: `${run.percent}%` }}\n />\n </div>\n ) : (\n <div className=\"mt-0.5 h-1 w-full overflow-hidden rounded bg-muted\">\n <div className=\"h-full w-1/3 animate-pulse bg-primary/60\" />\n </div>\n )}\n </div>\n );\n}\n\n// dark: variants only where there's no semantic token for the colour\n// (e.g. success green isn't in shadcn's default palette).\nconst STATUS_GLYPHS: Record<\n ProgressStatus,\n { Icon: typeof IconLoader2; className: string }\n> = {\n running: { Icon: IconLoader2, className: \"text-primary\" },\n succeeded: {\n Icon: IconCheck,\n className: \"text-green-600 dark:text-green-400\",\n },\n failed: { Icon: IconX, className: \"text-destructive\" },\n cancelled: { Icon: IconClock, className: \"text-muted-foreground\" },\n};\n\nfunction StatusGlyph({ status }: { status: ProgressStatus }) {\n const { Icon, className } = STATUS_GLYPHS[status];\n const spinClass = status === \"running\" ? \" animate-spin\" : \"\";\n return <Icon size={14} className={`${className}${spinClass}`} aria-hidden />;\n}\n"]}
1
+ {"version":3,"file":"RunsTray.js","sourceRoot":"","sources":["../../../src/client/progress/RunsTray.tsx"],"names":[],"mappings":"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","sourcesContent":["import { agentNativePath } from \"../api-path.js\";\nimport { useCallback, useEffect, useMemo, useState } from \"react\";\nimport {\n IconAlertCircle,\n IconCheck,\n IconClock,\n IconExternalLink,\n IconLoader2,\n IconX,\n} from \"@tabler/icons-react\";\nimport { usePausingInterval } from \"../use-pausing-interval.js\";\nimport type { AgentRun, ProgressStatus } from \"../../progress/types.js\";\nimport { cn } from \"../utils.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../components/ui/popover.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\n\ntype AgentRunDto = AgentRun;\ntype RunsTrayTriggerVariant = \"icon\" | \"pill\";\n\ninterface RunsTrayProps {\n /** Poll interval in ms. 0 disables. Default 3000. */\n pollMs?: number;\n /** Max runs to show in the dropdown. Default 5. */\n limit?: number;\n /** Hide the trigger entirely when no active runs. Default true. */\n hideWhenIdle?: boolean;\n /** Include recent terminal runs instead of active runs only. Defaults to !hideWhenIdle. */\n showRecent?: boolean;\n /** Compact icon for app headers, or a labeled pill for the agent panel. */\n triggerVariant?: RunsTrayTriggerVariant;\n /** Called when a run can open a related agent chat thread. */\n onOpenThread?: (threadId: string, run: AgentRunDto) => void;\n align?: \"start\" | \"center\" | \"end\";\n className?: string;\n}\n\n/**\n * Header-bar progress indicator. Shows a spinner icon or labeled Runs pill\n * with a count badge when runs are active; opens a popover with live progress.\n * Same inline-header pattern as <NotificationsBell /> — drop it into the\n * header, no floating overlay over the main content.\n */\nexport function RunsTray({\n pollMs = 3000,\n limit = 5,\n hideWhenIdle = true,\n showRecent,\n triggerVariant = \"icon\",\n onOpenThread,\n align = \"end\",\n className,\n}: RunsTrayProps) {\n const [runs, setRuns] = useState<AgentRunDto[]>([]);\n const [open, setOpen] = useState(false);\n const includeRecent = showRecent ?? !hideWhenIdle;\n\n const refresh = useCallback(async () => {\n try {\n const query = new URLSearchParams({ limit: String(limit) });\n if (!includeRecent) query.set(\"active\", \"true\");\n const res = await fetch(\n agentNativePath(`/_agent-native/runs?${query.toString()}`),\n );\n if (!res.ok) return;\n const rows = (await res.json()) as AgentRunDto[];\n setRuns(rows);\n } catch {\n // best-effort\n }\n }, [includeRecent, limit]);\n\n useEffect(() => {\n refresh();\n }, [refresh]);\n\n usePausingInterval(refresh, pollMs);\n\n const dismissRun = useCallback(\n async (runId: string) => {\n setRuns((current) => current.filter((run) => run.id !== runId));\n try {\n const res = await fetch(\n agentNativePath(`/_agent-native/runs/${runId}`),\n {\n method: \"DELETE\",\n headers: { \"X-Agent-Native-CSRF\": \"1\" },\n },\n );\n if (!res.ok) throw new Error(`Dismiss failed (${res.status})`);\n } catch {\n refresh();\n }\n },\n [refresh],\n );\n\n const hasRuns = runs.length > 0;\n const activeCount = useMemo(\n () => runs.filter((run) => run.status === \"running\").length,\n [runs],\n );\n const failedCount = useMemo(\n () => runs.filter((run) => run.status === \"failed\").length,\n [runs],\n );\n if (!hasRuns && hideWhenIdle) return null;\n\n const triggerLabel =\n activeCount > 0\n ? `${activeCount} active run${activeCount > 1 ? \"s\" : \"\"}`\n : failedCount > 0\n ? `${failedCount} failed run${failedCount > 1 ? \"s\" : \"\"}`\n : hasRuns\n ? \"Recent runs\"\n : \"No recent runs\";\n const TriggerIcon =\n activeCount > 0\n ? IconLoader2\n : failedCount > 0\n ? IconAlertCircle\n : IconClock;\n const triggerTone =\n activeCount > 0\n ? \"text-primary\"\n : failedCount > 0\n ? \"text-destructive\"\n : \"text-muted-foreground\";\n const terminalCount = runs.length - activeCount;\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <TooltipProvider delayDuration={200}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={triggerLabel}\n aria-expanded={open}\n className={cn(\n \"an-runs-tray__trigger relative inline-flex shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent/40 hover:text-foreground\",\n triggerVariant === \"pill\"\n ? \"h-7 min-w-[68px] gap-1.5 border border-border/70 bg-background px-2 text-[11px] font-medium\"\n : \"h-8 w-8\",\n open && \"bg-accent/50 text-foreground\",\n className,\n )}\n >\n <TriggerIcon\n size={triggerVariant === \"pill\" ? 14 : 18}\n className={cn(triggerTone, activeCount > 0 && \"animate-spin\")}\n aria-hidden\n />\n {triggerVariant === \"pill\" ? (\n <span className=\"leading-none\">Runs</span>\n ) : null}\n {activeCount > 0 ? (\n <span\n aria-hidden\n className={cn(\n \"an-runs-tray__badge rounded-full bg-primary text-[10px] font-medium leading-[14px] text-primary-foreground\",\n triggerVariant === \"pill\"\n ? \"min-w-4 px-1\"\n : \"absolute -right-0.5 -top-0.5 px-1\",\n )}\n >\n {activeCount > 9 ? \"9+\" : activeCount}\n </span>\n ) : failedCount > 0 ? (\n <span\n aria-hidden\n className={cn(\n \"rounded-full bg-destructive text-[10px] font-medium leading-[14px] text-destructive-foreground\",\n triggerVariant === \"pill\"\n ? \"min-w-4 px-1\"\n : \"absolute -right-0.5 -top-0.5 px-1\",\n )}\n >\n {failedCount > 9 ? \"9+\" : failedCount}\n </span>\n ) : null}\n </button>\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent>{triggerLabel}</TooltipContent>\n </Tooltip>\n </TooltipProvider>\n <PopoverContent\n align={align}\n sideOffset={8}\n className=\"an-runs-tray__menu w-80 max-w-[calc(100vw-24px)] p-0\"\n >\n <div className=\"border-b border-border px-3 py-2\">\n <div className=\"text-sm font-medium text-foreground\">Agent runs</div>\n <div className=\"mt-0.5 text-[11px] text-muted-foreground\">\n {activeCount > 0\n ? `${activeCount} running${terminalCount > 0 ? ` · ${terminalCount} recent` : \"\"}`\n : hasRuns\n ? `${runs.length} recent run${runs.length > 1 ? \"s\" : \"\"}`\n : \"No tracked work yet\"}\n </div>\n </div>\n {hasRuns ? (\n <div className=\"max-h-96 divide-y divide-border overflow-y-auto\">\n {runs.map((run) => (\n <RunRow\n key={run.id}\n run={run}\n onDismiss={dismissRun}\n onOpenThread={onOpenThread}\n />\n ))}\n </div>\n ) : (\n <div className=\"px-3 py-6 text-center\">\n <IconClock\n size={22}\n className=\"mx-auto text-muted-foreground/50\"\n aria-hidden\n />\n <div className=\"mt-2 text-sm font-medium text-foreground\">\n No recent runs\n </div>\n <p className=\"mt-1 text-xs leading-relaxed text-muted-foreground\">\n Background agent work will appear here while it runs and after it\n finishes.\n </p>\n </div>\n )}\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction getRunThreadId(run: AgentRunDto): string | undefined {\n const metadata = run.metadata ?? {};\n const direct =\n typeof metadata.threadId === \"string\"\n ? metadata.threadId\n : typeof metadata.thread_id === \"string\"\n ? metadata.thread_id\n : undefined;\n if (direct?.trim()) return direct.trim();\n\n const surfaceUrl =\n typeof metadata.surfaceUrl === \"string\" ? metadata.surfaceUrl : undefined;\n const match = surfaceUrl?.match(/^agent-native:\\/\\/threads\\/(.+)$/);\n return match?.[1] ? decodeURIComponent(match[1]) : undefined;\n}\n\nfunction formatRunTime(run: AgentRunDto): string {\n const when = run.completedAt ?? run.updatedAt ?? run.startedAt;\n const timestamp = Date.parse(when);\n if (!Number.isFinite(timestamp)) return \"\";\n const diffMs = Date.now() - timestamp;\n const prefix = run.status === \"running\" ? \"Updated\" : \"Finished\";\n if (diffMs < 30_000) return `${prefix} just now`;\n const minutes = Math.floor(diffMs / 60_000);\n if (minutes < 60) return `${prefix} ${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${prefix} ${hours}h ago`;\n return `${prefix} ${new Date(timestamp).toLocaleDateString([], {\n month: \"short\",\n day: \"numeric\",\n })}`;\n}\n\nfunction RunRow({\n run,\n onDismiss,\n onOpenThread,\n}: {\n run: AgentRunDto;\n onDismiss: (runId: string) => void;\n onOpenThread?: (threadId: string, run: AgentRunDto) => void;\n}) {\n const threadId = getRunThreadId(run);\n const isRunning = run.status === \"running\";\n\n return (\n <div className=\"flex flex-col gap-1.5 px-3 py-2.5 text-sm\">\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"truncate font-medium text-foreground\">\n {run.title}\n </div>\n {run.step ? (\n <div className=\"mt-0.5 truncate text-xs text-muted-foreground\">\n {run.step}\n </div>\n ) : null}\n </div>\n <StatusPill status={run.status} />\n </div>\n {run.percent != null || isRunning ? (\n <div className=\"h-1 w-full overflow-hidden rounded bg-muted\">\n {run.percent != null ? (\n <div\n className={cn(\n \"h-full transition-all\",\n run.status === \"failed\"\n ? \"bg-destructive\"\n : run.status === \"cancelled\"\n ? \"bg-muted-foreground/50\"\n : \"bg-primary\",\n )}\n style={{ width: `${run.percent}%` }}\n />\n ) : (\n <div className=\"h-full w-1/3 animate-pulse bg-primary/60\" />\n )}\n </div>\n ) : null}\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"min-w-0 truncate text-[10px] text-muted-foreground/70\">\n {formatRunTime(run)}\n </span>\n <div className=\"flex shrink-0 items-center gap-1\">\n {threadId && onOpenThread ? (\n <button\n type=\"button\"\n className=\"inline-flex h-6 items-center gap-1 rounded px-1.5 text-[11px] font-medium text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n onClick={() => onOpenThread(threadId, run)}\n >\n Open\n <IconExternalLink size={12} aria-hidden />\n </button>\n ) : null}\n {!isRunning ? (\n <button\n type=\"button\"\n aria-label={`Hide ${run.title}`}\n className=\"inline-flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent/60 hover:text-foreground\"\n onClick={() => onDismiss(run.id)}\n >\n <IconX size={13} aria-hidden />\n </button>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nconst STATUS_COPY: Record<ProgressStatus, string> = {\n running: \"Running\",\n succeeded: \"Done\",\n failed: \"Failed\",\n cancelled: \"Stopped\",\n};\n\nconst STATUS_PILL_STYLES: Record<ProgressStatus, string> = {\n running: \"bg-primary/10 text-primary\",\n succeeded: \"bg-emerald-500/10 text-emerald-600 dark:text-emerald-400\",\n failed: \"bg-destructive/10 text-destructive\",\n cancelled: \"bg-muted text-muted-foreground\",\n};\n\nfunction StatusPill({ status }: { status: ProgressStatus }) {\n const { Icon, className } = STATUS_GLYPHS[status];\n const spinClass = status === \"running\" ? \" animate-spin\" : \"\";\n return (\n <span\n className={cn(\n \"inline-flex h-5 shrink-0 items-center gap-1 rounded-md px-1.5 text-[10px] font-medium\",\n STATUS_PILL_STYLES[status],\n )}\n >\n <Icon size={12} className={`${className}${spinClass}`} aria-hidden />\n {STATUS_COPY[status]}\n </span>\n );\n}\n\n// dark: variants only where there's no semantic token for the colour\n// (e.g. success green isn't in shadcn's default palette).\nconst STATUS_GLYPHS: Record<\n ProgressStatus,\n { Icon: typeof IconLoader2; className: string }\n> = {\n running: { Icon: IconLoader2, className: \"text-primary\" },\n succeeded: {\n Icon: IconCheck,\n className: \"text-emerald-600 dark:text-emerald-400\",\n },\n failed: { Icon: IconAlertCircle, className: \"text-destructive\" },\n cancelled: { Icon: IconClock, className: \"text-muted-foreground\" },\n};\n"]}
@@ -0,0 +1,61 @@
1
+ import { type AgentNativeRouteWarmupConfigInput } from "../shared/route-warmup-config.js";
2
+ type ReactRouterManifestRoute = {
3
+ id: string;
4
+ parentId?: string;
5
+ path?: string;
6
+ index?: boolean;
7
+ module?: string;
8
+ clientActionModule?: string;
9
+ clientLoaderModule?: string;
10
+ hydrateFallbackModule?: string;
11
+ imports?: string[];
12
+ };
13
+ type ReactRouterManifest = {
14
+ routes?: Record<string, ReactRouterManifestRoute>;
15
+ };
16
+ type WarmupRouteObject = {
17
+ id: string;
18
+ path?: string;
19
+ index?: boolean;
20
+ children?: WarmupRouteObject[];
21
+ };
22
+ declare global {
23
+ interface Window {
24
+ __reactRouterContext?: {
25
+ basename?: string;
26
+ };
27
+ __reactRouterManifest?: ReactRouterManifest;
28
+ }
29
+ }
30
+ export interface AgentNativeRouteWarmupProps {
31
+ config?: AgentNativeRouteWarmupConfigInput;
32
+ }
33
+ declare function parseBuildTimeRouteWarmupConfig(raw: AgentNativeRouteWarmupConfigInput | string | undefined): AgentNativeRouteWarmupConfigInput | undefined;
34
+ declare function hasReactRouterManifestRoutes(): boolean;
35
+ declare function getManifestRouteTree(manifest: ReactRouterManifest): WarmupRouteObject[];
36
+ declare function hasWarmableRouteAssets(): boolean;
37
+ declare function routeAssetUrlsForHref(href: string): string[];
38
+ declare function renderWarmupLinksForSelector(selector: string): HTMLAnchorElement[];
39
+ declare function resetRouteWarmupCachesForTests(): void;
40
+ /**
41
+ * Warms React Router route data and matched route JS without using native link
42
+ * prefetch. React Router's built-in `<Link prefetch>` does both pieces, but
43
+ * its data side emits `<link rel="prefetch" as="fetch">`; Chrome sends
44
+ * `Sec-Purpose: prefetch` for that request and Cloudflare Speed Brain can 503
45
+ * dynamic `.data` routes before the CDN/origin can serve the cacheable result.
46
+ *
47
+ * Keep `.data` warmup as ordinary `fetch()` and JS warmup as `modulepreload`
48
+ * unless production providers stop rejecting `Sec-Purpose: prefetch`.
49
+ */
50
+ export declare function AgentNativeRouteWarmup({ config, }: AgentNativeRouteWarmupProps): any;
51
+ export declare const __routeWarmupInternalsForTests: {
52
+ getManifestRouteTree: typeof getManifestRouteTree;
53
+ hasReactRouterManifestRoutes: typeof hasReactRouterManifestRoutes;
54
+ hasWarmableRouteAssets: typeof hasWarmableRouteAssets;
55
+ parseBuildTimeRouteWarmupConfig: typeof parseBuildTimeRouteWarmupConfig;
56
+ renderWarmupLinksForSelector: typeof renderWarmupLinksForSelector;
57
+ routeAssetUrlsForHref: typeof routeAssetUrlsForHref;
58
+ resetRouteWarmupCachesForTests: typeof resetRouteWarmupCachesForTests;
59
+ };
60
+ export {};
61
+ //# sourceMappingURL=route-warmup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-warmup.d.ts","sourceRoot":"","sources":["../../src/client/route-warmup.tsx"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,iCAAiC,EAGvC,MAAM,kCAAkC,CAAC;AAO1C,KAAK,wBAAwB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;CACnD,CAAC;AAEF,KAAK,iBAAiB,GAAG;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,iBAAiB,EAAE,CAAC;CAChC,CAAC;AAIF,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,oBAAoB,CAAC,EAAE;YAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAC7C,qBAAqB,CAAC,EAAE,mBAAmB,CAAC;KAC7C;CACF;AAUD,MAAM,WAAW,2BAA2B;IAC1C,MAAM,CAAC,EAAE,iCAAiC,CAAC;CAC5C;AAED,iBAAS,+BAA+B,CACtC,GAAG,EAAE,iCAAiC,GAAG,MAAM,GAAG,SAAS,GAC1D,iCAAiC,GAAG,SAAS,CAU/C;AAqFD,iBAAS,4BAA4B,IAAI,OAAO,CAG/C;AAkBD,iBAAS,oBAAoB,CAC3B,QAAQ,EAAE,mBAAmB,GAC5B,iBAAiB,EAAE,CAoCrB;AAkBD,iBAAS,sBAAsB,IAAI,OAAO,CAezC;AAED,iBAAS,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAmCrD;AAgDD,iBAAS,4BAA4B,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAqB3E;AAED,iBAAS,8BAA8B,SAMtC;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,MAAM,GACP,EAAE,2BAA2B,OA4J7B;AAED,eAAO,MAAM,8BAA8B;;;;;;;;CAQ1C,CAAC"}