@parhelia/core 0.1.12272 → 0.1.12285

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 (85) hide show
  1. package/dist/agents-view/AgentCard.js +26 -2
  2. package/dist/agents-view/AgentCard.js.map +1 -1
  3. package/dist/components/MarkdownDisplay.d.ts +1 -1
  4. package/dist/components/MarkdownDisplay.js +6 -0
  5. package/dist/components/MarkdownDisplay.js.map +1 -1
  6. package/dist/config/notificationRoutes.js +19 -0
  7. package/dist/config/notificationRoutes.js.map +1 -1
  8. package/dist/editor/ConcurrentUserLimitDialog.d.ts +1 -1
  9. package/dist/editor/ConcurrentUserLimitDialog.js +46 -40
  10. package/dist/editor/ConcurrentUserLimitDialog.js.map +1 -1
  11. package/dist/editor/ai/AgentTerminal.d.ts +3 -1
  12. package/dist/editor/ai/AgentTerminal.js +92 -26
  13. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  14. package/dist/editor/ai/dialogs/AgentDialogHandler.js +32 -22
  15. package/dist/editor/ai/dialogs/AgentDialogHandler.js.map +1 -1
  16. package/dist/editor/ai/dialogs/QuestionnaireInline.js +4 -2
  17. package/dist/editor/ai/dialogs/QuestionnaireInline.js.map +1 -1
  18. package/dist/editor/client/EditorShell.js +6 -1
  19. package/dist/editor/client/EditorShell.js.map +1 -1
  20. package/dist/editor/notifications/WatchButton.js +3 -3
  21. package/dist/editor/notifications/WatchButton.js.map +1 -1
  22. package/dist/editor/notifications/useNotifications.js +19 -1
  23. package/dist/editor/notifications/useNotifications.js.map +1 -1
  24. package/dist/editor/services/agentService.d.ts +1 -0
  25. package/dist/editor/services/agentService.js.map +1 -1
  26. package/dist/editor/settings/About.js +23 -8
  27. package/dist/editor/settings/About.js.map +1 -1
  28. package/dist/licensing/LicenseOverlay.js +1 -3
  29. package/dist/licensing/LicenseOverlay.js.map +1 -1
  30. package/dist/licensing/types.d.ts +2 -0
  31. package/dist/licensing/types.js.map +1 -1
  32. package/dist/revision.d.ts +2 -2
  33. package/dist/revision.js +2 -2
  34. package/dist/task-board/TaskBoardWorkspace.js +390 -443
  35. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  36. package/dist/task-board/components/CreateProjectDialog.js +37 -17
  37. package/dist/task-board/components/CreateProjectDialog.js.map +1 -1
  38. package/dist/task-board/components/ProjectSelector.js +1 -1
  39. package/dist/task-board/components/ProjectSelector.js.map +1 -1
  40. package/dist/task-board/components/TaskAgentPanel.js +2 -6
  41. package/dist/task-board/components/TaskAgentPanel.js.map +1 -1
  42. package/dist/task-board/components/TaskBoardMyTasksSidebar.js +1 -1
  43. package/dist/task-board/components/TaskBoardMyTasksSidebar.js.map +1 -1
  44. package/dist/task-board/components/TaskCard.d.ts +1 -2
  45. package/dist/task-board/components/TaskCard.js +7 -3
  46. package/dist/task-board/components/TaskCard.js.map +1 -1
  47. package/dist/task-board/components/TaskDetailPanel.d.ts +0 -2
  48. package/dist/task-board/components/TaskDetailPanel.js +5 -12
  49. package/dist/task-board/components/TaskDetailPanel.js.map +1 -1
  50. package/dist/task-board/components/TaskReviewActions.d.ts +3 -0
  51. package/dist/task-board/components/TaskReviewActions.js +8 -7
  52. package/dist/task-board/components/TaskReviewActions.js.map +1 -1
  53. package/dist/task-board/components/TaskRow.d.ts +0 -2
  54. package/dist/task-board/components/TaskRow.js +7 -4
  55. package/dist/task-board/components/TaskRow.js.map +1 -1
  56. package/dist/task-board/components/WizardCommunicationCenter.d.ts +3 -0
  57. package/dist/task-board/components/WizardCommunicationCenter.js +181 -22
  58. package/dist/task-board/components/WizardCommunicationCenter.js.map +1 -1
  59. package/dist/task-board/index.d.ts +1 -1
  60. package/dist/task-board/services/taskService.d.ts +4 -1
  61. package/dist/task-board/services/taskService.js +3 -0
  62. package/dist/task-board/services/taskService.js.map +1 -1
  63. package/dist/task-board/taskAgentLink.js +5 -16
  64. package/dist/task-board/taskAgentLink.js.map +1 -1
  65. package/dist/task-board/taskExecutionRecords.d.ts +5 -0
  66. package/dist/task-board/taskExecutionRecords.js +49 -0
  67. package/dist/task-board/taskExecutionRecords.js.map +1 -0
  68. package/dist/task-board/taskExecutionStatus.d.ts +7 -3
  69. package/dist/task-board/taskExecutionStatus.js +75 -113
  70. package/dist/task-board/taskExecutionStatus.js.map +1 -1
  71. package/dist/task-board/taskStatus.d.ts +9 -2
  72. package/dist/task-board/taskStatus.js +53 -8
  73. package/dist/task-board/taskStatus.js.map +1 -1
  74. package/dist/task-board/types.d.ts +30 -5
  75. package/dist/task-board/views/KanbanView.d.ts +0 -2
  76. package/dist/task-board/views/KanbanView.js +14 -11
  77. package/dist/task-board/views/KanbanView.js.map +1 -1
  78. package/dist/task-board/views/ListView.d.ts +0 -2
  79. package/dist/task-board/views/ListView.js +3 -13
  80. package/dist/task-board/views/ListView.js.map +1 -1
  81. package/dist/task-board/views/WizardView.d.ts +0 -2
  82. package/dist/task-board/views/WizardView.js +54 -61
  83. package/dist/task-board/views/WizardView.js.map +1 -1
  84. package/package.json +1 -1
  85. package/styles.css +5 -0
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React, { useEffect, useState, useRef, useCallback, useLayoutEffect, useMemo, } from "react";
3
- import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, ArrowLeft, DollarSign, ExternalLink, Settings2, Target, X, } from "lucide-react";
3
+ import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, ArrowLeft, DollarSign, ExternalLink, Settings2, Target, X, Plus, } from "lucide-react";
4
4
  import { getAgent, startAgent, updateAgentSettings, updateAgentCostLimit, updateAgentContext, getAgentSkillCatalog, getAgentTriggerSubscriptions, cancelAgent, canonicalizeAgentMetadata, getPendingPrompts, } from "../services/agentService";
