@parhelia/core 0.1.12844 → 0.1.12856

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 (111) hide show
  1. package/dist/agents-view/AgentCard.js +2 -2
  2. package/dist/agents-view/AgentCard.js.map +1 -1
  3. package/dist/agents-view/AgentsView.js +9 -10
  4. package/dist/agents-view/AgentsView.js.map +1 -1
  5. package/dist/agents-view/AgentsWorkspaceView.js +3 -3
  6. package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
  7. package/dist/agents-view/ProfileAgentsGroup.js +2 -2
  8. package/dist/agents-view/ProfileAgentsGroup.js.map +1 -1
  9. package/dist/components/ui/LanguageSelectionGrid.d.ts +3 -1
  10. package/dist/components/ui/LanguageSelectionGrid.js +2 -2
  11. package/dist/components/ui/LanguageSelectionGrid.js.map +1 -1
  12. package/dist/components/ui/sonner.js +27 -1
  13. package/dist/components/ui/sonner.js.map +1 -1
  14. package/dist/config/config.js +8 -4
  15. package/dist/config/config.js.map +1 -1
  16. package/dist/config/types/sidebar.d.ts +2 -0
  17. package/dist/config/types.d.ts +1 -0
  18. package/dist/config/types.js.map +1 -1
  19. package/dist/editor/Editor.js +19 -3
  20. package/dist/editor/Editor.js.map +1 -1
  21. package/dist/editor/ai/AgentProfileSelector.d.ts +1 -0
  22. package/dist/editor/ai/AgentProfileSelector.js +4 -4
  23. package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
  24. package/dist/editor/ai/Agents.js +102 -309
  25. package/dist/editor/ai/Agents.js.map +1 -1
  26. package/dist/editor/ai/terminal/components/AgentGreeting.js +2 -2
  27. package/dist/editor/ai/terminal/components/AgentGreeting.js.map +1 -1
  28. package/dist/editor/ai/terminal/components/AgentThinkingDots.js +2 -2
  29. package/dist/editor/ai/terminal/components/AgentThinkingDots.js.map +1 -1
  30. package/dist/editor/ai/terminal/components/AiResponseMessage.js +2 -2
  31. package/dist/editor/ai/terminal/components/AiResponseMessage.js.map +1 -1
  32. package/dist/editor/ai/terminal/components/InitialThinkingSplash.js +2 -2
  33. package/dist/editor/ai/terminal/components/InitialThinkingSplash.js.map +1 -1
  34. package/dist/editor/ai/terminal/components/UserMessage.js +24 -5
  35. package/dist/editor/ai/terminal/components/UserMessage.js.map +1 -1
  36. package/dist/editor/client/EditorShell.d.ts +2 -1
  37. package/dist/editor/client/EditorShell.js +7 -5
  38. package/dist/editor/client/EditorShell.js.map +1 -1
  39. package/dist/editor/client/hooks/useEditorWebSocket.d.ts +1 -0
  40. package/dist/editor/client/hooks/useEditorWebSocket.js +5 -2
  41. package/dist/editor/client/hooks/useEditorWebSocket.js.map +1 -1
  42. package/dist/editor/client/pageModelBuilder.d.ts +1 -0
  43. package/dist/editor/client/pageModelBuilder.js +54 -11
  44. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  45. package/dist/editor/client/ui/EditorChrome.js +1 -1
  46. package/dist/editor/client/ui/EditorChrome.js.map +1 -1
  47. package/dist/editor/context-menu/InsertMenu.js +2 -2
  48. package/dist/editor/context-menu/InsertMenu.js.map +1 -1
  49. package/dist/editor/menubar/toolbar-sections/UtilityControls.js +2 -2
  50. package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
  51. package/dist/editor/menubar/toolbar-sections/ViewportControls.js +2 -1
  52. package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
  53. package/dist/editor/page-editor-chrome/CommentHighlightings.js +22 -65
  54. package/dist/editor/page-editor-chrome/CommentHighlightings.js.map +1 -1
  55. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +1 -1
  56. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  57. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js +5 -12
  58. package/dist/editor/page-editor-chrome/PlaceholderDropZones.js.map +1 -1
  59. package/dist/editor/page-viewer/PageViewer.js +43 -4
  60. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  61. package/dist/editor/page-viewer/PageViewerFrame.js +84 -13
  62. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  63. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js +377 -21
  64. package/dist/editor/page-viewer/pageModelSkeletonBuilder.js.map +1 -1
  65. package/dist/editor/pageModel.d.ts +3 -0
  66. package/dist/editor/pageModel.js +12 -1
  67. package/dist/editor/pageModel.js.map +1 -1
  68. package/dist/editor/reviews/CommentEditor.d.ts +3 -1
  69. package/dist/editor/reviews/CommentEditor.js +18 -8
  70. package/dist/editor/reviews/CommentEditor.js.map +1 -1
  71. package/dist/editor/reviews/CommentPopover.js +3 -2
  72. package/dist/editor/reviews/CommentPopover.js.map +1 -1
  73. package/dist/editor/services/contentService.js +5 -18
  74. package/dist/editor/services/contentService.js.map +1 -1
  75. package/dist/editor/settings/SettingsView.js +1 -1
  76. package/dist/editor/settings/SettingsView.js.map +1 -1
  77. package/dist/editor/settings/panels/AgentsPanel.js +3 -3
  78. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  79. package/dist/editor/settings/panels/NotificationSubscriptionsPanel.js +2 -2
  80. package/dist/editor/settings/panels/NotificationSubscriptionsPanel.js.map +1 -1
  81. package/dist/editor/settings/panels/ProjectTemplateSelectorList.js +4 -4
  82. package/dist/editor/settings/panels/ProjectTemplateSelectorList.js.map +1 -1
  83. package/dist/editor/settings/status/coreStatusChecks.js +52 -2
  84. package/dist/editor/settings/status/coreStatusChecks.js.map +1 -1
  85. package/dist/editor/sidebar/SidebarPanel.js +2 -2
  86. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  87. package/dist/editor/sidebar/SidebarStack.js +1 -0
  88. package/dist/editor/sidebar/SidebarStack.js.map +1 -1
  89. package/dist/editor/ui/Icons.d.ts +1 -1
  90. package/dist/editor/ui/Icons.js +2 -2
  91. package/dist/editor/ui/Icons.js.map +1 -1
  92. package/dist/editor/ui/PublishItemDialog.js +36 -71
  93. package/dist/editor/ui/PublishItemDialog.js.map +1 -1
  94. package/dist/editor/ui/Splitter.d.ts +1 -0
  95. package/dist/editor/ui/Splitter.js +4 -3
  96. package/dist/editor/ui/Splitter.js.map +1 -1
  97. package/dist/editor/utils.d.ts +8 -2
  98. package/dist/editor/utils.js +46 -33
  99. package/dist/editor/utils.js.map +1 -1
  100. package/dist/editor/version-diff/versionDiffTargets.js +8 -15
  101. package/dist/editor/version-diff/versionDiffTargets.js.map +1 -1
  102. package/dist/index.d.ts +1 -1
  103. package/dist/index.js +1 -1
  104. package/dist/index.js.map +1 -1
  105. package/dist/revision.d.ts +2 -2
  106. package/dist/revision.js +2 -2
  107. package/dist/splash-screen/RecentPages.js +7 -7
  108. package/dist/splash-screen/RecentPages.js.map +1 -1
  109. package/dist/tour/Tour.js +1 -1
  110. package/dist/tour/Tour.js.map +1 -1
  111. package/package.json +1 -1
