@parhelia/core 0.1.12774 → 0.1.12775

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 (84) hide show
  1. package/dist/agents-view/AgentsInbox.d.ts +5 -1
  2. package/dist/agents-view/AgentsInbox.js +5 -3
  3. package/dist/agents-view/AgentsInbox.js.map +1 -1
  4. package/dist/agents-view/AgentsView.js +29 -13
  5. package/dist/agents-view/AgentsView.js.map +1 -1
  6. package/dist/config/config.js +6 -5
  7. package/dist/config/config.js.map +1 -1
  8. package/dist/config/types.d.ts +1 -0
  9. package/dist/config/types.js.map +1 -1
  10. package/dist/editor/ai/AgentTerminal.js +85 -12
  11. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  12. package/dist/editor/ai/AgentTerminalStatusBar.js +27 -31
  13. package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
  14. package/dist/editor/ai/AiResponseMessage.js +2 -2
  15. package/dist/editor/ai/AiResponseMessage.js.map +1 -1
  16. package/dist/editor/ai/HeartbeatMessage.js +2 -2
  17. package/dist/editor/ai/HeartbeatMessage.js.map +1 -1
  18. package/dist/editor/ai/QueuedPromptsPanel.js +3 -2
  19. package/dist/editor/ai/QueuedPromptsPanel.js.map +1 -1
  20. package/dist/editor/ai/SpawnedAgentsPanel.js +2 -2
  21. package/dist/editor/ai/SpawnedAgentsPanel.js.map +1 -1
  22. package/dist/editor/ai/TimeWithTooltip.d.ts +9 -0
  23. package/dist/editor/ai/TimeWithTooltip.js +12 -0
  24. package/dist/editor/ai/TimeWithTooltip.js.map +1 -0
  25. package/dist/editor/ai/ToolCallDisplay.js +6 -3
  26. package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
  27. package/dist/editor/ai/UserMessage.js +3 -3
  28. package/dist/editor/ai/UserMessage.js.map +1 -1
  29. package/dist/editor/ai/agentDiagnostics.js +2 -1
  30. package/dist/editor/ai/agentDiagnostics.js.map +1 -1
  31. package/dist/editor/ai/agentDiagnostics.test.js +39 -1
  32. package/dist/editor/ai/agentDiagnostics.test.js.map +1 -1
  33. package/dist/editor/ai/agentMessageHelpers.d.ts +1 -0
  34. package/dist/editor/ai/agentMessageHelpers.js +6 -0
  35. package/dist/editor/ai/agentMessageHelpers.js.map +1 -1
  36. package/dist/editor/services/agentService.d.ts +8 -0
  37. package/dist/editor/services/agentService.js.map +1 -1
  38. package/dist/editor/services/aiService.d.ts +1 -1
  39. package/dist/editor/services/aiService.js +3 -2
  40. package/dist/editor/services/aiService.js.map +1 -1
  41. package/dist/editor/settings/QuotaInfo.js +29 -60
  42. package/dist/editor/settings/QuotaInfo.js.map +1 -1
  43. package/dist/editor/settings/QuotaUserPicker.d.ts +13 -0
  44. package/dist/editor/settings/QuotaUserPicker.js +58 -0
  45. package/dist/editor/settings/QuotaUserPicker.js.map +1 -0
  46. package/dist/editor/settings/SettingsBreadcrumb.d.ts +5 -1
  47. package/dist/editor/settings/SettingsBreadcrumb.js +3 -3
  48. package/dist/editor/settings/SettingsBreadcrumb.js.map +1 -1
  49. package/dist/editor/settings/SettingsHeaderActionsContext.d.ts +3 -0
  50. package/dist/editor/settings/SettingsHeaderActionsContext.js +11 -0
  51. package/dist/editor/settings/SettingsHeaderActionsContext.js.map +1 -1
  52. package/dist/editor/settings/SettingsView.js +5 -3
  53. package/dist/editor/settings/SettingsView.js.map +1 -1
  54. package/dist/editor/settings/panels/AgentsPanel.js +2 -4
  55. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  56. package/dist/editor/settings/panels/GroupedFieldConfigPanel.js +2 -8
  57. package/dist/editor/settings/panels/GroupedFieldConfigPanel.js.map +1 -1
  58. package/dist/editor/settings/panels/ItemConfigPanel.js +1 -1
  59. package/dist/editor/settings/panels/ItemConfigPanel.js.map +1 -1
  60. package/dist/editor/settings/panels/ModelsPanel.js +28 -14
  61. package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
  62. package/dist/editor/settings/panels/ProjectTemplateSelector.d.ts +2 -7
  63. package/dist/editor/settings/panels/ProjectTemplateSelector.js +6 -8
  64. package/dist/editor/settings/panels/ProjectTemplateSelector.js.map +1 -1
  65. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +63 -31
  66. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  67. package/dist/editor/settings/panels/ProviderIcon.d.ts +17 -0
  68. package/dist/editor/settings/panels/ProviderIcon.js +89 -0
  69. package/dist/editor/settings/panels/ProviderIcon.js.map +1 -0
  70. package/dist/editor/settings/panels/ProvidersPanel.js +17 -4
  71. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
  72. package/dist/editor/ui/SimpleTabs.js +28 -3
  73. package/dist/editor/ui/SimpleTabs.js.map +1 -1
  74. package/dist/revision.d.ts +2 -2
  75. package/dist/revision.js +2 -2
  76. package/dist/task-board/TaskBoardWorkspace.js +1 -1
  77. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  78. package/dist/task-board/components/ProjectDashboard.js +3 -3
  79. package/dist/task-board/components/ProjectDashboard.js.map +1 -1
  80. package/dist/task-board/components/ProjectPropertiesPanel.js +1 -1
  81. package/dist/task-board/components/ProjectPropertiesPanel.js.map +1 -1
  82. package/dist/task-board/views/DependencyGraphView.js +76 -18
  83. package/dist/task-board/views/DependencyGraphView.js.map +1 -1
  84. package/package.json +1 -1