5
5
  import { useEditContext, useFieldsEditContext } from "../client/editContext";
6
6
  import { localStorageService } from "../services/localStorageService";
@@ -50,6 +50,9 @@ function buildPlaceholderAgentDetails(agentStub) {
50
50
  messageCount: agentStub.messageCount || 0,
51
51
  };
52
52
  }
53
+ function normalizeDialogAgentId(value) {
54
+ return value?.trim().toLowerCase() || "";
55
+ }
53
56
  // Simple user message component
54
57
  const UserMessage = ({ message }) => {
55
58
  const content = message.content || "";
@@ -660,7 +663,7 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
660
663
  // interface AgentTerminalProps {
661
664
  // agentStub: Agent;
662
665
  // }
663
- export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive = true, compact = false, displayMode = "full", showSummaryInput = false, hideContext = false, hideBottomControls = false, hideGreeting = false, simpleMode = false, className, initialPrompt, onAgentUpdate, onInteractionSubmitted, questionnaireFooterActions, hideSummaryMessages = false, summaryPlaceholderActions, hideSummaryWaitingPlaceholder = false, }) {
666
+ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive = true, compact = false, displayMode = "full", showSummaryInput = false, hideContext = false, hideBottomControls = false, hideGreeting = false, simpleMode = false, className, initialPrompt, onAgentUpdate, onInteractionSubmitted, onQuestionnaireOpenChange, questionnaireFooterActions, hideSummaryMessages = false, summaryPlaceholderActions, summaryPlaceholderMessage, hideSummaryWaitingPlaceholder = false, }) {
664
667
  const editContext = useEditContext();
665
668
  const fieldsContext = useFieldsEditContext();
666
669
  const [agent, setAgent] = useState(() => buildPlaceholderAgentDetails(agentStub));
@@ -705,10 +708,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
705
708
  // Agent inline dialog state (for component type selector, etc.)
706
709
  const [activeInlineDialog, setActiveInlineDialog] = useState(null);
707
710
  const activeInlineDialogRef = useRef(activeInlineDialog);
711
+ const isQuestionnaireDialogOpen = activeInlineDialog?.request.dialogType === "questionnaire";
708
712
  const orphanTimeoutRef = useRef(null);
709
713
  useEffect(() => {
710
714
  activeInlineDialogRef.current = activeInlineDialog;
711
715
  }, [activeInlineDialog]);
716
+ useEffect(() => {
717
+ onQuestionnaireOpenChange?.(isQuestionnaireDialogOpen);
718
+ }, [isQuestionnaireDialogOpen, onQuestionnaireOpenChange]);
719
+ useEffect(() => {
720
+ return () => {
721
+ onQuestionnaireOpenChange?.(false);
722
+ };
723
+ }, [onQuestionnaireOpenChange]);
712
724
  const isWaitingRef = useRef(false);
713
725
  useEffect(() => {
714
726
  isWaitingRef.current = isWaitingForResponse;
@@ -784,6 +796,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
784
796
  const [hiddenContextPanelTabIds, setHiddenContextPanelTabIds] = useState(new Set());
785
797
  const [showCostAndAgent, setShowCostAndAgent] = useState(false);
786
798
  const [showAgentSettings, setShowAgentSettings] = useState(false);
799
+ const [showSkillPicker, setShowSkillPicker] = useState(false);
787
800
  const [availableSkills, setAvailableSkills] = useState([]);
788
801
  const [skillRootIds, setSkillRootIds] = useState([]);
789
802
  const [selectableTemplateIds, setSelectableTemplateIds] = useState([]);
@@ -1041,11 +1054,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1041
1054
  }
1042
1055
  return availableSkills.filter((skill) => allowedProfileSkillIdSet.has(skill.id.toLowerCase()));
1043
1056
  }, [availableSkills, allowedProfileSkillIdSet]);