@@ -1,25 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import React, { useState, useRef, useEffect, useMemo } from "react";
2
+ import React, { useState, useRef, useEffect } from "react";
3
3
  import { SimpleIconButton } from "../ui/SimpleIconButton";
4
- import { Plus, MoreVertical } from "lucide-react";
4
+ import { ArrowLeft, List, Plus } from "lucide-react";
5
+ import { CloseButton } from "../../components/ui/close-button";
5
6
  import { cn } from "../../lib/utils";
6
7
  import { sanitizeSvg } from "../../lib/sanitize";
7
- import { startViewTransition } from "../../lib/viewTransition";
8
- import { getAgentStatusConfig } from "./AgentStatusBadge";
9
- import { CloseButton } from "../../components/ui/close-button";
10
- import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
11
8
  import { getActiveAgents, closeAgent as closeAgentService, } from "../services/agentService";
12
- import { isExecutingAgentStatus, isRunningAgentStatus, needsAgentAttention, parseAgentRunStatusData, parseAgentStatus, shouldIgnoreReplayRunStart, } from "../services/agentStatus";
13
- import { toUserFacingAgentErrorMessage } from "../services/agentErrorMessage";
9
+ import { isExecutingAgentStatus, parseAgentRunStatusData, parseAgentStatus, shouldIgnoreReplayRunStart, } from "../services/agentStatus";
14
10
  import { AgentTerminal } from "./AgentTerminal";
15
11
  import { useEditContext } from "../client/editContext";
16
- import { Tooltip, TooltipContent, TooltipTrigger, } from "../../components/ui/tooltip";
17
- // import { Button } from "../../components/ui/button";
18
12
  import { loadAiProfiles } from "../services/aiService";
19
- import { ChevronDown, List } from "lucide-react";
20
13
  import { AgentProfileSelector } from "./AgentProfileSelector";
21
14
  import { AgentsView } from "../../agents-view/AgentsView";
22
- import { SecretAgentIcon } from "../ui/Icons";
15
+ import { ParheliaAgentIcon } from "../ui/Icons";
23
16
  import { Spinner } from "../ui/Spinner";
24
17
  import { localStorageService } from "../services/localStorageService";
25
18
  import { LicenseFeatures, useFeature } from "../../licensing";
@@ -48,14 +41,6 @@ import { LicenseFeatures, useFeature } from "../../licensing";
48
41
  // }
49
42
  const ACTIVE_AGENT_STORAGE_KEY = "editor.activeAgentId";
50
43
  const TASKBOARD_PROJECT_QUERY_KEY = "tbProjectId";
51
- function AgentStatusIndicator({ status, label, size = "sm", }) {
52
- if (status === "running") {
53
- const dotClass = size === "md" ? "h-1.5 w-1.5" : "h-1 w-1";
54
- return (_jsxs("div", { className: "flex flex-shrink-0 items-center gap-0.5", title: label, "aria-label": label, children: [_jsx("div", { className: cn(dotClass, "bg-highlight-100 animate-bounce rounded-full [animation-delay:-0.3s]") }), _jsx("div", { className: cn(dotClass, "bg-highlight-100 animate-bounce rounded-full [animation-delay:-0.15s]") }), _jsx("div", { className: cn(dotClass, "bg-highlight-100 animate-bounce rounded-full") })] }));
55
- }
56
- const statusConfig = getAgentStatusConfig({ status });
57
- return (_jsx("div", { className: cn(size === "md" ? "h-2 w-2" : "h-1.5 w-1.5", "flex-shrink-0 rounded-full", statusConfig.color, statusConfig.shouldPulse && "animate-pulse"), title: label, "aria-label": label }));
58
- }
59
44
  const TASKBOARD_TASK_QUERY_KEY = "tbTaskId";