@@ -26,7 +26,7 @@ import { cn } from "../../../lib/utils";
26
26
  import { AgentProfileEditorPanel, } from "./AgentProfileEditorPanel";
27
27
  import { ProjectTemplateAgentPanel } from "./ProjectTemplateAgentPanel";
28
28
  import { ProjectTemplateSelector } from "./ProjectTemplateSelector";
29
- import { useRequiredSettingsHeaderActions } from "../SettingsHeaderActionsContext";
29
+ import { useRequiredSettingsBreadcrumbExtra, useRequiredSettingsHeaderActions, } from "../SettingsHeaderActionsContext";
30
30
  import { useSearchParams } from "../../client/navigation";
31
31
  // Query param for deep-linking the selected project template (settings reload).
32
32
  const SELECTED_PROJECT_TEMPLATE_QUERY_PARAM = "projectTemplateId";
@@ -198,7 +198,7 @@ function buildUpsertTemplateRequest(template) {
198
198
  disabled: normalizedTask.disabled === true,
199
199
  taskType: normalizedTask.taskType ?? "Task",
200
200
  decisionMode: normalizedTask.taskType === "DecisionPoint"
201
- ? normalizedTask.decisionMode ?? "MultiSelect"
201
+ ? (normalizedTask.decisionMode ?? "MultiSelect")
202
202
  : null,
203
203
  priority: normalizedTask.priority || null,
204
204
  sortOrder: normalizedTask.sortOrder || index * 100,
@@ -407,6 +407,7 @@ export function ProjectTemplatesPanel() {
407
407
  const [mobileView, setMobileView] = useState("detail");
408
408
  const [editingAgentProfile, setEditingAgentProfile] = useState(null);
409
409
  const setSettingsHeaderActions = useRequiredSettingsHeaderActions();
410
+ const setSettingsBreadcrumbExtra = useRequiredSettingsBreadcrumbExtra();
410
411
  const autosaveTimeoutRef = useRef(null);
411
412
  const lastPersistedSignatureRef = useRef(null);
412
413
  const latestDraftSignatureRef = useRef(null);
@@ -459,8 +460,9 @@ export function ProjectTemplatesPanel() {
459
460
  return;
460
461
  }
461
462
  const clonedTemplate = template ? cloneTemplate(template) : null;
462
- const preferredTaskId = clonedTemplate?.id &&
463
- clonedTemplate.id === selectedTemplateIdRef.current
463
+ const isSameTemplate = !!clonedTemplate &&
464
+ clonedTemplate.id === selectedTemplateIdRef.current;
465
+ const preferredTaskId = isSameTemplate
464
466
  ? selectedTaskIdRef.current
465
467
  : null;
466
468
  const persistedSignature = clonedTemplate && clonedTemplate.name.trim()
@@ -472,7 +474,12 @@ export function ProjectTemplatesPanel() {
472
474
  setDraftTemplate(clonedTemplate);
473
475
  setEditingAgentProfile(null);
474
476
  setSelectedTaskId(getSelectedTaskIdForTemplate(clonedTemplate, preferredTaskId));
475
- setActiveDetailTab(clonedTemplate && !clonedTemplate.name.trim() ? "basic" : "tasks");
477
+ // Re-selecting the same template (e.g. via external refresh) must not
478
+ // clobber the user's current tab choice. Only reset the tab when the
479
+ // selected template actually changes.
480
+ if (!isSameTemplate) {
481
+ setActiveDetailTab(clonedTemplate && !clonedTemplate.name.trim() ? "basic" : "tasks");
482
+ }
476
483
  setIsDirty(false);
477
484
  setSaveError(null);
478
485
  lastPersistedSignatureRef.current = persistedSignature;
@@ -518,7 +525,8 @@ export function ProjectTemplatesPanel() {
518
525
  ? null
519
526
  : loadedTemplates[0]?.id || null;
520
527
  const nextTemplate = loadedTemplates.find((template) => template.id === nextTemplateId);
521
- if (options?.preserveDraftIfDirty && (savingRef.current || isDirtyRef.current)) {
528
+ if (options?.preserveDraftIfDirty &&
529
+ (savingRef.current || isDirtyRef.current)) {
522
530
  return;
523
531
  }
524
532
  selectTemplate(nextTemplate ?? null);
@@ -618,12 +626,12 @@ export function ProjectTemplatesPanel() {
618
626
  }, [dependencyTasks, selectedDependencyId]);
619
627
  const headerStatusBadge = useMemo(() => {
620
628
  if (saveError) {
621
- return (_jsx("span", { "data-testid": "project-template-save-status", "data-state": "error", className: "inline-flex min-w-[84px] justify-center rounded bg-red-100 px-1.5 py-0.5 whitespace-nowrap text-red-700", children: "Save failed" }));
629
+ return (_jsx("span", { "data-testid": "project-template-save-status", "data-state": "error", className: "inline-flex min-w-[84px] justify-center rounded bg-red-100 px-1.5 whitespace-nowrap text-red-700", children: "Save failed" }));
622
630
  }
623
631
  if (isDirty || saving) {
624
- return (_jsx("span", { "data-testid": "project-template-save-status", "data-state": "saving", className: "inline-flex min-w-[84px] justify-center rounded bg-amber-100 px-1.5 py-0.5 whitespace-nowrap text-amber-700", children: "Saving..." }));
632
+ return (_jsx("span", { "data-testid": "project-template-save-status", "data-state": "saving", className: "inline-flex min-w-[84px] justify-center rounded bg-amber-100 px-1.5 whitespace-nowrap text-amber-700", children: "Saving..." }));
625
633
  }
626
- return (_jsx("span", { "aria-hidden": "true", "data-testid": "project-template-save-status", "data-state": "saved", className: "pointer-events-none inline-flex min-w-[84px] justify-center rounded px-1.5 py-0.5 whitespace-nowrap opacity-0 select-none", children: "Saving..." }));
634
+ return (_jsx("span", { "aria-hidden": "true", "data-testid": "project-template-save-status", "data-state": "saved", className: "pointer-events-none inline-flex min-w-[84px] justify-center rounded px-1.5 whitespace-nowrap opacity-0 select-none", children: "Saving..." }));
627
635
  }, [isDirty, saveError, saving]);
628
636
  const graphTasks = useMemo(() => buildTemplateTaskItems(draftTemplate, aiProfilesById), [aiProfilesById, draftTemplate]);
629
637
  const graphDependencies = useMemo(() => buildTemplateDependencies(draftTemplate), [draftTemplate]);
@@ -897,7 +905,9 @@ export function ProjectTemplatesPanel() {
897
905
  : null;
898
906
  draftTemplateRef.current = nextTemplate;
899
907
  latestDraftSignatureRef.current = nextSignature;
900
- setTemplates((existingTemplates) => existingTemplates.map((template) => template.id === nextTemplate.id ? cloneTemplate(nextTemplate) : template));
908
+ setTemplates((existingTemplates) => existingTemplates.map((template) => template.id === nextTemplate.id
909
+ ? cloneTemplate(nextTemplate)
910
+ : template));
901
911
  return nextTemplate;
902
912
  });
903
913
  setIsDirty(true);
@@ -1549,33 +1559,51 @@ export function ProjectTemplatesPanel() {
1549
1559
  selectedDependencyId,
1550
1560
  selectedTaskId,
1551
1561
  ]);
1552
- const templateSelector = useMemo(() => (_jsx(ProjectTemplateSelector, { templates: templates, selectedTemplate: draftTemplate, selectedTemplateId: selectedTemplateId, state: state, error: error, deleting: deleting, statusBadge: headerStatusBadge, onSelectTemplate: handleSelectTemplate, onCreateTemplate: handleCreateTemplate, onRefreshTemplates: handleRefreshTemplates, onDeleteTemplate: handleDeleteTemplate })), [
1562
+ const templateSelector = useMemo(() => (_jsx(ProjectTemplateSelector, { templates: templates, selectedTemplate: draftTemplate, selectedTemplateId: selectedTemplateId, error: error, deleting: deleting, loading: state === "loading", onSelectTemplate: handleSelectTemplate, onDeleteTemplate: handleDeleteTemplate })), [
1553
1563
  deleting,
1554
1564
  draftTemplate,
1555
1565
  error,
1556
- handleCreateTemplate,
1557
1566
  handleDeleteTemplate,
1558
- handleRefreshTemplates,
1559
1567
  handleSelectTemplate,
1560
- headerStatusBadge,
1561
1568
  selectedTemplateId,
1562
1569
  state,
1563
1570
  templates,
1564
1571
  ]);
1565
- const desktopTemplateSelector = useMemo(() => !isMobile ? (_jsxs("div", { className: "flex w-full max-w-[40rem] items-center justify-end gap-2", children: [_jsx("div", { className: "min-w-0 flex-1 max-w-[32rem]", children: templateSelector }), draftTemplate && !draftTemplate.isSystem ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), deleting ? "Deleting..." : "Delete"] })) : null] })) : null, [deleting, draftTemplate, handleDeleteTemplate, isMobile, templateSelector]);
1572
+ const desktopBreadcrumbSelector = useMemo(() => !isMobile ? (_jsx("div", { className: "max-w-[32rem] min-w-0", children: templateSelector })) : null, [isMobile, templateSelector]);
1573
+ const desktopHeaderActions = useMemo(() => {
1574
+ if (isMobile)
1575
+ return null;
1576
+ const showDelete = draftTemplate && !draftTemplate.isSystem;
1577
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [headerStatusBadge, _jsxs(Button, { size: "sm", onClick: () => void handleCreateTemplate(), "data-testid": "project-template-create-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Create new template"] }), showDelete ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), deleting ? "Deleting..." : "Delete"] })) : null] }));
1578
+ }, [
1579
+ deleting,
1580
+ draftTemplate,
1581
+ handleCreateTemplate,
1582
+ handleDeleteTemplate,
1583
+ headerStatusBadge,
1584
+ isMobile,
1585
+ ]);
1586
+ useEffect(() => {
1587
+ if (!setSettingsBreadcrumbExtra)
1588
+ return;
1589
+ setSettingsBreadcrumbExtra(desktopBreadcrumbSelector);
1590
+ return () => {
1591
+ setSettingsBreadcrumbExtra(null);
1592
+ };
1593
+ }, [desktopBreadcrumbSelector, setSettingsBreadcrumbExtra]);
1566
1594
  useEffect(() => {
1567
1595
  if (!setSettingsHeaderActions)
1568
1596
  return;
1569
- setSettingsHeaderActions(desktopTemplateSelector);
1597
+ setSettingsHeaderActions(desktopHeaderActions);
1570
1598
  return () => {
1571
1599
  setSettingsHeaderActions(null);
1572
1600
  };
1573
- }, [desktopTemplateSelector, setSettingsHeaderActions]);
1601
+ }, [desktopHeaderActions, setSettingsHeaderActions]);
1574
1602
  const renderTemplateTaskEditorMain = () => {
1575
1603
  if (!draftTemplate) {
1576
1604
  return null;
1577
1605
  }
1578
- const graphView = (_jsx("div", { className: "h-full min-h-0 overflow-hidden bg-slate-50/40", "data-testid": "project-template-graph", children: _jsx(DependencyGraphView, { projectId: draftTemplate.id, layoutKey: `project-template:${draftTemplate.id}`, tasks: graphTasks, dependencies: graphDependencies, miniMapWidth: 56, miniMapHeight: 42, showMiniMap: !isMobile, orientation: "horizontal", showOrientationToggle: true, autoLayoutStrategy: "hierarchy", savedLayout: draftTemplate.graphLayout, selectedTaskId: selectedTaskId, selectedDependencyId: selectedDependencyId, onSelectTask: handleSelectTask, onSelectDependency: handleSelectDependencyFromGraph, onClearDependencySelection: handleClearDependencySelection, onAddDependentTaskFromNode: (taskId) => {
1606
+ const graphView = (_jsx("div", { className: "h-full min-h-0 overflow-hidden bg-slate-50/40", "data-testid": "project-template-graph", children: _jsx(DependencyGraphView, { projectId: draftTemplate.id, layoutKey: `project-template:${draftTemplate.id}`, tasks: graphTasks, dependencies: graphDependencies, miniMapWidth: 160, miniMapHeight: 120, showMiniMap: !isMobile, orientation: "horizontal", showOrientationToggle: true, autoLayoutStrategy: "hierarchy", savedLayout: draftTemplate.graphLayout, selectedTaskId: selectedTaskId, selectedDependencyId: selectedDependencyId, onSelectTask: handleSelectTask, onSelectDependency: handleSelectDependencyFromGraph, onClearDependencySelection: handleClearDependencySelection, onAddDependentTaskFromNode: (taskId) => {
1579
1607
  void handleOpenCreateDependentTaskDialogForTask(taskId);
1580
1608
  }, onAddChildTaskFromNode: (taskId) => {
1581
1609
  void handleOpenAddChildTaskDialogForTask(taskId);
@@ -1590,7 +1618,7 @@ export function ProjectTemplatesPanel() {
1590
1618
  }));
1591
1619
  return nextLayout;
1592
1620
  } }) }));
1593
- const taskPane = (_jsx("div", { className: "flex h-full min-h-0 flex-col overflow-hidden", "data-testid": "project-template-task-detail-pane", children: !selectedTask ? (_jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children: _jsx("div", { className: "rounded-lg border border-dashed border-gray-200 bg-gray-50 p-6 text-center text-xs text-gray-500", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "shrink-0 border-b border-gray-100 bg-white px-4 pt-4 pb-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "text-xs font-semibold text-gray-900", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), selectedTask.taskType === "DecisionPoint" ? (_jsx(Badge, { variant: "outline", className: "border-violet-200 bg-violet-50 text-[10px] uppercase text-violet-700", children: "Decision Point" })) : null, selectedTask.disabled ? (_jsx(Badge, { variant: "outline", className: "text-[10px] uppercase", children: "Disabled" })) : null] }), _jsx("div", { className: "text-xs text-gray-500", children: "Configure task details, assignment, and dependencies." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleDeleteSelectedTask, "data-testid": "project-template-remove-task-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), "Remove Task"] })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-4 pt-3 pb-4", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-task-title-input", children: "Task title" }), _jsx(Input, { id: "project-template-task-title-input", value: selectedTask.title, onChange: (event) => updateSelectedTask((currentTask) => ({
1621
+ const taskPane = (_jsx("div", { className: "flex h-full min-h-0 flex-col overflow-hidden", "data-testid": "project-template-task-detail-pane", children: !selectedTask ? (_jsx("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children: _jsx("div", { className: "rounded-lg border border-dashed border-gray-200 bg-gray-50 p-6 text-center text-xs text-gray-500", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "shrink-0 border-b border-gray-100 bg-white px-4 pt-4 pb-3", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "text-xs font-semibold text-gray-900", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), selectedTask.taskType === "DecisionPoint" ? (_jsx(Badge, { variant: "outline", className: "border-violet-200 bg-violet-50 text-[10px] text-violet-700 uppercase", children: "Decision Point" })) : null, selectedTask.disabled ? (_jsx(Badge, { variant: "outline", className: "text-[10px] uppercase", children: "Disabled" })) : null] }), _jsx("div", { className: "text-xs text-gray-500", children: "Configure task details, assignment, and dependencies." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleDeleteSelectedTask, "data-testid": "project-template-remove-task-button", children: [_jsx(Trash2, { className: "h-4 w-4", strokeWidth: 1.5 }), "Remove Task"] })] }) }), _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-4 pt-3 pb-4", children: _jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid gap-4 md:grid-cols-2", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-task-title-input", children: "Task title" }), _jsx(Input, { id: "project-template-task-title-input", value: selectedTask.title, onChange: (event) => updateSelectedTask((currentTask) => ({
1594
1622
  ...currentTask,
1595
1623
  title: event.target.value,
1596
1624
  })), placeholder: "Task title", className: "text-xs md:text-xs", "data-testid": "project-template-task-title-input" })] }), _jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Description" }), _jsx(Textarea, { className: "text-xs", value: selectedTask.description ?? "", onChange: (event) => updateSelectedTask((currentTask) => ({
@@ -1598,9 +1626,11 @@ export function ProjectTemplatesPanel() {
1598
1626
  description: event.target.value,
1599
1627
  })), rows: 4, placeholder: "Describe what this task should accomplish", "data-testid": "project-template-task-description-input" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Task type" }), _jsx(Select, { className: "text-xs", value: selectedTask.taskType ?? "Task", onValueChange: (value) => updateSelectedTask((currentTask) => ({
1600
1628
  ...currentTask,
1601
- taskType: value === "DecisionPoint" ? "DecisionPoint" : "Task",
1629
+ taskType: value === "DecisionPoint"
1630
+ ? "DecisionPoint"
1631
+ : "Task",
1602
1632
  decisionMode: value === "DecisionPoint"
1603
- ? currentTask.decisionMode ?? "MultiSelect"
1633
+ ? (currentTask.decisionMode ?? "MultiSelect")
1604
1634
  : null,
1605
1635
  })), options: TASK_TYPE_OPTIONS, "data-testid": "project-template-task-type-select" })] }), selectedTask.taskType === "DecisionPoint" ? (_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Decision mode" }), _jsx(Select, { className: "text-xs", value: selectedTask.decisionMode ?? "MultiSelect", onValueChange: (value) => updateSelectedTask((currentTask) => ({
1606
1636
  ...currentTask,
@@ -1610,14 +1640,14 @@ export function ProjectTemplatesPanel() {
1610
1640
  })), options: DECISION_MODE_OPTIONS, "data-testid": "project-template-task-decision-mode-select" })] })) : null, _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", children: "Priority" }), _jsx(Select, { className: "text-xs", value: selectedTask.priority ?? "", onValueChange: (value) => updateSelectedTask((currentTask) => ({