1044
- const profileFilteredSkillIdSet = useMemo(() => new Set(profileFilteredSkills.map((skill) => skill.id.toLowerCase())), [profileFilteredSkills]);
1057
+ const profileFilteredSkillIdSet = useMemo(() => new Set(profileFilteredSkills.map((s) => s.id.toLowerCase())), [profileFilteredSkills]);
1058
+ const availableSkillIdSet = useMemo(() => new Set(availableSkills.map((skill) => skill.id.toLowerCase())), [availableSkills]);
1045
1059
  const selectableTemplateIdSet = useMemo(() => new Set(selectableTemplateIds.map((id) => id.toLowerCase())), [selectableTemplateIds]);
1046
1060
  const selectedSkills = useMemo(() => selectedSkillIds
1047
- .map((id) => profileFilteredSkills.find((s) => s.id.toLowerCase() === id.toLowerCase()))
1048
- .filter((s) => !!s), [profileFilteredSkills, selectedSkillIds]);
1061
+ .map((id) => availableSkills.find((s) => s.id.toLowerCase() === id.toLowerCase()))
1062
+ .filter((s) => !!s), [availableSkills, selectedSkillIds]);
1049
1063
  const selectedSkillSet = useMemo(() => new Set(selectedSkillIds.map((id) => id.toLowerCase())), [selectedSkillIds]);
1050
1064
  const backendAssignedSkillSet = useMemo(() => new Set(backendAssignedSkillIds.map((id) => id.toLowerCase())), [backendAssignedSkillIds]);
1051
1065
  // Remove deprecated cost limit fields from metadata to avoid confusion with agent/profile settings
@@ -2219,6 +2233,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2219
2233
  const isRunning = agentData.status === "running" || agentData.status === 1;
2220
2234
  const isWaiting = agentData.status === "waitingForApproval" ||
2221
2235
  agentData.status === 2 ||
2236
+ agentData.status === "waitingForInput" ||
2222
2237
  agentData.status === "costLimitReached" ||
2223
2238
  agentData.status === 7;
2224
2239
  const keepLocalStreaming = isRunning || isWaiting;