60
45
  function readTaskboardLinkageFromUrl() {
61
46
  if (typeof window === "undefined") {
@@ -74,9 +59,10 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
74
59
  const [activeAgentId, setActiveAgentId] = useState(""); // "" = show profile selector, null = show overview, string = agent ID
75
60
  const activeAgentIdRef = useRef("");
76
61
  const singleAgentModeRef = useRef(false);
77
- const [profileTabDropdownOpen, setProfileTabDropdownOpen] = useState(null);
78
- const [menuPopoverOpen, setMenuPopoverOpen] = useState(false);
79
- const [loadingAgents, setLoadingAgents] = useState(false);
62
+ // Remembers the agent to return to when dismissing the agents-list or
63
+ // profile-selector overlay via the X button.
64
+ const returnAgentIdRef = useRef(null);
65
+ const [loadingAgents, setLoadingAgents] = useState(true);
80
66
  const [inactiveAgents, setInactiveAgents] = useState([]);
81
67
  const [initialMetadataMap, setInitialMetadataMap] = useState({});
82
68
  const [availableProfiles, setAvailableProfiles] = useState([]);
@@ -84,36 +70,15 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
84
70
  const [loadingProfiles, setLoadingProfiles] = useState(false);
85
71
  const editContext = useEditContext();
86
72
  const canUseAi = useFeature(LicenseFeatures.AI);
87
- // Group agents by profile for profile-based tabs
88
- const agentsGroupedByProfile = useMemo(() => {
89
- const profileMap = new Map();
90
- agents.forEach((agent) => {
91
- const profileId = agent.profileId || null;
92
- const profileKey = profileId || "general";
93
- const profile = availableProfiles.find((p) => p.id === profileId);
94
- if (!profileMap.has(profileKey)) {
95
- profileMap.set(profileKey, {
96
- profileId,
97
- profileName: agent.profileName || "General",
98
- profileSvgIcon: profile?.svgIcon,
99
- agents: [],
100
- });
101
- }
102
- else {
103
- // Update icon if current group doesn't have one but this agent does
104
- const group = profileMap.get(profileKey);
105
- if (!group.profileSvgIcon && profile?.svgIcon) {
106
- group.profileSvgIcon = profile?.svgIcon;
107
- }
108
- }
109
- profileMap.get(profileKey).agents.push(agent);
110
- });
111
- return profileMap;
112
- }, [agents, availableProfiles]);
113
- // Calculate inbox count (agents needing attention, excluding currently open agent)
114
- const inboxCount = useMemo(() => {
115
- return agents.filter((agent) => needsAgentAttention(agent.status) && agent.id !== activeAgentId).length;
116
- }, [agents, activeAgentId]);
73
+ const defaultCloseButton = (_jsx(CloseButton, { onClick: () => {
74
+ editContext?.setShowAgentsPanel(false);
75
+ if (editContext?.openSidebars.includes("agents-panel")) {
76
+ editContext.toggleSidebar("agents-panel", { forceClose: true });
77
+ }
78
+ }, label: "Close Agents Panel", showTooltip: false }));
79
+ // Resolve the profile SVG icon for the active/return agent shown in the header.
80
+ const getAgentIcon = (agent) => availableProfiles.find((p) => p.id === agent.profileId)?.svgIcon ||
81
+ agent.profileSvgIcon;
117
82
  // Detect single-agent mode from query parameter once on mount
118
83
  useEffect(() => {
119
84
  try {
@@ -134,37 +99,13 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
134
99
  : mostRecent;
135
100
  });
136
101
  };
137
- // Helper function to get highest priority status for a group of agents
138
- const getHighestPriorityStatus = (agentList) => {
139
- const statusPriority = {
140
- waitingForApproval: 5,
141
- error: 4,
142
- running: 3,
143
- idle: 2,
144
- completed: 1,
145
- closed: 0,
146
- new: 0,
147
- };
148
- let highestPriority = -1;
149
- let highestStatus = "idle";
150
- agentList.forEach((agent) => {
151
- const statusKey = typeof agent.status === "string" ? agent.status : "idle";
152
- const priority = statusPriority[statusKey] ?? 0;
153
- if (priority > highestPriority) {
154
- highestPriority = priority;
155
- highestStatus = agent.status;
156
- }
157
- });
158
- return highestStatus;
159
- };
160
102
  // Helper function to set active agent and persist to localStorage.
161
- // Wrapped in startViewTransition so tab switches cross-fade instead of
162
- // flashing the empty terminal frame while messages load.
103
+ // Keep this as a plain React update: the embedded panel can contain long
104
+ // transcripts, profile grids, and hidden running terminals, and browser View
105
+ // Transition snapshots have proven too expensive here.
163
106
  const setActiveAgentIdWithStorage = (agentId) => {
164
107
  activeAgentIdRef.current = agentId;
165
- startViewTransition(() => {
166
- setActiveAgentId(agentId);
167
- });
108
+ setActiveAgentId(agentId);
168
109
  if (agentId) {
169
110
  localStorageService.setString(ACTIVE_AGENT_STORAGE_KEY, agentId);
170
111
  }
@@ -172,6 +113,34 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
172
113
  localStorageService.removeItem(ACTIVE_AGENT_STORAGE_KEY);
173
114
  }
174
115
  };
116
+ // Remember the currently open agent (if any) so the overlay X can return to it.
117
+ const rememberReturnAgent = () => {
118
+ const current = activeAgentIdRef.current;
119
+ if (typeof current === "string" && current) {
120
+ returnAgentIdRef.current = current;
121
+ }
122
+ };
123
+ // The "+" button: open the profile selector to start a new agent.
124
+ const showNewAgentProfileSelector = () => {
125
+ rememberReturnAgent();
126
+ setActiveAgentIdWithStorage("");
127
+ };
128
+ // Clicking the agent title: open the full agents list to switch agents.
129
+ const openAgentsList = () => {
130
+ rememberReturnAgent();
131
+ setActiveAgentIdWithStorage(null);
132
+ };
133
+ // The overlay X: return to the previously open agent, falling back to the
134
+ // most recent agent, or the agents list when nothing is open.
135
+ const dismissOverlay = () => {
136
+ const ret = returnAgentIdRef.current;
137
+ if (ret && agents.some((a) => a.id === ret)) {
138
+ setActiveAgentIdWithStorage(ret);
139
+ return;
140
+ }
141
+ const mostRecent = getMostRecentAgent(agents);
142
+ setActiveAgentIdWithStorage(mostRecent ? mostRecent.id : null);
143
+ };
175
144
  // Open an agent from history (or switch to it if already open)
176
145
  const openAgentFromHistory = React.useCallback(async (agent) => {
177
146
  if (!canUseAi) {
@@ -688,30 +657,24 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
688
657
  selectedAgentId = mostRecentAgent?.id || null;
689
658
  }
690
659
  }
691
- // If there are no active agents after load, set to empty string to show profile selector
660
+ // If there are no active agents after load, show the agents list/empty
661
+ // state. The profile selector is heavier and should only mount when the
662
+ // user explicitly clicks + New Agent.
692
663
  if (activeAgentsResult.length === 0) {
693
- // Only if no new agent was added in the meantime
694
- setAgents((prev) => {
695
- if (prev.length === 0) {
696
- setActiveAgentId("");
697
- activeAgentIdRef.current = "";
698
- localStorage.removeItem(ACTIVE_AGENT_STORAGE_KEY);
699
- setSelectedProfileId("");
700
- }
701
- return prev;
702
- });
664
+ if (!activeAgentIdRef.current) {
665
+ setActiveAgentId(null);
666
+ activeAgentIdRef.current = null;
667
+ localStorage.removeItem(ACTIVE_AGENT_STORAGE_KEY);
668
+ setSelectedProfileId("");
669
+ }
703
670
  }
704
671
  else {
705
672
  // Only restore from backend/storage if no new agent is currently active
706
673
  // This prevents overwriting a newly created agent from a comment (especially on mobile)
707
674
  const currentActiveId = activeAgentIdRef.current;
708
- setAgents((prev) => {
709
- const isNewAgentActive = prev.some((a) => a.id === currentActiveId && a.status === "new");
710
- if (!isNewAgentActive) {
711
- setActiveAgentIdWithStorage(selectedAgentId);
712
- }
713
- return prev;
714
- });
675
+ if (!currentActiveId) {
676
+ setActiveAgentIdWithStorage(selectedAgentId);
677
+ }
715
678
  }
716
679
  }
717
680
  catch (error) {
@@ -882,217 +845,44 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
882
845
  closeAgent(agentId);
883
846
  }
884
847
  };