1611
1641
  ...currentTask,
1612
1642
  priority: value || null,
1613
- })), options: PRIORITY_OPTIONS, "data-testid": "project-template-task-priority-select" })] }), selectedTask.taskType === "DecisionPoint" ? (_jsx("div", { className: "grid gap-1.5 md:col-span-2", children: _jsx("div", { className: "rounded-md border border-violet-100 bg-violet-50 px-3 py-2 text-[11px] leading-snug text-violet-800", children: "Direct dependents of this task become selectable option roots when the project is created. Their descendants are materialized only after the Decision Point is resolved at runtime." }) })) : null, _jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx(Label, { className: "text-xs", children: "Default assignee" }), selectedTask.assigneeType === "Agent" ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2 text-xs", onClick: () => void handleEditAssignedAgentProfile(), disabled: !selectedAgentProfileId, "data-testid": "project-template-task-edit-agent-profile-button", children: [_jsx(Settings2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), "Edit Profile"] })) : null] }), _jsx(TaskAssigneePicker, { projectTemplateId: draftTemplate.id, assigneeType: selectedTask.assigneeType ?? null, value: selectedTask.assigneeId ?? null, displayValue: selectedTaskAssigneeDisplayValue, onChange: (next) => updateSelectedTask((currentTask) => ({
1614
- ...currentTask,
1615
- assigneeType: next?.assigneeType ?? null,
1616
- assigneeId: next?.assigneeId ?? null,
1617
- agentProfileId: next?.assigneeType === "Agent"
1618
- ? next.assigneeId
1619
- : null,
1620
- })), placeholder: "Assign user or agent", buttonClassName: "h-[27px] w-full justify-between rounded-md bg-gray-5 text-xs", buttonTestId: "project-template-task-assignee-picker" }), profilesError ? (_jsx("div", { className: "text-xs text-amber-700", children: profilesError })) : null] })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3", "data-testid": "project-template-dependencies-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800", children: [_jsx(Shield, { className: "h-4 w-4 text-gray-500", strokeWidth: 1.5 }), "Dependencies"] }), _jsxs(Popover, { open: dependencyPickerOpen, onOpenChange: setDependencyPickerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", disabled: dependencyAddCandidates.length === 0, "aria-label": "Add dependency", "data-testid": "project-template-add-dependency-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }) }), _jsxs(PopoverContent, { align: "end", className: "w-72 p-0", sideOffset: 6, "data-testid": "project-template-dependency-popover", children: [_jsx("div", { className: "border-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-700", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length === 0 ? (_jsx("div", { className: "px-2 py-3 text-center text-xs text-gray-500", children: "All other tasks are already linked." })) : (dependencyAddCandidates.map((task) => (_jsxs("button", { type: "button", className: "flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-xs hover:bg-gray-100", onClick: () => handleAddDependency(task.id), "data-testid": `project-template-dependency-option-${task.id}`, children: [_jsx(Link2, { className: "h-3.5 w-3.5 shrink-0 text-gray-400", strokeWidth: 1.5 }), _jsx("span", { className: "min-w-0 truncate font-medium text-gray-900", children: task.title || "Untitled Task" })] }, task.id)))) })] })] })] }), _jsx("p", { className: "mb-2 text-[11px] leading-snug text-gray-500", children: "This task must wait for these tasks to finish first." }), dependencyTasks.length === 0 ? (_jsx("div", { className: "text-xs text-gray-500", children: draftTemplate.taskTemplates.filter((t) => t.id !== selectedTask.id).length === 0
1643
+ })), options: PRIORITY_OPTIONS, "data-testid": "project-template-task-priority-select" })] }), selectedTask.taskType === "DecisionPoint" ? (_jsx("div", { className: "grid gap-1.5 md:col-span-2", children: _jsx("div", { className: "rounded-md border border-violet-100 bg-violet-50 px-3 py-2 text-[11px] leading-snug text-violet-800", children: "Direct dependents of this task become selectable option roots when the project is created. Their descendants are materialized only after the Decision Point is resolved at runtime." }) })) : null, _jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", children: "Default assignee" }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsx(TaskAssigneePicker, { projectTemplateId: draftTemplate.id, assigneeType: selectedTask.assigneeType ?? null, value: selectedTask.assigneeId ?? null, displayValue: selectedTaskAssigneeDisplayValue, onChange: (next) => updateSelectedTask((currentTask) => ({
1644
+ ...currentTask,
1645
+ assigneeType: next?.assigneeType ?? null,
1646
+ assigneeId: next?.assigneeId ?? null,
1647
+ agentProfileId: next?.assigneeType === "Agent"
1648
+ ? next.assigneeId
1649
+ : null,
1650
+ })), placeholder: "Assign user or agent", buttonClassName: "h-[27px] w-full justify-between rounded-md bg-gray-5 text-xs", buttonTestId: "project-template-task-assignee-picker" }) }), selectedTask.assigneeType === "Agent" ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-[27px] shrink-0 gap-1 px-2 text-xs", onClick: () => void handleEditAssignedAgentProfile(), disabled: !selectedAgentProfileId, "data-testid": "project-template-task-edit-agent-profile-button", children: [_jsx(Settings2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }), "Edit Profile"] })) : null] }), profilesError ? (_jsx("div", { className: "text-xs text-amber-700", children: profilesError })) : null] })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "rounded-lg border border-gray-200 bg-gray-50 p-3", "data-testid": "project-template-dependencies-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-xs font-medium text-gray-800", children: [_jsx(Shield, { className: "h-4 w-4 text-gray-500", strokeWidth: 1.5 }), "Dependencies"] }), _jsxs(Popover, { open: dependencyPickerOpen, onOpenChange: setDependencyPickerOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", disabled: dependencyAddCandidates.length === 0, "aria-label": "Add dependency", "data-testid": "project-template-add-dependency-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) }) }), _jsxs(PopoverContent, { align: "end", className: "w-72 p-0", sideOffset: 6, "data-testid": "project-template-dependency-popover", children: [_jsx("div", { className: "border-b border-gray-100 px-3 py-2 text-xs font-medium text-gray-700", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length === 0 ? (_jsx("div", { className: "px-2 py-3 text-center text-xs text-gray-500", children: "All other tasks are already linked." })) : (dependencyAddCandidates.map((task) => (_jsxs("button", { type: "button", className: "flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-xs hover:bg-gray-100", onClick: () => handleAddDependency(task.id), "data-testid": `project-template-dependency-option-${task.id}`, children: [_jsx(Link2, { className: "h-3.5 w-3.5 shrink-0 text-gray-400", strokeWidth: 1.5 }), _jsx("span", { className: "min-w-0 truncate font-medium text-gray-900", children: task.title || "Untitled Task" })] }, task.id)))) })] })] })] }), _jsx("p", { className: "mb-2 text-[11px] leading-snug text-gray-500", children: "This task must wait for these tasks to finish first." }), dependencyTasks.length === 0 ? (_jsx("div", { className: "text-xs text-gray-500", children: draftTemplate.taskTemplates.filter((t) => t.id !== selectedTask.id).length === 0
1621
1651
  ? "Add more task templates to create dependencies."