@@ -2262,6 +2277,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2262
2277
  const runningNow = agentData.status === "running" || agentData.status === 1;
2263
2278
  const waitingForApprovalNow = agentData.status === "waitingForApproval" ||
2264
2279
  agentData.status === 2;
2280
+ const waitingForInputNow = agentData.status === "waitingForInput";
2265
2281
  const hasStreamingNow = merged.some((m) => !m.isCompleted && m.messageType === "streaming");
2266
2282
  if (runningNow || hasStreamingNow) {
2267
2283
  setIsWaitingForResponse(true);
@@ -2269,11 +2285,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2269
2285
  // Agent is actively running, show thinking dots
2270
2286
  setIsAgentThinking(true);
2271
2287
  }
2272
- else if (waitingForApprovalNow) {
2288
+ else if (waitingForApprovalNow || waitingForInputNow) {
2273
2289
  setIsWaitingForResponse(false);
2274
2290
  isWaitingRef.current = false;
2275
2291
  setIsConnecting(false);
2276
- // Agent is waiting for user approval, hide thinking dots
2292
+ // Agent is waiting for user input/approval, hide thinking dots
2277
2293
  setIsAgentThinking(false);
2278
2294
  }
2279
2295
  else {
@@ -2914,7 +2930,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2914
2930
  setIsWaitingForResponse(false);
2915
2931
  return;
2916
2932
  }
2917
- // Handle "WaitingForApproval" state explicitly
2933
+ // Handle waiting states explicitly
2918
2934
  if (statusData?.state === "WaitingForApproval" ||
2919
2935
  statusData?.state === "waitingForApproval") {
2920
2936
  setAgent((prev) => prev ? { ...prev, status: "waitingForApproval" } : prev);
@@ -2923,6 +2939,14 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2923
2939
  setIsAgentThinking(false);
2924
2940
  return;
2925
2941
  }
2942
+ if (statusData?.state === "WaitingForInput" ||
2943
+ statusData?.state === "waitingForInput") {
2944
+ setAgent((prev) => prev ? { ...prev, status: "waitingForInput" } : prev);
2945
+ setIsConnecting(false);
2946
+ setIsWaitingForResponse(false);
2947
+ setIsAgentThinking(false);
2948
+ return;
2949
+ }
2926
2950
  if (statusData?.state === "CostLimitReached") {
2927
2951
  const totalCost = Number(statusData.totalCost) || 0;
2928
2952
  const costLimit = Number(statusData.costLimit) || agent?.costLimit || 0;
@@ -3133,6 +3157,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3133
3157
  const isRunning = currentAgent.status === "running" || currentAgent.status === 1;
3134
3158
  const isWaitingForApproval = currentAgent.status === "waitingForApproval" ||
3135
3159
  currentAgent.status === 2;
3160
+ const isWaitingForInput = currentAgent.status === "waitingForInput";
3136
3161
  if (isRunning) {
3137
3162
  setIsWaitingForResponse(true);
3138
3163
  isWaitingRef.current = true;
@@ -3140,10 +3165,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3140
3165
  // Agent is currently running, show thinking dots
3141
3166
  setIsAgentThinking(true);
3142
3167
  }
3143
- else if (isWaitingForApproval) {
3168
+ else if (isWaitingForApproval || isWaitingForInput) {
3144
3169
  setIsWaitingForResponse(false);
3145
3170
  isWaitingRef.current = false;
3146
- // Agent is waiting for user approval, hide thinking dots
3171
+ // Agent is waiting for user input/approval, hide thinking dots
3147
3172
  setIsAgentThinking(false);
3148
3173
  }
3149
3174
  else {
@@ -3224,8 +3249,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3224
3249
  orphanTimeoutRef.current = null;
3225
3250
  }
3226
3251
  const globalListeners = (globalThis.__agentDialogMountedAgents ?? []).filter((x) => typeof x === "string");
3227
- if (!globalListeners.includes(agentStubIdRefForDialogs.current)) {
3228
- globalListeners.push(agentStubIdRefForDialogs.current);
3252
+ const normalizedAgentStubId = normalizeDialogAgentId(agentStubIdRefForDialogs.current);
3253
+ if (normalizedAgentStubId &&
3254
+ !globalListeners.includes(normalizedAgentStubId)) {
3255
+ globalListeners.push(normalizedAgentStubId);
3229
3256
  }
3230
3257
  globalThis.__agentDialogMountedAgents = globalListeners;
3231
3258
  const handleDialogShow = (event) => {
@@ -3233,18 +3260,20 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3233
3260
  const request = detail?.request;
3234
3261
  const onComplete = detail?.onComplete;
3235
3262
  const onCancel = detail?.onCancel;
3236
- const terminalAgentId = agentIdRefForDialogs.current;
3237
- const terminalAgentStubId = agentStubIdRefForDialogs.current;
3263
+ const terminalAgentId = normalizeDialogAgentId(agentIdRefForDialogs.current);
3264
+ const terminalAgentStubId = normalizeDialogAgentId(agentStubIdRefForDialogs.current);
3238
3265
  const isActiveNow = isActiveRefForDialogs.current;
3239
3266
  if (!isActiveNow) {
3240
3267
  return;
3241
3268
  }
3242
3269
  if (!request)
3243
3270
  return;
3271
+ const requestAgentId = normalizeDialogAgentId(request.agentId);
3244
3272
  // Only handle dialog requests for this terminal's agent stub
3245
- if (request.agentId &&
3273
+ if (requestAgentId &&
3246
3274
  terminalAgentStubId &&
3247
- request.agentId !== terminalAgentStubId) {
3275
+ requestAgentId !== terminalAgentStubId &&
3276
+ requestAgentId !== terminalAgentId) {
3248
3277
  return;
3249
3278
  }
3250
3279
  console.log("[AgentTerminal] Received inline dialog request:", request);
@@ -3271,7 +3300,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3271
3300
  window.addEventListener("agent:dialog:show", handleDialogShow);
3272
3301
  return () => {
3273
3302
  const mounted = (globalThis.__agentDialogMountedAgents ?? []).filter((x) => typeof x === "string");
3274
- globalThis.__agentDialogMountedAgents = mounted.filter((id) => id !== agentStubIdRefForDialogs.current);
3303
+ globalThis.__agentDialogMountedAgents = mounted.filter((id) => id !== normalizeDialogAgentId(agentStubIdRefForDialogs.current));
3275
3304
  // If unmounting with an active dialog, defer the orphan event so that
3276
3305
  // React strict mode remounts can cancel it. Only real unmounts fire.
3277
3306
  const orphanedDialog = activeInlineDialogRef.current;
@@ -3286,16 +3315,27 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3286
3315
  window.removeEventListener("agent:dialog:show", handleDialogShow);
3287
3316
  };
3288
3317
  }, []);
3289
- // Announce when this terminal is ready to accept dialogs
3290
- // This allows AgentDialogHandler to re-dispatch pending dialogs when switching to an agent
3318
+ // Announce when this terminal is ready to accept dialogs.
3319
+ // Fire immediately on mount using agentStub.id so the AgentDialogHandler
3320
+ // can re-dispatch pending dialogs without waiting for the async agent load.
3321
+ // Also fire when agent?.id becomes available in case it differs from the stub.
3291
3322
  useEffect(() => {
3292
- if (agent?.id) {
3293
- console.log("[AgentTerminal] Terminal ready for agent:", agent.id);
3323
+ const normalizedStubId = normalizeDialogAgentId(agentStub.id);
3324
+ if (normalizedStubId) {
3294
3325
  window.dispatchEvent(new CustomEvent("agent:terminal:ready", {
3295
- detail: { agentId: agent.id },
3326
+ detail: { agentId: normalizedStubId },
3296
3327
  }));
3297
3328
  }
3298
- }, [agent?.id]);
3329
+ }, [agentStub.id]);
3330
+ useEffect(() => {
3331
+ const normalizedAgentId = normalizeDialogAgentId(agent?.id);
3332
+ const normalizedStubId = normalizeDialogAgentId(agentStub.id);
3333
+ if (normalizedAgentId && normalizedAgentId !== normalizedStubId) {
3334
+ window.dispatchEvent(new CustomEvent("agent:terminal:ready", {
3335
+ detail: { agentId: normalizedAgentId },
3336
+ }));
3337
+ }
3338
+ }, [agent?.id, agentStub.id]);
3299
3339
  // Profiles are provided by parent component (Agents). No local loading here.
3300
3340
  // Select active profile based on agent.profileId or agentStub.profileId
3301
3341
  useEffect(() => {
@@ -4492,10 +4532,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4492
4532
  catch { }
4493
4533
  }
4494
4534
  sendQuickMessage(text);
4495
- } }) })) : hideSummaryWaitingPlaceholder ? (_jsx("div", { className: "flex h-full min-h-[220px] items-center justify-center p-6", children: summaryPlaceholderActions ? (_jsx("div", { className: "flex justify-center", children: summaryPlaceholderActions })) : null })) : (_jsx("div", { className: "flex h-full min-h-[220px] items-center justify-center p-6", children: _jsxs("div", { className: "max-w-md rounded-xl border border-slate-200 bg-slate-50 px-5 py-4 text-center text-sm text-slate-600", children: [_jsx("div", { children: shouldShowThinkingDots || isExecuting
4535
+ } }) })) : hideSummaryWaitingPlaceholder ? (_jsx("div", { className: `flex h-full items-center justify-center ${compact ? "min-h-[100px] p-3" : "min-h-[220px] p-6"}`, children: summaryPlaceholderActions ? (_jsx("div", { className: "flex justify-center", children: summaryPlaceholderActions })) : null })) : (_jsx("div", { className: `flex h-full items-center justify-center ${compact ? "min-h-[100px] p-3" : "min-h-[220px] p-6"}`, children: _jsxs("div", { className: `max-w-md rounded-xl border border-slate-200 bg-slate-50 text-center text-slate-600 ${compact ? "px-3 py-2 text-xs" : "px-5 py-4 text-sm"}`, children: [_jsx("div", { children: shouldShowThinkingDots || isExecuting
4496
4536
  ? "The agent is still working. The next update will appear here automatically."
4497
4537
  : agent?.statusMessage ||
4498
- "Waiting for the next agent update." }), summaryPlaceholderActions ? (_jsx("div", { className: "mt-3 flex justify-center", children: summaryPlaceholderActions })) : null] }) })), shouldShowThinkingDots &&
4538
+ summaryPlaceholderMessage ||
4539
+ "Waiting for the next agent update." }), summaryPlaceholderActions ? (_jsx("div", { className: `flex justify-center ${compact ? "mt-2" : "mt-3"}`, children: summaryPlaceholderActions })) : null] }) })), shouldShowThinkingDots &&
4499
4540
  !inlineDialog &&
