@parhelia/core 0.3.12791 → 0.3.12806

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 (101) hide show
  1. package/dist/components/ui/PlaceholderInput.js +16 -2
  2. package/dist/components/ui/PlaceholderInput.js.map +1 -1
  3. package/dist/editor/FieldHistory.js +12 -2
  4. package/dist/editor/FieldHistory.js.map +1 -1
  5. package/dist/editor/ai/agentTodoExtraction.d.ts +1 -0
  6. package/dist/editor/ai/agentTodoExtraction.js +3 -0
  7. package/dist/editor/ai/agentTodoExtraction.js.map +1 -1
  8. package/dist/editor/ai/terminal/agentSessionState.js +26 -4
  9. package/dist/editor/ai/terminal/agentSessionState.js.map +1 -1
  10. package/dist/editor/ai/terminal/components/AgentThinkingIndicator.js +2 -1
  11. package/dist/editor/ai/terminal/components/AgentThinkingIndicator.js.map +1 -1
  12. package/dist/editor/ai/terminal/components/AiResponseMessage.js +55 -41
  13. package/dist/editor/ai/terminal/components/AiResponseMessage.js.map +1 -1
  14. package/dist/editor/ai/terminal/components/ApprovalCard.d.ts +1 -0
  15. package/dist/editor/ai/terminal/components/ApprovalCard.js +15 -1
  16. package/dist/editor/ai/terminal/components/ApprovalCard.js.map +1 -1
  17. package/dist/editor/ai/terminal/components/EditFieldToolCallContent.d.ts +24 -0
  18. package/dist/editor/ai/terminal/components/EditFieldToolCallContent.js +97 -0
  19. package/dist/editor/ai/terminal/components/EditFieldToolCallContent.js.map +1 -0
  20. package/dist/editor/ai/terminal/components/InitialThinkingSplash.js +2 -1
  21. package/dist/editor/ai/terminal/components/InitialThinkingSplash.js.map +1 -1
  22. package/dist/editor/ai/terminal/components/TodoListPanel.js +5 -3
  23. package/dist/editor/ai/terminal/components/TodoListPanel.js.map +1 -1
  24. package/dist/editor/ai/terminal/components/ToolCallDisplay.d.ts +4 -1
  25. package/dist/editor/ai/terminal/components/ToolCallDisplay.js +33 -5
  26. package/dist/editor/ai/terminal/components/ToolCallDisplay.js.map +1 -1
  27. package/dist/editor/ai/terminal/components/ValueDiff.d.ts +15 -0
  28. package/dist/editor/ai/terminal/components/ValueDiff.js +21 -0
  29. package/dist/editor/ai/terminal/components/ValueDiff.js.map +1 -0
  30. package/dist/editor/ai/terminal/components/agentThinkingStyles.d.ts +1 -0
  31. package/dist/editor/ai/terminal/components/agentThinkingStyles.js +2 -0
  32. package/dist/editor/ai/terminal/components/agentThinkingStyles.js.map +1 -0
  33. package/dist/editor/ai/terminal/components/toolCallContentRenderers.d.ts +15 -0
  34. package/dist/editor/ai/terminal/components/toolCallContentRenderers.js +12 -0
  35. package/dist/editor/ai/terminal/components/toolCallContentRenderers.js.map +1 -0
  36. package/dist/editor/ai/terminal/useAgentPromptQueueSocketHandler.d.ts +0 -2
  37. package/dist/editor/ai/terminal/useAgentPromptQueueSocketHandler.js +6 -5
  38. package/dist/editor/ai/terminal/useAgentPromptQueueSocketHandler.js.map +1 -1
  39. package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.d.ts +1 -0
  40. package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.js +6 -1
  41. package/dist/editor/ai/terminal/useAgentRunResyncSocketHandler.js.map +1 -1
  42. package/dist/editor/ai/terminal/useAgentRunStatusSocketHandler.js +3 -3
  43. package/dist/editor/ai/terminal/useAgentRunStatusSocketHandler.js.map +1 -1
  44. package/dist/editor/ai/terminal/useAgentStopCommand.d.ts +0 -1
  45. package/dist/editor/ai/terminal/useAgentStopCommand.js +3 -5
  46. package/dist/editor/ai/terminal/useAgentStopCommand.js.map +1 -1
  47. package/dist/editor/ai/terminal/useAgentStreamPipeline.js +1 -1
  48. package/dist/editor/ai/terminal/useAgentStreamPipeline.js.map +1 -1
  49. package/dist/editor/ai/types.d.ts +1 -0
  50. package/dist/editor/bridge/protocol.d.ts +7 -0
  51. package/dist/editor/bridge/protocol.js.map +1 -1
  52. package/dist/editor/client/EditorShell.js +29 -5
  53. package/dist/editor/client/EditorShell.js.map +1 -1
  54. package/dist/editor/client/hooks/useSocketMessageHandler.js +14 -0
  55. package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
  56. package/dist/editor/client/itemsRepository.js +14 -1
  57. package/dist/editor/client/itemsRepository.js.map +1 -1
  58. package/dist/editor/client/pageModelBuilder.js +6 -1
  59. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  60. package/dist/editor/client/waitForEditOperationTerminal.js +1 -1
  61. package/dist/editor/client/waitForEditOperationTerminal.js.map +1 -1
  62. package/dist/editor/content-tree/TreeSettingsMenu.js +1 -1
  63. package/dist/editor/content-tree/TreeSettingsMenu.js.map +1 -1
  64. package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +94 -38
  65. package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
  66. package/dist/editor/page-editor-chrome/bridgeLinkValue.d.ts +10 -0
  67. package/dist/editor/page-editor-chrome/bridgeLinkValue.js +55 -0
  68. package/dist/editor/page-editor-chrome/bridgeLinkValue.js.map +1 -0
  69. package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.d.ts +4 -0
  70. package/dist/editor/page-editor-chrome/overlay/IframeOverlayProvider.js.map +1 -1
  71. package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +23 -1
  72. package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
  73. package/dist/editor/page-viewer/PageViewerFrame.js +29 -2
  74. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  75. package/dist/editor/page-viewer/bridgeFieldPatch.js +1 -0
  76. package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
  77. package/dist/editor/reviews/ReviewDetail.d.ts +1 -0
  78. package/dist/editor/reviews/ReviewDetail.js +18 -8
  79. package/dist/editor/reviews/ReviewDetail.js.map +1 -1
  80. package/dist/editor/services/agentService.d.ts +6 -0
  81. package/dist/editor/services/agentService.js.map +1 -1
  82. package/dist/editor/settings/panels/ProjectTemplatesPanel.d.ts +4 -0
  83. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +148 -6
  84. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  85. package/dist/editor/settings/panels/projectTemplateDuplication.js +5 -0
  86. package/dist/editor/settings/panels/projectTemplateDuplication.js.map +1 -1
  87. package/dist/editor/setup-wizard/steps/CreateSettingsStep.js +9 -4
  88. package/dist/editor/setup-wizard/steps/CreateSettingsStep.js.map +1 -1
  89. package/dist/editor/sidebar/MainContentTree.js +1 -1
  90. package/dist/editor/sidebar/MainContentTree.js.map +1 -1
  91. package/dist/editor/ui/CopyMoveTargetSelectorDialog.js +26 -10
  92. package/dist/editor/ui/CopyMoveTargetSelectorDialog.js.map +1 -1
  93. package/dist/revision.d.ts +2 -2
  94. package/dist/revision.js +2 -2
  95. package/dist/task-board/TaskBoardWorkspace.js +5 -9
  96. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  97. package/dist/task-board/taskExecutionRecords.d.ts +1 -0
  98. package/dist/task-board/taskExecutionRecords.js +22 -0
  99. package/dist/task-board/taskExecutionRecords.js.map +1 -1
  100. package/dist/task-board/types.d.ts +9 -0
  101. package/package.json +1 -1