1622
1652
  : "No dependencies yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: dependencyTasks.map((task) => (_jsxs("li", { tabIndex: 0, className: cn("flex items-center justify-between gap-2 rounded-md border bg-white px-3 py-2 text-xs transition-colors outline-none", selectedDependencyId === task.id
1623
1653
  ? "border-amber-300 bg-amber-50 ring-1 ring-amber-200"
@@ -1693,7 +1723,9 @@ export function ProjectTemplatesPanel() {
1693
1723
  openInWizardMode: checked,
1694
1724
  })), "aria-label": "Open new projects from this template in wizard mode", "data-testid": "project-template-open-in-wizard-mode-switch" })] })] }));
1695
1725
  const taskEditorContent = (_jsx("div", { className: "flex h-full min-h-0 flex-1 flex-col overflow-hidden", children: renderTemplateTaskEditorMain() }));
1696
- return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain p-5 md:overflow-hidden", children: [_jsx("div", { className: "flex shrink-0 flex-col gap-5 md:max-h-[50vh] md:min-h-0 md:overflow-y-auto md:overscroll-y-contain", children: saveError && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 px-4 py-3 text-xs text-red-700", children: saveError })) }), _jsxs("section", { className: "flex min-h-0 flex-1 flex-col rounded-lg border border-gray-200 bg-white shadow-sm md:overflow-hidden", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-gray-100 px-4 py-3", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsx(SimpleTabs, { tabs: detailTabs, activeTab: activeDetailTab === "basic" ? 0 : 1, setActiveTab: (index) => setActiveDetailTab(index === 0 ? "basic" : "tasks"), hideContent: true, variant: "elegant", className: "w-full justify-start gap-6" }) }), activeDetailTab === "tasks" ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => void handleOpenCreateTaskDialog(), disabled: creatingTask, "data-testid": "project-template-add-task-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Add Task"] })) : null] }), _jsx("div", { className: "flex flex-col min-h-0 flex-1 overflow-hidden", children: activeDetailTab === "basic"
1726
+ return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain p-5 md:overflow-hidden", children: [_jsx("div", { className: "flex shrink-0 flex-col gap-5 md:max-h-[50vh] md:min-h-0 md:overflow-y-auto md:overscroll-y-contain", children: saveError && (_jsx("div", { className: "rounded border border-red-200 bg-red-50 px-4 py-3 text-xs text-red-700", children: saveError })) }), _jsxs("section", { className: "flex min-h-0 flex-1 flex-col rounded-lg border border-gray-200 bg-white shadow-sm md:overflow-hidden", children: [_jsxs("div", { className: "flex shrink-0 items-center justify-between gap-3 border-b border-gray-100 px-2 py-1", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsx(SimpleTabs, { tabs: detailTabs, activeTab: activeDetailTab === "basic" ? 0 : 1, setActiveTab: (index) => setActiveDetailTab(index === 0 ? "basic" : "tasks"), hideContent: true, variant: "elegant", className: "w-full justify-start gap-6" }) }), _jsxs(Button, { size: "sm", variant: "outline", onClick: () => void handleOpenCreateTaskDialog(), disabled: creatingTask, "data-testid": "project-template-add-task-button", className: activeDetailTab === "tasks"
1727
+ ? ""
1728
+ : "pointer-events-none invisible", "aria-hidden": activeDetailTab !== "tasks", tabIndex: activeDetailTab === "tasks" ? undefined : -1, children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Add Task"] })] }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: activeDetailTab === "basic"
1697
1729
  ? basicSettingsContent
1698
1730
  : taskEditorContent })] })] }));