885
- const handleCloseProfileAgents = async (profileAgents, profileName, e) => {
886
- e.stopPropagation();
887
- const agentCount = profileAgents.length;
888
- const hasActiveAgents = profileAgents.some((agent) => isExecutingAgentStatus(agent.status));
889
- if (editContext?.confirm) {
890
- editContext.confirm({
891
- header: `Close ${agentCount} Agent${agentCount > 1 ? "s" : ""}`,
892
- message: hasActiveAgents
893
- ? `This will close all ${agentCount} ${profileName} agent${agentCount > 1 ? "s" : ""}, including ${profileAgents.filter((a) => isRunningAgentStatus(a.status)).length} running agent(s). Are you sure?`
894
- : `Are you sure you want to close all ${agentCount} ${profileName} agent${agentCount > 1 ? "s" : ""}?`,
895
- acceptLabel: `Close ${agentCount > 1 ? "All" : "Agent"}`,
896
- accept: async () => {
897
- // Close all agents in this profile
898
- const closePromises = profileAgents.map((agent) => closeAgentService(agent.id).catch((error) => {
899
- console.error(`Failed to close agent ${agent.id}:`, error);
900
- }));
901
- await Promise.all(closePromises);
902
- // Update UI state
903
- setAgents((prev) => {
904
- const agentIds = new Set(profileAgents.map((a) => a.id));
905
- const filtered = prev.filter((a) => !agentIds.has(a.id));
906
- // Add closed agents to history
907
- const closedAgents = profileAgents.map((agent) => ({
908
- ...agent,
909
- status: "closed",
910
- updatedDate: new Date().toISOString(),
911
- }));
912
- setInactiveAgents((prevInactive) => {
913
- const newAgents = closedAgents.filter((closedAgent) => !prevInactive.some((a) => a.id === closedAgent.id));
914
- return [...newAgents, ...prevInactive];
915
- });
916
- // If we're closing the active agent, switch to most recent remaining or show profile selector
917
- if (activeAgentIdRef.current &&
918
- agentIds.has(activeAgentIdRef.current)) {
919
- if (filtered.length > 0) {
920
- const mostRecentAgent = getMostRecentAgent(filtered);
921
- setActiveAgentIdWithStorage(mostRecentAgent?.id || null);
922
- }
923
- else {
924
- // No agents left, show profile selector
925
- setActiveAgentId("");
926
- activeAgentIdRef.current = "";
927
- localStorageService.removeItem(ACTIVE_AGENT_STORAGE_KEY);
928
- }
929
- }
930
- // Reset profile selection if no agents remain
931
- if (filtered.length === 0) {
932
- setSelectedProfileId("");
933
- }
934
- return filtered;
935
- });
936
- },
937
- showCancel: true,
938
- });
939
- }
940
- };
941
- const closeOtherAgents = async () => {
942
- if (!activeAgentIdRef.current)
943
- return;
944
- // Get agents to close (all except active)
945
- const agentsToClose = agents.filter((a) => a.id !== activeAgentIdRef.current);
946
- // Permanently close each agent in the backend
947
- const closePromises = agentsToClose.map(async (agent) => {
948
- try {
949
- await closeAgentService(agent.id);
950
- }
951
- catch (error) {
952
- console.error(`Failed to close agent ${agent.id}:`, error);
953
- }
954
- });
955
- // Wait for all close operations to complete
956
- await Promise.all(closePromises);
957
- // Add closed agents to history (deduplicate to prevent duplicates)
958
- if (agentsToClose.length > 0) {
959
- const closedAgents = agentsToClose.map((agent) => ({
960
- ...agent,
961
- status: "closed",
962
- updatedDate: new Date().toISOString(),
963
- }));
964
- setInactiveAgents((prevInactive) => {
965
- // Filter out agents that already exist in history
966
- const newAgents = closedAgents.filter((closedAgent) => !prevInactive.some((a) => a.id === closedAgent.id));
967
- return [...newAgents, ...prevInactive];
968
- });
969
- }
970
- setAgents((prev) => {
971
- return prev.filter((a) => a.id === activeAgentIdRef.current);
972
- });
973
- setMenuPopoverOpen(false);
974
- };
975
- const getTabsMenuItems = () => {
976
- return [
977
- {
978
- id: "close-other",
979
- label: "Close Other",
980
- command: async () => {
981
- await closeOtherAgents();
982
- },
983
- disabled: agents.length <= 1,
984
- },
985
- ];
986
- };
987
848
  if (!canUseAi) {
988
849
  return (_jsx("div", { className: "text-neutral-grey-50 flex h-full items-center justify-center p-4 text-center text-sm", children: "AI features are unavailable with the current license." }));
989
850
  }