@@ -1,5 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, Link2, PanelRightOpen, Plus, RefreshCw, Settings2, Shield, Trash2, X, } from "lucide-react";
2
+ import { ArrowDown, ArrowUp, ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, ListChecks, Link2, PanelRightOpen, Plus, RefreshCw, Settings2, Shield, Trash2, X, } from "lucide-react";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState, Suspense, lazy, } from "react";
4
4
  import { toast } from "sonner";
5
5
  import { Badge } from "../../../components/ui/badge";
@@ -91,7 +91,17 @@ function isProjectTemplateItemChange(changes, selectedTemplateId) {
91
91
  function cloneTemplate(template) {
92
92
  return normalizeProjectTemplate(JSON.parse(JSON.stringify(template)));
93
93
  }
94
- function normalizeTaskTemplate(task) {
94
+ function normalizeTaskTemplateTodo(todo, index) {
95
+ return {
96
+ ...todo,
97
+ id: todo.id?.trim() || crypto.randomUUID(),
98
+ title: todo.title ?? "",
99
+ instructions: todo.instructions ?? "",
100
+ agentProfileId: todo.agentProfileId?.trim() || null,
101
+ sortOrder: Number.isFinite(todo.sortOrder) ? todo.sortOrder : index * 100,
102
+ };
103
+ }
104
+ export function normalizeTaskTemplate(task) {
95
105
  const rawAssigneeId = task.assigneeId?.trim() || null;
96
106
  const rawAgentProfileId = task.agentProfileId?.trim() || null;
97
107
  const rawParentTaskId = task.parentTaskId?.trim() || null;
@@ -108,6 +118,8 @@ function normalizeTaskTemplate(task) {
108
118
  : "MultiSelect"
109
119
  : null;
110
120
  const assigneeType = task.assigneeType ?? (rawAgentProfileId ? "Agent" : null);
121
+ const todos = (task.todos ?? []).map(normalizeTaskTemplateTodo);
122
+ const todosManaged = task.todosManaged === true && todos.length > 0;
111
123
  if (assigneeType === "Agent") {
112
124
  const canonicalAgentId = rawAgentProfileId || (isValidGuid(rawAssigneeId) ? rawAssigneeId : null);
113
125
  return {
@@ -120,6 +132,8 @@ function normalizeTaskTemplate(task) {
120
132
  agentProfileId: canonicalAgentId,
121
133
  parentTaskId: rawParentTaskId,
122
134
  dependencyIds,
135
+ todos,
136
+ todosManaged,
123
137
  };
124
138
  }
125
139
  if (assigneeType === "user" || assigneeType === "Role") {
@@ -133,6 +147,8 @@ function normalizeTaskTemplate(task) {
133
147
  agentProfileId: null,
134
148
  parentTaskId: rawParentTaskId,
135
149
  dependencyIds,
150
+ todos,
151
+ todosManaged,
136
152
  };
137
153
  }
138
154
  return {
@@ -145,6 +161,8 @@ function normalizeTaskTemplate(task) {
145
161
  agentProfileId: null,
146
162
  parentTaskId: rawParentTaskId,
147
163
  dependencyIds,
164
+ todos,
165
+ todosManaged,
148
166
  };
149
167
  }
150
168
  function normalizeGraphOrientation(orientation) {
@@ -196,6 +214,17 @@ function createEmptyTaskTemplate(taskCount, title) {
196
214
  sortOrder: taskCount * 100,
197
215
  parentTaskId: null,
198
216
  dependencyIds: [],
217
+ todos: [],
218
+ todosManaged: false,
219
+ };
220
+ }
221
+ function createEmptyTaskTemplateTodo(todoCount) {
222
+ return {
223
+ id: crypto.randomUUID(),
224
+ title: `Todo ${todoCount + 1}`,
225
+ instructions: "",
226
+ agentProfileId: null,
227
+ sortOrder: todoCount * 100,
199
228
  };
200
229
  }
201
230
  function createEmptyGoalDefinition(goalCount, title) {
@@ -212,7 +241,7 @@ function createEmptyGoalDefinition(goalCount, title) {
212
241
  function sortTemplates(templates) {
213
242
  return [...templates].sort((left, right) => left.name.localeCompare(right.name, undefined, { sensitivity: "base" }));
214
243
  }
215
- function buildUpsertTemplateRequest(template) {
244
+ export function buildUpsertTemplateRequest(template) {
216
245
  return {
217
246
  projectTemplateId: template.id,
218
247
  name: template.name.trim(),
@@ -249,6 +278,15 @@ function buildUpsertTemplateRequest(template) {
249
278
  assigneeType: normalizedTask.assigneeType || null,
250
279
  assigneeId: normalizedTask.assigneeId || null,
251
280
  dependencyIds: Array.from(new Set(normalizedTask.dependencyIds || [])),
281
+ todosManaged: normalizedTask.todosManaged === true &&
282
+ (normalizedTask.todos?.length ?? 0) > 0,
283
+ todos: (normalizedTask.todos ?? []).map((todo, todoIndex) => ({
284
+ id: todo.id,
285
+ title: todo.title.trim(),
286
+ instructions: todo.instructions?.trim() || null,
287
+ agentProfileId: todo.agentProfileId || null,
288
+ sortOrder: todoIndex * 100,
289
+ })),
252
290
  };
253
291
  }),
254
292
  goalTemplates: (template.goalTemplates ?? []).map((goal, index) => ({
@@ -262,7 +300,7 @@ function buildUpsertTemplateRequest(template) {
262
300
  })),
263
301
  };
264
302
  }
265
- function mergeTemplateResponseWithRequest(serverTemplate, request) {
303
+ export function mergeTemplateResponseWithRequest(serverTemplate, request) {
266
304
  const requestedTaskById = new Map((request.taskTemplates ?? []).map((task) => [task.id, task]));
267
305
  const requestedGoalById = new Map((request.goalTemplates ?? []).map((goal) => [goal.id, goal]));
268
306
  // Server re-reads goals after BeginEdit/EndEdit; if a just-written goal is
@@ -310,6 +348,9 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
310
348
  dependencyIds: serverDeps.length === 0 && requestedDeps.length > 0
311
349
  ? Array.from(new Set(requestedDeps))
312
350
  : serverDeps,
351
+ todos: requested?.todos ?? task.todos ?? [],
352
+ todosManaged: (requested?.todos?.length ?? task.todos?.length ?? 0) > 0 &&
353
+ (requested?.todosManaged ?? task.todosManaged) === true,
313
354
  };
314
355
  }),
315
356
  });
@@ -530,6 +571,7 @@ export function ProjectTemplatesPanel() {
530
571
  const [templates, setTemplates] = useState([]);
531
572
  const [error, setError] = useState(null);
532
573
  const [selectedTemplateId, setSelectedTemplateId] = useState(null);
574
+ const [persistedTemplateId, setPersistedTemplateId] = useState(null);
533
575
  const [draftTemplate, setDraftTemplate] = useState(null);
534
576
  const [selectedTaskId, setSelectedTaskId] = useState(null);
535
577
  const [saving, setSaving] = useState(false);
@@ -834,6 +876,7 @@ export function ProjectTemplatesPanel() {
834
876
  selectedTemplateIdRef.current = template?.id ?? null;
835
877
  draftTemplateRef.current = clonedTemplate;
836
878
  setSelectedTemplateId(template?.id ?? null);
879
+ setPersistedTemplateId(template?.id ?? null);
837
880
  setDraftTemplate(clonedTemplate);
838
881
  setEditingAgentProfile(null);
839
882
  setSelectedTaskId(getSelectedTaskIdForTemplate(clonedTemplate, preferredTaskId));
@@ -960,6 +1003,16 @@ export function ProjectTemplatesPanel() {
960
1003
  }
961
1004
  return byId;
962
1005
  }, [aiProfiles]);
1006
+ const taskTodoProfileOptions = useMemo(() => [
1007
+ { value: "__task_agent__", label: "Use task agent profile" },
1008
+ ...aiProfiles
1009
+ .filter((profile) => !!profile.id)
1010
+ .map((profile) => ({
1011
+ value: profile.id,
1012
+ label: profile.displayTitle || profile.name || profile.id,
1013
+ }))
1014
+ .sort((left, right) => left.label.localeCompare(right.label)),
1015
+ ], [aiProfiles]);
963
1016
  const selectedTask = useMemo(() => draftTemplate?.taskTemplates.find((task) => task.id === selectedTaskId) ??
964
1017
  null, [draftTemplate, selectedTaskId]);
965
1018
  const templateAgentInitialMetadata = useMemo(() => draftTemplate
@@ -1059,6 +1112,16 @@ export function ProjectTemplatesPanel() {
1059
1112
  setTemplateAgentError(null);
1060
1113
  return;
1061
1114
  }
1115
+ // New and duplicated templates are shown optimistically before their first
1116
+ // save has reached Sitecore. Resolving the assistant during that window
1117
+ // races the upsert and produces a transient "Project template not found"
1118
+ // response. Wait until persistTemplate confirms this ID exists remotely.
1119
+ if (persistedTemplateId !== selectedTemplateId) {
1120
+ setTemplateAgentId(null);
1121
+ setTemplateAgentLoading(true);
1122
+ setTemplateAgentError(null);
1123
+ return;
1124
+ }
1062
1125
  setTemplateAgentId(null);
1063
1126
  setTemplateAgentLoading(true);
1064
1127
  setTemplateAgentError(null);
@@ -1082,7 +1145,12 @@ export function ProjectTemplatesPanel() {
1082
1145
  ? loadError.message
1083
1146
  : "Failed to load project template assistant");
1084
1147
  });
1085
- }, [draftTemplate?.id, selectedTemplateId, syncProjectTemplateAgentContext]);
1148
+ }, [
1149
+ draftTemplate?.id,
1150
+ persistedTemplateId,
1151
+ selectedTemplateId,
1152
+ syncProjectTemplateAgentContext,
1153
+ ]);
1086
1154
  useEffect(() => {
1087
1155
  if (!templateAgentId || templateAgentLoading)
1088
1156
  return;
@@ -1122,6 +1190,59 @@ export function ProjectTemplatesPanel() {
1122
1190
  taskTemplates: currentTemplate.taskTemplates.map((task) => task.id === selectedTaskId ? updater({ ...task }) : task),
1123
1191
  }));