4500
4541
  !latestSummaryAssistantGroup && (_jsxs("div", { className: "flex gap-3 px-4 py-3", "data-testid": "agent-thinking-dots", children: [_jsx("div", { className: "shrink-0", children: activeProfile?.svgIcon ? (_jsx("div", { className: "text-gray-2 flex h-6 w-6 items-center justify-center [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
4501
4542
  __html: activeProfile.svgIcon,
@@ -4869,6 +4910,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4869
4910
  }
4870
4911
  } }), _jsxs(Popover, { open: showAgentSettings, onOpenChange: (open) => {
4871
4912
  setShowAgentSettings(open);
4913
+ if (!open) {
4914
+ setShowSkillPicker(false);
4915
+ }
4872
4916
  }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { size: "xs", variant: "outline", className: "h-5 rounded border px-1.5 text-[11px] text-gray-600", "data-testid": "agent-settings-popover-trigger", children: [_jsx(Settings2, { className: "mr-1 h-3 w-3", strokeWidth: 1 }), "Agent settings"] }) }), _jsx(PopoverContent, { className: "w-80 p-3", align: "start", children: _jsxs("div", { className: "space-y-3", children: [profiles?.length > 0 && (_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[11px] font-medium text-gray-700", children: "Agent profile" }), _jsx(Select, { size: "xs", maxWidth: 300, searchable: profiles.length > 5, searchPlaceholder: "Filter profiles...", className: "h-6 w-full rounded border px-1.5 text-[11px] text-gray-500", value: activeProfile?.id || "", options: profileOptions, "data-testid": "agent-profile-selector", onValueChange: async (val) => {
4873
4917
  const nextProfile = profiles.find((x) => x.id === val);
4874
4918
  if (!nextProfile)
@@ -4941,7 +4985,29 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
4941
4985
  catch (err) {
4942
4986
  console.error("Failed to persist agent model", err);
4943
4987
  }
4944
- } })] })) : null, _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center gap-1 text-[11px] font-medium text-gray-700", children: [_jsx(Target, { className: "h-3 w-3", strokeWidth: 1 }), "Skills"] }), selectedSkillIds.length > 0 && (_jsx("div", { className: "mb-2 flex flex-wrap gap-1", children: selectedSkillIds.map((skillId) => {
4988
+ } })] })) : null, _jsxs("div", { children: [_jsxs("div", { className: "mb-1 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-1 text-[11px] font-medium text-gray-700", children: [_jsx(Target, { className: "h-3 w-3", strokeWidth: 1 }), "Skills"] }), _jsxs(Popover, { open: showSkillPicker, onOpenChange: setShowSkillPicker, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { size: "xs", variant: "outline", className: "h-5 rounded border px-1.5 text-[10px] text-gray-600", "data-testid": "agent-skill-picker-trigger", children: [_jsx(Plus, { className: "mr-1 h-3 w-3", strokeWidth: 1.5 }), "Add"] }) }), _jsx(PopoverContent, { className: "w-[22rem] p-2", align: "end", side: "bottom", children: _jsxs("div", { className: "space-y-2", children: [_jsx("div", { className: "text-[11px] font-medium text-gray-700", children: "Select a skill" }), _jsxs("div", { className: "relative h-56 rounded border border-gray-200 bg-gray-50", children: [_jsx(ScrollingContentTree, { rootItemIds: skillRootIds, selectedItemId: selectedSkillIds[selectedSkillIds.length - 1] || undefined, expandedItemId: selectedSkillIds[selectedSkillIds.length - 1] || skillRootIds[0], scrollToSelected: true, hideRootNodes: false, onSelectionChange: (selection) => {
4989
+ const selected = selection[0];
4990
+ if (!selected?.id)
4991
+ return;
4992
+ if (selectableTemplateIdSet.size > 0 &&
4993
+ (!selected.templateId ||
4994
+ !selectableTemplateIdSet.has(selected.templateId.toLowerCase()))) {
4995
+ return;
4996
+ }
4997
+ if (!availableSkillIdSet.has(selected.id.toLowerCase())) {
4998
+ return;
4999
+ }
5000
+ void handleAddSkill(selected.id);
5001
+ setShowSkillPicker(false);
5002
+ } }), skillsLoading && (_jsx("div", { className: "bg-background/70 absolute inset-0 flex items-center justify-center text-[10px] text-gray-500", children: "Loading skills..." }))] }), !skillsLoading &&
5003
+ !skillsError &&
5004
+ profileFilteredSkills.length > 0 && (_jsx("div", { className: "text-[10px] text-gray-500", children: "Click a skill item in the tree to add it." })), skillsError && (_jsx("div", { className: "text-[10px] text-red-600", children: skillsError })), !skillsLoading &&
5005
+ !skillsError &&
5006
+ skillRootIds.length === 0 && (_jsx("div", { className: "text-[10px] text-gray-500", children: "No skill roots available." })), !skillsLoading &&
5007
+ !skillsError &&
5008
+ profileFilteredSkills.length === 0 && (_jsx("div", { className: "text-[10px] text-gray-500", children: selectedSkillIds.length > 0
5009
+ ? "All allowed skills are selected"
5010
+ : "No skills available for this profile" }))] }) })] })] }), selectedSkillIds.length > 0 && (_jsx("div", { className: "mb-2 flex flex-wrap gap-1", children: selectedSkillIds.map((skillId) => {
4945
5011
  const skill = selectedSkills.find((s) => s.id === skillId);
4946
5012
  return (_jsxs("div", { className: "inline-flex items-center gap-1 rounded-full border border-gray-200 bg-gray-100 px-1.5 py-0.5 text-[10px] text-gray-700", children: [_jsx("span", { children: skill?.name || skillId }), _jsx("button", { type: "button", className: "rounded p-0.5 text-gray-500 hover:bg-gray-200 hover:text-gray-700", title: "Open skill item", "aria-label": `Open ${skill?.name || skillId}`, onClick: () => {
4947
5013
  void handleOpenSkillItem(skillId);