990
851
  if (loadingAgents) {
991
852
  return (_jsxs("div", { className: "flex h-full items-center justify-center gap-2", children: [_jsx(Spinner, { size: "sm" }), _jsx("div", { className: "text-neutral-grey-50 text-xs", children: "Loading agents..." })] }));
992
853
  }
993
- // Empty state when no agents are open
994
- if (!loadingAgents && agents.length === 0) {
995
- const showingOverview = activeAgentId === null;
996
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "border-border-default flex items-center border-b bg-[color-mix(in_srgb,var(--color-neutral-grey-5)_45%,var(--color-white))]", children: [_jsx("div", { className: "flex-1" }), _jsxs("div", { className: "flex items-center gap-2", children: [showingOverview ? (
997
- /* Show Overview as an active tab when displaying overview - clickable to toggle back */
998
- _jsx("div", { className: "flex items-center px-1", children: _jsxs("div", { onClick: (e) => {
999
- console.log("[Agents Empty State] Overview tab clicked, toggling back to profile selector", e);
1000
- setActiveAgentId("");
1001
- activeAgentIdRef.current = "";
1002
- localStorageService.removeItem(ACTIVE_AGENT_STORAGE_KEY);
1003
- }, className: cn("border-border-default flex h-8 min-w-0 cursor-pointer items-center gap-2 border-r px-2 text-xs", "hover:bg-neutral-grey-5 border-b-white bg-white"), children: [_jsxs("div", { className: "relative", children: [_jsx(List, { className: "text-neutral-grey-50 size-4 flex-shrink-0", strokeWidth: 1 }), inboxCount > 0 && (_jsx("span", { className: "bg-feedback-orange absolute -top-1.5 -right-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full px-1 text-[9px] font-bold text-white", children: inboxCount > 9 ? "9+" : inboxCount }))] }), _jsx("span", { className: "truncate font-medium", children: "Overview" })] }) })) : (
1004
- /* Show Overview as a button when displaying profile selector */
1005
- _jsx("div", { className: "flex items-center px-1", children: _jsx(SimpleIconButton, { onClick: (e) => {
1006
- console.log("[Agents Empty State] Overview button clicked", e);
1007
- setActiveAgentIdWithStorage(null);
1008
- }, icon: _jsxs("div", { className: "relative", children: [_jsx(List, { className: "size-4", strokeWidth: 1 }), inboxCount > 0 && (_jsx("span", { className: "bg-feedback-orange absolute -top-1.5 -right-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full px-1 text-[9px] font-bold text-white", children: inboxCount > 9 ? "9+" : inboxCount }))] }), label: `Agent Overview${inboxCount > 0 ? ` (${inboxCount} need attention)` : ""}`, className: "text-neutral-grey-50 hover:text-neutral-grey-100 h-8" }) })), _jsxs(Popover, { open: menuPopoverOpen, onOpenChange: (open) => {
1009
- console.log("[Agents Empty State] Menu popover onOpenChange:", open);
1010
- setMenuPopoverOpen(open);
1011
- }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { onClick: (e) => {
1012
- setMenuPopoverOpen(!menuPopoverOpen);
1013
- }, icon: _jsx(MoreVertical, { className: "size-4", strokeWidth: 1 }), label: "Menu", className: "text-neutral-grey-50 hover:text-neutral-grey-100", showTooltip: false }) }), _jsx(PopoverContent, { className: "w-48 p-0", align: "end", children: _jsx("div", { className: "py-1", children: getTabsMenuItems().map((item) => item.separator ? (_jsx("div", { className: "bg-border-default my-1 h-px" }, item.id)) : (_jsx("button", { onClick: async (e) => {
1014
- if (item.command)
1015
- await item.command(e);
1016
- setMenuPopoverOpen(false);
1017
- }, disabled: !!item.disabled, className: "hover:bg-neutral-grey-5 disabled:text-neutral-grey-50 w-full px-3 py-2 text-left text-xs disabled:cursor-not-allowed", children: item.label }, item.id))) }) })] }), closeButton && (_jsx("div", { className: "flex items-center", children: closeButton }))] })] }), showingOverview ? (_jsx("div", { className: "relative flex-1", children: _jsx("div", { className: "absolute inset-0", children: _jsx(AgentsView, {}) }) })) : (_jsx("div", { className: "flex flex-1 items-start justify-center overflow-y-auto p-3", children: _jsx("div", { className: "w-full max-w-5xl", children: _jsx(AgentProfileSelector, { profiles: availableProfiles, onSelectProfile: createAgentWithSelectedProfile, loading: loadingProfiles }) }) }))] }));
1018
- }
1019
- return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: "border-border-default flex items-center border-b bg-[color-mix(in_srgb,var(--color-neutral-grey-5)_45%,var(--color-white))]", children: [_jsxs("div", { className: "flex min-w-0 flex-1 overflow-hidden", children: [activeAgentId === "" && agents.length > 0 && (_jsxs("div", { className: cn("border-border-default flex min-w-0 cursor-default items-center gap-2 overflow-hidden border-r p-2 text-xs", "border-b-white bg-white"), children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(Plus, { size: 18, strokeWidth: 1, className: "text-neutral-grey-50" }) }), _jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: "New Agent" })] }), _jsx(CloseButton, { onClick: (e) => {
1020
- e.stopPropagation();
1021
- // Switch back to the most recent agent if we cancel "New Agent"
1022
- const mostRecent = getMostRecentAgent(agents);
1023
- setActiveAgentIdWithStorage(mostRecent?.id || null);
1024
- }, label: "Cancel", className: "flex-shrink-0 opacity-60 hover:opacity-100", showTooltip: false })] })), Array.from(agentsGroupedByProfile.values()).map((profileGroup) => {
1025
- const profileKey = profileGroup.profileId || "general";
1026
- const activeAgent = profileGroup.agents.find((a) => a.id === activeAgentId);
1027
- const isActive = !!activeAgent;
1028
- const agentCount = profileGroup.agents.length;
1029
- const singleAgent = agentCount === 1 ? profileGroup.agents[0] : null;
1030
- const highestStatus = getHighestPriorityStatus(profileGroup.agents);
1031
- const statusConfig = getAgentStatusConfig({
1032
- status: highestStatus,
1033
- });
1034
- const singleAgentErrorMessage = toUserFacingAgentErrorMessage(singleAgent?.statusMessage) ||
1035
- singleAgent?.statusMessage;
1036
- const activeAgentErrorMessage = toUserFacingAgentErrorMessage(activeAgent?.statusMessage) ||
1037
- activeAgent?.statusMessage;
1038
- // Use agent name if: single agent OR active agent from this profile
1039
- const displayName = activeAgent
1040
- ? activeAgent.name
1041
- : singleAgent
1042
- ? singleAgent.name
1043
- : profileGroup.profileName;
1044
- // Always use profile group icon since all agents in the group share the same profile
1045
- const displayIcon = profileGroup.profileSvgIcon;
1046
- // For data-agent-id: prioritize singleAgent, then activeAgent
1047
- // This ensures a single agent always has its ID on the tab
1048
- const tabAgentId = singleAgent?.id || activeAgent?.id || "";
1049
- return (_jsx("div", { className: "min-w-0 shrink", "data-active": isActive ? "true" : "false", "data-agent-id": tabAgentId, children: _jsxs(Popover, { open: profileTabDropdownOpen === profileKey, onOpenChange: (open) => {
1050
- setProfileTabDropdownOpen(open ? profileKey : null);
1051
- if (open) {
1052
- setMenuPopoverOpen(false);
1053
- }
1054
- }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("div", { className: cn("border-border-default flex min-w-0 cursor-pointer items-center gap-2 overflow-hidden border-r p-2 text-xs", isActive
1055
- ? "border-b-white bg-white"
1056
- : "hover:bg-neutral-grey-5"), onClick: () => {
1057
- if (singleAgent) {
1058
- // Single agent: switch directly
1059
- setActiveAgentIdWithStorage(singleAgent.id);
1060
- }
1061
- // Multiple agents: popover will open via PopoverTrigger
1062
- }, children: [_jsxs("div", { className: "flex min-w-0 flex-1 items-center gap-2 overflow-hidden", children: [_jsx("div", { className: "flex-shrink-0", children: displayIcon ? (_jsx("div", { className: "text-neutral-grey-50 flex h-[18px] w-[18px] items-center justify-center [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
1063
- __html: sanitizeSvg(displayIcon),
1064
- } })) : (_jsx(SecretAgentIcon, { size: 18, strokeWidth: 1, className: "text-neutral-grey-50" })) }), _jsx("span", { className: "min-w-0 flex-1 truncate font-medium", children: displayName }), agentCount > 1 && (_jsx("div", { className: "bg-neutral-grey-10 badge-pad-sm text-neutral-grey-100 flex-shrink-0 rounded-full text-[10px] leading-none font-medium", children: agentCount })), _jsxs(Tooltip, { delayDuration: 1000, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: "flex flex-shrink-0 items-center", title: statusConfig.label, children: _jsx(AgentStatusIndicator, { status: highestStatus, label: statusConfig.label }) }) }), _jsx(TooltipContent, { children: _jsxs("div", { children: [_jsx("div", { children: statusConfig.label }), singleAgent?.status === "error" ? (singleAgentErrorMessage ? (_jsx("div", { className: "text-feedback-red mt-1 text-xs", children: singleAgentErrorMessage })) : null) : activeAgent?.status === "error" ? (activeAgentErrorMessage ? (_jsx("div", { className: "text-feedback-red mt-1 text-xs", children: activeAgentErrorMessage })) : null) : null] }) })] }), agentCount > 1 && (_jsx(ChevronDown, { className: "text-neutral-grey-50 size-3 flex-shrink-0", strokeWidth: 1 }))] }), _jsx(CloseButton, { onClick: (e) => singleAgent
1065
- ? handleCloseAgent(singleAgent.id, e)
1066
- : handleCloseProfileAgents(profileGroup.agents, profileGroup.profileName, e), label: agentCount > 1
1067
- ? `Close all ${agentCount} agents`
1068
- : "Close", className: "flex-shrink-0 opacity-60 hover:opacity-100", showTooltip: false })] }) }), agentCount > 1 && (_jsxs(PopoverContent, { className: "w-80 p-0", align: "start", children: [_jsxs("div", { className: "border-border-default text-neutral-grey-50 border-b px-3 py-2 text-xs font-medium", children: [profileGroup.profileName, " Agents"] }), _jsx("div", { className: "max-h-64 overflow-y-auto", children: profileGroup.agents.map((agent) => {
1069
- const agentStatusConfig = getAgentStatusConfig(agent);
1070
- const agentErrorMessage = toUserFacingAgentErrorMessage(agent.statusMessage) || agent.statusMessage;
1071
- return (_jsx("div", { "data-agent-id": agent.id, className: cn("border-border-default hover:bg-neutral-grey-5 cursor-pointer border-b px-3 py-2", activeAgentId === agent.id &&
1072
- "bg-highlight-10/50"), onClick: () => {
1073
- setActiveAgentIdWithStorage(agent.id);
1074
- setProfileTabDropdownOpen(null);
1075
- }, children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(AgentStatusIndicator, { status: agent.status, label: agentStatusConfig.label, size: "md" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-neutral-grey-100 truncate text-xs font-medium", children: agent.name }), _jsx("div", { className: "text-neutral-grey-50 font-mono text-[9px]", children: agent.id }), agent.status === "error" ? (agentErrorMessage ? (_jsx("div", { className: "text-feedback-red truncate text-[11px] leading-tight", children: agentErrorMessage })) : (agent.description && (_jsx("div", { className: "text-neutral-grey-50 truncate text-[11px] leading-tight", children: agent.description })))) : (agent.description && (_jsx("div", { className: "text-neutral-grey-50 truncate text-[11px] leading-tight", children: agent.description })))] }), _jsx(CloseButton, { onClick: (e) => handleCloseAgent(agent.id, e), label: "Close", className: "opacity-60 hover:opacity-100" })] }) }, agent.id));
1076
- }) })] }))] }) }, profileKey));
1077
- })] }), activeAgentId !== null && (_jsx("div", { className: "flex items-center px-1", children: _jsx(SimpleIconButton, { onClick: () => setActiveAgentIdWithStorage(null), icon: _jsxs("div", { className: "relative", children: [_jsx(List, { className: "size-4", strokeWidth: 1 }), inboxCount > 0 && (_jsx("span", { className: "bg-feedback-orange absolute -top-1.5 -right-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full px-1 text-[9px] font-bold text-white", children: inboxCount > 9 ? "9+" : inboxCount }))] }), label: `Agent Overview${inboxCount > 0 ? ` (${inboxCount} need attention)` : ""}`, className: "text-neutral-grey-50 hover:text-neutral-grey-100" }) })), activeAgentId === null && (_jsx("div", { className: "flex items-center px-1", children: _jsxs("div", { className: cn("border-border-default flex min-w-0 cursor-default items-center gap-2 border-r p-2 text-xs", "border-b-white bg-white"), children: [_jsxs("div", { className: "relative", children: [_jsx(List, { className: "text-neutral-grey-50 size-4 flex-shrink-0", strokeWidth: 1 }), inboxCount > 0 && (_jsx("span", { className: "bg-feedback-orange absolute -top-1.5 -right-1.5 flex h-3.5 min-w-3.5 items-center justify-center rounded-full px-1 text-[9px] font-bold text-white", children: inboxCount > 9 ? "9+" : inboxCount }))] }), _jsx("span", { className: "truncate font-medium", children: "Overview" })] }) })), agents.length > 0 && (_jsx("div", { className: "flex items-center px-1", children: _jsxs(Popover, { open: menuPopoverOpen, onOpenChange: (open) => {
1078
- setMenuPopoverOpen(open);
1079
- if (open) {
1080
- setProfileTabDropdownOpen(null);
1081
- }
1082
- }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(SimpleIconButton, { onClick: (e) => {
1083
- setMenuPopoverOpen(!menuPopoverOpen);
1084
- if (!menuPopoverOpen) {
1085
- setProfileTabDropdownOpen(null);
1086
- }
1087
- }, icon: _jsx(MoreVertical, { className: "size-4", strokeWidth: 1 }), label: "Menu", className: "text-neutral-grey-50 hover:text-neutral-grey-100", showTooltip: false }) }), _jsx(PopoverContent, { className: "w-48 p-0", align: "end", children: _jsx("div", { className: "py-1", children: getTabsMenuItems().map((item) => item.separator ? (_jsx("div", { className: "bg-border-default my-1 h-px" }, item.id)) : (_jsx("button", { onClick: async (e) => {
1088
- if (item.command)
1089
- await item.command(e);
1090
- setMenuPopoverOpen(false);
1091
- }, disabled: !!item.disabled, className: "hover:bg-neutral-grey-5 disabled:text-neutral-grey-50 w-full px-3 py-2 text-left text-xs disabled:cursor-not-allowed", children: item.label }, item.id))) }) })] }) })), _jsx("div", { className: "flex items-center px-1", children: _jsx(SimpleIconButton, { onClick: () => {
1092
- setActiveAgentId("");
1093
- activeAgentIdRef.current = "";
1094
- localStorage.removeItem(ACTIVE_AGENT_STORAGE_KEY);
1095
- }, icon: _jsx(Plus, { className: "size-4", strokeWidth: 1 }), label: agents.length === 0 ? "Create Agent" : "Add Agent", className: cn("text-neutral-grey-50 hover:text-neutral-grey-100", activeAgentId === "" && "bg-highlight-10 text-highlight-100"), showTooltip: false, "data-testid": "add-agent-button" }) }), closeButton && (_jsx("div", { className: "flex items-center px-2", children: closeButton }))] }), _jsx("div", { className: "relative flex-1", children: (() => {
854
+ // Derived display state for the header.
855
+ const activeAgent = agents.find((a) => a.id === activeAgentId);
856
+ const returnAgent = returnAgentIdRef.current &&
857
+ agents.find((agent) => agent.id === returnAgentIdRef.current);
858
+ // Overlay modes shown instead of an agent terminal:
859
+ // null = agents list, "" = profile selector, string = an agent.
860
+ const showingList = activeAgentId === null;
861
+ const showingSelector = activeAgentId === "";
862
+ const inOverlay = showingList || showingSelector;
863
+ // The return button can go back to an agent only when at least one is open.
864
+ const canDismissToAgent = agents.length > 0;
865
+ const headerActsAsBack = inOverlay && canDismissToAgent;
866
+ const contextLabel = showingSelector
867
+ ? "Choose an agent profile"
868
+ : showingList
869
+ ? "Select an agent"
870
+ : activeAgent
871
+ ? activeAgent.name
872
+ : "Agents";
873
+ const headerAgent = !inOverlay ? activeAgent : null;
874
+ const headerAgentIcon = headerAgent ? getAgentIcon(headerAgent) : undefined;
875
+ return (_jsxs("div", { className: "flex h-full flex-col", children: [_jsxs("div", { className: cn("border-border-default flex min-h-12 items-center gap-1.5 border-b bg-white px-2.5 py-2", headerActsAsBack && "cursor-pointer"), onClick: headerActsAsBack ? dismissOverlay : undefined, children: [_jsxs("button", { type: "button", "data-active": !inOverlay ? "true" : undefined, "data-agent-id": typeof activeAgentId === "string" ? activeAgentId : "", "data-testid": "agent-title", "aria-label": headerActsAsBack ? "Return to agent" : "Open agents list", onClick: (event) => {
876
+ if (headerActsAsBack) {
877
+ event.stopPropagation();
878
+ dismissOverlay();
879
+ return;
880
+ }
881
+ openAgentsList();
882
+ }, className: "flex min-w-0 flex-1 cursor-pointer items-center gap-1.5 rounded-md px-1.5 py-1 text-left", children: [headerActsAsBack && (_jsx(ArrowLeft, { className: "text-neutral-grey-50 size-4 shrink-0", strokeWidth: 1.5 })), headerAgent &&
883
+ (headerAgentIcon ? (_jsx("div", { className: "text-neutral-grey-100 flex size-[22px] shrink-0 items-center justify-center [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
884
+ __html: sanitizeSvg(headerAgentIcon),
885
+ } })) : (_jsx(ParheliaAgentIcon, { size: 22, strokeWidth: 1.35, className: "text-neutral-grey-100 shrink-0" }))), headerAgent && (_jsx("span", { className: "text-neutral-grey-50 shrink-0 text-xs", children: "-" })), _jsx("span", { className: "text-neutral-grey-100 min-w-0 flex-1 truncate text-xs font-medium", children: contextLabel })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-1", onClick: (event) => event.stopPropagation(), children: [!showingList && agents.length > 0 && (_jsx(SimpleIconButton, { onClick: openAgentsList, icon: _jsx(List, { className: "size-4", strokeWidth: 1.5 }), label: "Switch Agent", className: "text-neutral-grey-50 hover:text-neutral-grey-100", "data-testid": "switch-agent-button" })), !showingSelector && (_jsx(SimpleIconButton, { onClick: showNewAgentProfileSelector, icon: _jsx(Plus, { className: "size-4", strokeWidth: 1.5 }), label: agents.length === 0 ? "Create Agent" : "New Agent", className: "text-neutral-grey-50 hover:text-neutral-grey-100", "data-testid": "add-agent-button" })), _jsx("div", { className: "flex items-center pl-0.5", children: closeButton ?? defaultCloseButton })] })] }), _jsx("div", { className: "relative flex-1", children: (() => {
1096
886
  const shouldKeepMounted = (agent) => {
1097
887
  const parsedStatus = parseAgentStatus(agent.status);
1098
888
  return (agent.id === activeAgentId ||
@@ -1111,11 +901,14 @@ export const Agents = React.memo(function Agents({ closeButton, }) {
1111
901
  return (_jsx("div", { className: cn("absolute inset-0", !isSelected && "hidden"), style: isSelected
1112
902
  ? { viewTransitionName: "agents-tab-pane" }
1113
903
  : undefined, children: _jsx(AgentTerminal, { agentStub: agent, initialMetadata: initialMetadataMap[agent.id], profiles: availableProfiles, onReloadProfiles: reloadProfiles, isActive: isSelected, isVisible: keepStreaming, isFocused: isSelected, onAgentUpdate: (updates) => handleAgentUpdate(agent.id, updates) }) }, agent.id));
1114
- }), activeAgentId === null ? (
1115
- // Show AgentsView when no agent is selected
1116
- _jsx("div", { className: "absolute inset-0", children: _jsx(AgentsView, {}) })) : activeAgentId === "" ? (
1117
- // Show Profile Selector when activeAgentId is ""
1118
- _jsx("div", { className: "absolute inset-0 flex items-start justify-center overflow-y-auto p-2", children: _jsx("div", { className: "w-full max-w-5xl", children: _jsx(AgentProfileSelector, { profiles: availableProfiles, onSelectProfile: createAgentWithSelectedProfile, loading: loadingProfiles }) }) })) : null] }));
904
+ }), showingList ? (
905
+ // Agents list pick an agent to switch, or create a new one.
906
+ _jsx("div", { className: "absolute inset-0", children: _jsx(AgentsView, { compact: true, hideNewAgentButton: true, selectedAgentId: returnAgentIdRef.current &&
907
+ agents.some((a) => a.id === returnAgentIdRef.current)
908
+ ? returnAgentIdRef.current
909
+ : undefined, onSelectAgent: (agent) => openAgentFromHistory(agent), onRequestCreateAgent: showNewAgentProfileSelector }) })) : showingSelector ? (
910
+ // Profile selector — its heading lives in the header instead.
911
+ _jsx("div", { className: "absolute inset-0 flex items-start justify-center overflow-y-auto p-2", children: _jsx("div", { className: "w-full max-w-5xl", children: _jsx(AgentProfileSelector, { profiles: availableProfiles, onSelectProfile: createAgentWithSelectedProfile, loading: loadingProfiles, title: "" }) }) })) : null] }));
1119
912
  })() })] }));
1120
913
  });
1121
914
  //# sourceMappingURL=Agents.js.map