1124
1192
  }, [applyDraftChange, selectedTaskId]);
1193
+ const handleAddTaskTodo = useCallback(() => {
1194
+ updateSelectedTask((currentTask) => ({
1195
+ ...currentTask,
1196
+ todos: [
1197
+ ...(currentTask.todos ?? []),
1198
+ createEmptyTaskTemplateTodo(currentTask.todos?.length ?? 0),
1199
+ ],
1200
+ }));
1201
+ }, [updateSelectedTask]);
1202
+ const handleUpdateTaskTodo = useCallback((todoId, updater) => {
1203
+ updateSelectedTask((currentTask) => ({
1204
+ ...currentTask,
1205
+ todos: (currentTask.todos ?? []).map((todo) => todo.id === todoId ? updater({ ...todo }) : todo),
1206
+ }));
1207
+ }, [updateSelectedTask]);
1208
+ const handleRemoveTaskTodo = useCallback((todoId) => {
1209
+ updateSelectedTask((currentTask) => {
1210
+ const todos = (currentTask.todos ?? [])
1211
+ .filter((todo) => todo.id !== todoId)
1212
+ .map((todo, index) => ({ ...todo, sortOrder: index * 100 }));
1213
+ return {
1214
+ ...currentTask,
1215
+ todos,
1216
+ todosManaged: todos.length > 0 && currentTask.todosManaged === true,
1217
+ };
1218
+ });
1219
+ }, [updateSelectedTask]);
1220
+ const handleMoveTaskTodo = useCallback((todoId, direction) => {
1221
+ updateSelectedTask((currentTask) => {
1222
+ const todos = [...(currentTask.todos ?? [])];
1223
+ const currentIndex = todos.findIndex((todo) => todo.id === todoId);
1224
+ const targetIndex = currentIndex + direction;
1225
+ if (currentIndex < 0 ||
1226
+ targetIndex < 0 ||
1227
+ targetIndex >= todos.length) {
1228
+ return currentTask;
1229
+ }
1230
+ const currentTodo = todos[currentIndex];
1231
+ const targetTodo = todos[targetIndex];
1232
+ if (currentTodo === undefined || targetTodo === undefined) {
1233
+ return currentTask;
1234
+ }
1235
+ todos[currentIndex] = targetTodo;
1236
+ todos[targetIndex] = currentTodo;
1237
+ return {
1238
+ ...currentTask,
1239
+ todos: todos.map((todo, index) => ({
1240
+ ...todo,
1241
+ sortOrder: index * 100,
1242
+ })),
1243
+ };
1244
+ });
1245
+ }, [updateSelectedTask]);
1125
1246
  const updateSelectedGoal = useCallback((updater) => {
1126
1247
  if (!selectedGoalId)
1127
1248
  return;
@@ -1245,6 +1366,9 @@ export function ProjectTemplatesPanel() {
1245
1366
  }
1246
1367
  const savedTemplate = mergeTemplateResponseWithRequest(result.data, request);
1247
1368
  lastPersistedSignatureRef.current = signature;
1369
+ if (selectedTemplateIdRef.current === savedTemplate.id) {
1370
+ setPersistedTemplateId(savedTemplate.id);
1371
+ }
1248
1372
  setTemplates((existingTemplates) => sortTemplates([
1249
1373
  ...existingTemplates.filter((template) => template.id !== savedTemplate.id),
1250
1374
  savedTemplate,
@@ -1511,6 +1635,7 @@ export function ProjectTemplatesPanel() {
1511
1635
  latestDraftSignatureRef.current = signature;
1512
1636
  setTemplates((current) => sortTemplates([nextTemplate, ...current]));
1513
1637
  setSelectedTemplateId(nextTemplate.id);
1638
+ setPersistedTemplateId(null);
1514
1639
  setDraftTemplate(cloneTemplate(nextTemplate));
1515
1640
  setSelectedTaskId(null);
1516
1641
  setSelectedGoalId(null);
@@ -1572,6 +1697,7 @@ export function ProjectTemplatesPanel() {
1572
1697
  latestDraftSignatureRef.current = signature;
1573
1698
  setTemplates((current) => sortTemplates([nextTemplate, ...current]));
1574
1699
  setSelectedTemplateId(nextTemplate.id);
1700
+ setPersistedTemplateId(null);
1575
1701
  setDraftTemplate(cloneTemplate(nextTemplate));
1576
1702
  setSelectedTaskId(getSelectedTaskIdForTemplate(nextTemplate, null));
1577
1703
  setSelectedGoalId(null);
@@ -2257,7 +2383,23 @@ export function ProjectTemplatesPanel() {
2257
2383
  agentProfileId: next?.assigneeType === "Agent"
2258
2384
  ? next.assigneeId
2259
2385
  : null,
2260
- })), placeholder: "Assign user or agent", buttonClassName: "h-8 min-h-0 w-full justify-between rounded-md bg-white text-xs", buttonTestId: "project-template-task-assignee-picker" }) }), selectedTask.assigneeType === "Agent" ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-8 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 }), "Edit Profile"] })) : null] }), profilesError ? (_jsx("div", { className: "text-feedback-orange text-xs", children: profilesError })) : null] })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border 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: "text-neutral-grey-100 flex items-center gap-2 text-xs font-medium", children: [_jsx(Shield, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1 }), "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 }) }) }), _jsxs(PopoverContent, { align: "end", className: "w-72 p-0", sideOffset: 6, "data-testid": "project-template-dependency-popover", children: [_jsx("div", { className: "border-border-default text-neutral-grey-100 border-b px-3 py-2 text-xs font-medium", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 px-2 py-3 text-center text-xs", children: "All other tasks are already linked." })) : (dependencyAddCandidates.map((task) => (_jsxs("button", { type: "button", className: "hover:bg-neutral-grey-5 flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-xs", onClick: () => handleAddDependency(task.id), "data-testid": `project-template-dependency-option-${task.id}`, children: [_jsx(Link2, { className: "text-neutral-grey-50 h-3.5 w-3.5 shrink-0", strokeWidth: 1 }), _jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" })] }, task.id)))) })] })] })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "This task must wait for these tasks to finish first." }), dependencyTasks.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: draftTemplate.taskTemplates.filter((t) => t.id !== selectedTask.id).length === 0
2386
+ })), placeholder: "Assign user or agent", buttonClassName: "h-8 min-h-0 w-full justify-between rounded-md bg-white text-xs", buttonTestId: "project-template-task-assignee-picker" }) }), selectedTask.assigneeType === "Agent" ? (_jsxs(Button, { type: "button", size: "sm", variant: "outline", className: "h-8 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 }), "Edit Profile"] })) : null] }), profilesError ? (_jsx("div", { className: "text-feedback-orange text-xs", children: profilesError })) : null] })] }), _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border p-3", "data-testid": "project-template-todos-section", children: [_jsxs("div", { className: "mb-2 flex items-center justify-between gap-2", children: [_jsxs("div", { className: "text-neutral-grey-100 flex items-center gap-2 text-xs font-medium", children: [_jsx(ListChecks, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1 }), "Todos"] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("div", { className: "flex items-center gap-1.5", title: (selectedTask.todos?.length ?? 0) > 0
2387
+ ? "Deliver todo items to the agent one at a time"
2388
+ : "Add at least one todo to enable managed execution", children: [_jsx(Switch, { id: "project-template-todos-managed", checked: selectedTask.todosManaged === true, disabled: (selectedTask.todos?.length ?? 0) === 0, onCheckedChange: (checked) => updateSelectedTask((currentTask) => ({
2389
+ ...currentTask,
2390
+ todosManaged: checked &&
2391
+ (currentTask.todos?.length ?? 0) > 0,
2392
+ })), "aria-label": "Managed todo execution", "data-testid": "project-template-todos-managed-toggle" }), _jsx(Label, { htmlFor: "project-template-todos-managed", className: "text-neutral-grey-100 text-xs", children: "Managed" })] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: handleAddTaskTodo, "aria-label": "Add todo", "data-testid": "project-template-add-todo-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1 }) })] })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "These task-specific todos override predefined todos from the assigned agent profile. Managed lists are delivered one item at a time after a brief orientation turn." }), (selectedTask.todos ?? []).length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "No todos yet. The agent profile defaults will be used." })) : (_jsx("div", { className: "space-y-2", children: (selectedTask.todos ?? []).map((todo, todoIndex) => (_jsxs("div", { className: "border-border-default space-y-2 rounded-md border bg-white p-2", "data-testid": `project-template-todo-row-${todo.id}`, children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx(Input, { className: "h-8 min-w-0 flex-1 text-xs md:text-xs", value: todo.title, onChange: (event) => handleUpdateTaskTodo(todo.id, (current) => ({
2393
+ ...current,
2394
+ title: event.target.value,
2395
+ })), placeholder: "Todo title", "aria-label": `Todo ${todoIndex + 1} title`, "data-testid": "project-template-todo-title-input" }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "h-7 w-7 shrink-0", disabled: todoIndex === 0, onClick: () => handleMoveTaskTodo(todo.id, -1), "aria-label": `Move ${todo.title || "todo"} up`, "data-testid": "project-template-move-todo-up", children: _jsx(ArrowUp, { className: "h-3.5 w-3.5", strokeWidth: 1 }) }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "h-7 w-7 shrink-0", disabled: todoIndex ===
2396
+ (selectedTask.todos?.length ?? 0) - 1, onClick: () => handleMoveTaskTodo(todo.id, 1), "aria-label": `Move ${todo.title || "todo"} down`, "data-testid": "project-template-move-todo-down", children: _jsx(ArrowDown, { className: "h-3.5 w-3.5", strokeWidth: 1 }) }), _jsx(Button, { type: "button", size: "icon", variant: "ghost", className: "text-feedback-red h-7 w-7 shrink-0", onClick: () => handleRemoveTaskTodo(todo.id), "aria-label": `Remove ${todo.title || "todo"}`, "data-testid": "project-template-remove-todo-button", children: _jsx(Trash2, { className: "h-3.5 w-3.5", strokeWidth: 1 }) })] }), _jsx(Textarea, { className: "text-xs", rows: 2, value: todo.instructions ?? "", onChange: (event) => handleUpdateTaskTodo(todo.id, (current) => ({
2397
+ ...current,
2398
+ instructions: event.target.value,
2399
+ })), placeholder: "Instructions for completing this todo", "aria-label": `Todo ${todoIndex + 1} instructions`, "data-testid": "project-template-todo-instructions-input" }), _jsx(Select, { value: todo.agentProfileId ?? "__task_agent__", onValueChange: (value) => handleUpdateTaskTodo(todo.id, (current) => ({
2400
+ ...current,
2401
+ agentProfileId: value === "__task_agent__" ? null : value,
2402
+ })), options: taskTodoProfileOptions, searchable: true, placeholder: "Use task agent profile", "data-testid": "project-template-todo-agent-profile-select" })] }, todo.id))) }))] }), _jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border 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: "text-neutral-grey-100 flex items-center gap-2 text-xs font-medium", children: [_jsx(Shield, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1 }), "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 }) }) }), _jsxs(PopoverContent, { align: "end", className: "w-72 p-0", sideOffset: 6, "data-testid": "project-template-dependency-popover", children: [_jsx("div", { className: "border-border-default text-neutral-grey-100 border-b px-3 py-2 text-xs font-medium", children: "Depends on" }), _jsx("div", { className: "max-h-56 overflow-y-auto p-1", children: dependencyAddCandidates.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 px-2 py-3 text-center text-xs", children: "All other tasks are already linked." })) : (dependencyAddCandidates.map((task) => (_jsxs("button", { type: "button", className: "hover:bg-neutral-grey-5 flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-xs", onClick: () => handleAddDependency(task.id), "data-testid": `project-template-dependency-option-${task.id}`, children: [_jsx(Link2, { className: "text-neutral-grey-50 h-3.5 w-3.5 shrink-0", strokeWidth: 1 }), _jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" })] }, task.id)))) })] })] })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "This task must wait for these tasks to finish first." }), dependencyTasks.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: draftTemplate.taskTemplates.filter((t) => t.id !== selectedTask.id).length === 0
2261
2403
  ? "Add more task templates to create dependencies."
2262
2404
  : "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
2263
2405
  ? "border-feedback-orange bg-feedback-orange-light ring-feedback-orange ring-1"