1699
1731
  })()) : (_jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-5", children: _jsxs("div", { className: "max-w-sm rounded-lg border border-dashed border-gray-300 bg-white p-8 text-center", children: [_jsx(GitBranch, { className: "mx-auto mb-3 h-10 w-10 text-gray-300", strokeWidth: 1.2 }), _jsx("h3", { className: "text-xs font-semibold text-gray-900", children: "Select a project template" }), _jsx("p", { className: "mt-1 text-xs text-gray-500", children: "Choose a template from the dropdown or create a new one to start editing." })] }) }))] }));
@@ -1719,7 +1751,7 @@ export function ProjectTemplatesPanel() {
1719
1751
  hidden: isMobile && mobileView !== "agent",
1720
1752
  },
1721
1753
  ];
1722
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-full", "data-testid": "project-template-editor", onKeyDownCapture: handleProjectTemplateEditorKeyDownCapture, children: _jsx(Splitter, { panels: panels, localStorageKey: "settings-project-templates-panel-splitter-v3", direction: "horizontal", className: "h-full" }) }), _jsx(Dialog, { open: isCreateTaskDialogOpen, onOpenChange: (open) => {
1754
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: "h-full", "data-testid": "project-template-editor", onKeyDownCapture: handleProjectTemplateEditorKeyDownCapture, children: _jsx(Splitter, { panels: panels, localStorageKey: "settings-project-templates-panel-splitter-v3", direction: "horizontal", className: "h-full", forceExpandLastPanelKey: editingAgentProfile?.id ?? null }) }), _jsx(Dialog, { open: isCreateTaskDialogOpen, onOpenChange: (open) => {
1723
1755
  setIsCreateTaskDialogOpen(open);
1724
1756
  if (!open) {
1725
1757
  setNewTaskDependencySourceId(null);