@parhelia/core 0.1.12912 → 0.1.12917

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 (247) hide show
  1. package/dist/agents-view/AgentGalleryCard.js +1 -1
  2. package/dist/agents-view/AgentGalleryCard.js.map +1 -1
  3. package/dist/agents-view/AgentsWorkspaceView.js +15 -2
  4. package/dist/agents-view/AgentsWorkspaceView.js.map +1 -1
  5. package/dist/components/MarkdownViewerPopover.d.ts +73 -0
  6. package/dist/components/MarkdownViewerPopover.js +109 -0
  7. package/dist/components/MarkdownViewerPopover.js.map +1 -0
  8. package/dist/components/PageHeader.d.ts +5 -1
  9. package/dist/components/PageHeader.js +2 -2
  10. package/dist/components/PageHeader.js.map +1 -1
  11. package/dist/components/SearchInput.js +1 -1
  12. package/dist/components/ui/UserPicker.js +1 -1
  13. package/dist/components/ui/UserPicker.js.map +1 -1
  14. package/dist/components/ui/select.js +1 -1
  15. package/dist/components/ui/select.js.map +1 -1
  16. package/dist/config/config.js +17 -2
  17. package/dist/config/config.js.map +1 -1
  18. package/dist/config/types/workspace.d.ts +6 -2
  19. package/dist/editor/ConfirmationDialog.d.ts +3 -0
  20. package/dist/editor/ConfirmationDialog.js +5 -1
  21. package/dist/editor/ConfirmationDialog.js.map +1 -1
  22. package/dist/editor/ContentTree.d.ts +7 -1
  23. package/dist/editor/ContentTree.js +13 -1
  24. package/dist/editor/ContentTree.js.map +1 -1
  25. package/dist/editor/ContextMenu.js +6 -2
  26. package/dist/editor/ContextMenu.js.map +1 -1
  27. package/dist/editor/FieldHistory.js +2 -1
  28. package/dist/editor/FieldHistory.js.map +1 -1
  29. package/dist/editor/FieldListField.js +4 -3
  30. package/dist/editor/FieldListField.js.map +1 -1
  31. package/dist/editor/GlobalMenuBar.js +5 -2
  32. package/dist/editor/GlobalMenuBar.js.map +1 -1
  33. package/dist/editor/MobileLayout.js +4 -1
  34. package/dist/editor/MobileLayout.js.map +1 -1
  35. package/dist/editor/ScrollingContentTree.d.ts +2 -1
  36. package/dist/editor/ScrollingContentTree.js +2 -2
  37. package/dist/editor/ScrollingContentTree.js.map +1 -1
  38. package/dist/editor/Titlebar.d.ts +2 -1
  39. package/dist/editor/Titlebar.js +4 -9
  40. package/dist/editor/Titlebar.js.map +1 -1
  41. package/dist/editor/WorkspaceTitleSwitcher.d.ts +2 -1
  42. package/dist/editor/WorkspaceTitleSwitcher.js +4 -3
  43. package/dist/editor/WorkspaceTitleSwitcher.js.map +1 -1
  44. package/dist/editor/ai/AgentProfileSelector.js +3 -3
  45. package/dist/editor/ai/AgentProfileSelector.js.map +1 -1
  46. package/dist/editor/ai/Agents.js +15 -4
  47. package/dist/editor/ai/Agents.js.map +1 -1
  48. package/dist/editor/ai/InlineAiTrigger.js +5 -1
  49. package/dist/editor/ai/InlineAiTrigger.js.map +1 -1
  50. package/dist/editor/ai/agentActivitySummary.js +17 -9
  51. package/dist/editor/ai/agentActivitySummary.js.map +1 -1
  52. package/dist/editor/ai/dialogs/capturePageScreenshot.d.ts +18 -1
  53. package/dist/editor/ai/dialogs/capturePageScreenshot.js +60 -13
  54. package/dist/editor/ai/dialogs/capturePageScreenshot.js.map +1 -1
  55. package/dist/editor/ai/terminal/components/AgentDocumentList.js +6 -3
  56. package/dist/editor/ai/terminal/components/AgentDocumentList.js.map +1 -1
  57. package/dist/editor/ai/terminal/components/AgentFullPromptControls.d.ts +2 -1
  58. package/dist/editor/ai/terminal/components/AgentFullPromptControls.js +9 -6
  59. package/dist/editor/ai/terminal/components/AgentFullPromptControls.js.map +1 -1
  60. package/dist/editor/ai/terminal/components/AgentModeSelector.js +8 -7
  61. package/dist/editor/ai/terminal/components/AgentModeSelector.js.map +1 -1
  62. package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js +4 -1
  63. package/dist/editor/ai/terminal/components/AgentPromptTrayPopovers.js.map +1 -1
  64. package/dist/editor/ai/terminal/components/AgentSummaryPromptActions.d.ts +2 -1
  65. package/dist/editor/ai/terminal/components/AgentSummaryPromptActions.js +7 -2
  66. package/dist/editor/ai/terminal/components/AgentSummaryPromptActions.js.map +1 -1
  67. package/dist/editor/ai/terminal/components/AgentTerminalSummaryLayout.d.ts +2 -1
  68. package/dist/editor/ai/terminal/components/AgentTerminalSummaryLayout.js +2 -2
  69. package/dist/editor/ai/terminal/components/AgentTerminalSummaryLayout.js.map +1 -1
  70. package/dist/editor/ai/terminal/components/ContextInfoBar.js +35 -8
  71. package/dist/editor/ai/terminal/components/ContextInfoBar.js.map +1 -1
  72. package/dist/editor/ai/terminal/components/UserMessage.js +4 -4
  73. package/dist/editor/ai/terminal/components/UserMessage.js.map +1 -1
  74. package/dist/editor/ai/terminal/projectTemplateContext.d.ts +11 -0
  75. package/dist/editor/ai/terminal/projectTemplateContext.js +64 -0
  76. package/dist/editor/ai/terminal/projectTemplateContext.js.map +1 -0
  77. package/dist/editor/ai/terminal/useAgentLoadPipeline.js +1 -0
  78. package/dist/editor/ai/terminal/useAgentLoadPipeline.js.map +1 -1
  79. package/dist/editor/ai/terminal/useAgentLoader.d.ts +1 -0
  80. package/dist/editor/ai/terminal/useAgentLoader.js +14 -2
  81. package/dist/editor/ai/terminal/useAgentLoader.js.map +1 -1
  82. package/dist/editor/ai/terminal/useAgentSettingsData.js +1 -0
  83. package/dist/editor/ai/terminal/useAgentSettingsData.js.map +1 -1
  84. package/dist/editor/ai/terminal/useAgentSubmitHandlers.d.ts +1 -0
  85. package/dist/editor/ai/terminal/useAgentSubmitHandlers.js +19 -1
  86. package/dist/editor/ai/terminal/useAgentSubmitHandlers.js.map +1 -1
  87. package/dist/editor/ai/terminal/useAgentTerminalController.js +4 -1
  88. package/dist/editor/ai/terminal/useAgentTerminalController.js.map +1 -1
  89. package/dist/editor/ai/useInlineAiPosition.d.ts +2 -1
  90. package/dist/editor/ai/useInlineAiPosition.js +10 -3
  91. package/dist/editor/ai/useInlineAiPosition.js.map +1 -1
  92. package/dist/editor/bridge/protocol.d.ts +22 -1
  93. package/dist/editor/bridge/protocol.js +3 -1
  94. package/dist/editor/bridge/protocol.js.map +1 -1
  95. package/dist/editor/client/EditorShell.js +45 -22
  96. package/dist/editor/client/EditorShell.js.map +1 -1
  97. package/dist/editor/client/editContext.d.ts +1 -0
  98. package/dist/editor/client/editContext.js.map +1 -1
  99. package/dist/editor/client/pageModelBuilder.d.ts +1 -0
  100. package/dist/editor/client/pageModelBuilder.js +9 -2
  101. package/dist/editor/client/pageModelBuilder.js.map +1 -1
  102. package/dist/editor/client/ui/FullscreenControls.js +1 -1
  103. package/dist/editor/client/ui/FullscreenControls.js.map +1 -1
  104. package/dist/editor/commands/componentCommands.d.ts +1 -0
  105. package/dist/editor/commands/componentCommands.js +139 -2
  106. package/dist/editor/commands/componentCommands.js.map +1 -1
  107. package/dist/editor/content-tree/TreeSettingsMenu.js +1 -1
  108. package/dist/editor/content-tree/TreeSettingsMenu.js.map +1 -1
  109. package/dist/editor/fieldTypeConfiguration.d.ts +2 -0
  110. package/dist/editor/fieldTypeConfiguration.js +7 -0
  111. package/dist/editor/fieldTypeConfiguration.js.map +1 -0
  112. package/dist/editor/menubar/PageSelector.js +8 -1
  113. package/dist/editor/menubar/PageSelector.js.map +1 -1
  114. package/dist/editor/menubar/toolbar-sections/DeviceSwitchToolbar.d.ts +2 -1
  115. package/dist/editor/menubar/toolbar-sections/DeviceSwitchToolbar.js +2 -2
  116. package/dist/editor/menubar/toolbar-sections/DeviceSwitchToolbar.js.map +1 -1
  117. package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js +7 -1
  118. package/dist/editor/page-editor-chrome/BridgeInlineFormatOverlay.js.map +1 -1
  119. package/dist/editor/page-editor-chrome/DragInsertionOverlay.js +53 -19
  120. package/dist/editor/page-editor-chrome/DragInsertionOverlay.js.map +1 -1
  121. package/dist/editor/page-editor-chrome/FrameMenu.js +3 -1
  122. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  123. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js +4 -3
  124. package/dist/editor/page-editor-chrome/PlaceholderDropZone.js.map +1 -1
  125. package/dist/editor/page-editor-chrome/bridgeInlineFormatToolbarLayout.d.ts +2 -1
  126. package/dist/editor/page-editor-chrome/bridgeInlineFormatToolbarLayout.js +2 -0
  127. package/dist/editor/page-editor-chrome/bridgeInlineFormatToolbarLayout.js.map +1 -1
  128. package/dist/editor/page-editor-chrome/insertTargetLabel.d.ts +1 -0
  129. package/dist/editor/page-editor-chrome/insertTargetLabel.js +14 -1
  130. package/dist/editor/page-editor-chrome/insertTargetLabel.js.map +1 -1
  131. package/dist/editor/page-editor-chrome/overlay/placeholderZones.js +13 -3
  132. package/dist/editor/page-editor-chrome/overlay/placeholderZones.js.map +1 -1
  133. package/dist/editor/page-editor-chrome/useComponentDragHandle.js +11 -5
  134. package/dist/editor/page-editor-chrome/useComponentDragHandle.js.map +1 -1
  135. package/dist/editor/page-viewer/PageViewer.js +5 -4
  136. package/dist/editor/page-viewer/PageViewer.js.map +1 -1
  137. package/dist/editor/page-viewer/PageViewerFrame.js +53 -3
  138. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  139. package/dist/editor/page-viewer/bridgeFieldPatch.d.ts +3 -1
  140. package/dist/editor/page-viewer/bridgeFieldPatch.js +24 -1
  141. package/dist/editor/page-viewer/bridgeFieldPatch.js.map +1 -1
  142. package/dist/editor/page-viewer/pageViewContext.d.ts +4 -1
  143. package/dist/editor/page-viewer/pageViewContext.js +4 -1
  144. package/dist/editor/page-viewer/pageViewContext.js.map +1 -1
  145. package/dist/editor/page-viewer/parentBridgeInjection.d.ts +23 -0
  146. package/dist/editor/page-viewer/parentBridgeInjection.js +251 -0
  147. package/dist/editor/page-viewer/parentBridgeInjection.js.map +1 -0
  148. package/dist/editor/page-viewer/renderUrl.js +4 -2
  149. package/dist/editor/page-viewer/renderUrl.js.map +1 -1
  150. package/dist/editor/pageModel.d.ts +1 -0
  151. package/dist/editor/reviews/MultiReviewManager.js +3 -22
  152. package/dist/editor/reviews/MultiReviewManager.js.map +1 -1
  153. package/dist/editor/reviews/openCommentsFeedback.js +2 -0
  154. package/dist/editor/reviews/openCommentsFeedback.js.map +1 -1
  155. package/dist/editor/services/agentService.js +6 -2
  156. package/dist/editor/services/agentService.js.map +1 -1
  157. package/dist/editor/services/editService.d.ts +15 -0
  158. package/dist/editor/services/editService.js +3 -0
  159. package/dist/editor/services/editService.js.map +1 -1
  160. package/dist/editor/settings/SettingsBreadcrumb.js +5 -2
  161. package/dist/editor/settings/SettingsBreadcrumb.js.map +1 -1
  162. package/dist/editor/settings/SettingsHeaderActionsContext.d.ts +4 -0
  163. package/dist/editor/settings/SettingsHeaderActionsContext.js.map +1 -1
  164. package/dist/editor/settings/SettingsTitlebar.d.ts +1 -0
  165. package/dist/editor/settings/SettingsTitlebar.js +18 -0
  166. package/dist/editor/settings/SettingsTitlebar.js.map +1 -0
  167. package/dist/editor/settings/SettingsView.js +64 -18
  168. package/dist/editor/settings/SettingsView.js.map +1 -1
  169. package/dist/editor/settings/panels/ModelsPanel.js +4 -3
  170. package/dist/editor/settings/panels/ModelsPanel.js.map +1 -1
  171. package/dist/editor/settings/panels/ProjectTemplateAgentPanel.d.ts +8 -1
  172. package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js +75 -9
  173. package/dist/editor/settings/panels/ProjectTemplateAgentPanel.js.map +1 -1
  174. package/dist/editor/settings/panels/ProjectTemplateSelectorList.js +1 -1
  175. package/dist/editor/settings/panels/ProjectTemplateSelectorList.js.map +1 -1
  176. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +515 -50
  177. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  178. package/dist/editor/settings/panels/ProvidersPanel.js +1 -1
  179. package/dist/editor/settings/panels/ProvidersPanel.js.map +1 -1
  180. package/dist/editor/settings/settingsNavigationStore.d.ts +12 -0
  181. package/dist/editor/settings/settingsNavigationStore.js +32 -0
  182. package/dist/editor/settings/settingsNavigationStore.js.map +1 -0
  183. package/dist/editor/setup-wizard/steps/ProviderStep.js +6 -2
  184. package/dist/editor/setup-wizard/steps/ProviderStep.js.map +1 -1
  185. package/dist/editor/sidebar/ComponentPalette.js +10 -4
  186. package/dist/editor/sidebar/ComponentPalette.js.map +1 -1
  187. package/dist/editor/sidebar/ComponentTree.js +12 -12
  188. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  189. package/dist/editor/sidebar/ContentTreePanel.js +1 -1
  190. package/dist/editor/sidebar/ContentTreePanel.js.map +1 -1
  191. package/dist/editor/sidebar/SidebarPanel.js +1 -1
  192. package/dist/editor/sidebar/SidebarPanel.js.map +1 -1
  193. package/dist/editor/sidebar/WorkspaceRailMobile.d.ts +0 -1
  194. package/dist/editor/sidebar/WorkspaceRailMobile.js +4 -14
  195. package/dist/editor/sidebar/WorkspaceRailMobile.js.map +1 -1
  196. package/dist/editor/ui/ComponentThumbnailDialog.d.ts +14 -0
  197. package/dist/editor/ui/ComponentThumbnailDialog.js +75 -0
  198. package/dist/editor/ui/ComponentThumbnailDialog.js.map +1 -0
  199. package/dist/editor/ui/PublishRestrictionsDialog.js +77 -9
  200. package/dist/editor/ui/PublishRestrictionsDialog.js.map +1 -1
  201. package/dist/editor/ui/Splitter.d.ts +3 -0
  202. package/dist/editor/ui/Splitter.js +30 -16
  203. package/dist/editor/ui/Splitter.js.map +1 -1
  204. package/dist/editor/utils/itemutils.js +2 -0
  205. package/dist/editor/utils/itemutils.js.map +1 -1
  206. package/dist/editor/views/ItemEditorPane.js +1 -1
  207. package/dist/editor/views/ItemEditorPane.js.map +1 -1
  208. package/dist/index.d.ts +5 -1
  209. package/dist/index.js +3 -1
  210. package/dist/index.js.map +1 -1
  211. package/dist/revision.d.ts +2 -2
  212. package/dist/revision.js +2 -2
  213. package/dist/task-board/TaskBoardWorkspace.js +73 -5
  214. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  215. package/dist/task-board/components/CreateProjectDialog.d.ts +0 -1
  216. package/dist/task-board/components/CreateProjectDialog.js +1 -4
  217. package/dist/task-board/components/CreateProjectDialog.js.map +1 -1
  218. package/dist/task-board/components/GoalDialog.d.ts +9 -0
  219. package/dist/task-board/components/GoalDialog.js +149 -0
  220. package/dist/task-board/components/GoalDialog.js.map +1 -0
  221. package/dist/task-board/components/ProjectDashboard.d.ts +10 -0
  222. package/dist/task-board/components/ProjectDashboard.js +3 -3
  223. package/dist/task-board/components/ProjectDashboard.js.map +1 -1
  224. package/dist/task-board/components/ProjectGoalsPanel.d.ts +16 -0
  225. package/dist/task-board/components/ProjectGoalsPanel.js +310 -0
  226. package/dist/task-board/components/ProjectGoalsPanel.js.map +1 -0
  227. package/dist/task-board/components/ProjectPropertiesPanel.js +5 -3
  228. package/dist/task-board/components/ProjectPropertiesPanel.js.map +1 -1
  229. package/dist/task-board/components/TaskAssigneePicker.js +1 -1
  230. package/dist/task-board/components/TaskAssigneePicker.js.map +1 -1
  231. package/dist/task-board/components/TaskAttachmentDropZone.d.ts +1 -0
  232. package/dist/task-board/components/TaskAttachmentDropZone.js +5 -3
  233. package/dist/task-board/components/TaskAttachmentDropZone.js.map +1 -1
  234. package/dist/task-board/components/TaskAttachmentsSection.js +8 -1
  235. package/dist/task-board/components/TaskAttachmentsSection.js.map +1 -1
  236. package/dist/task-board/components/WizardCommunicationCenter.js +1 -10
  237. package/dist/task-board/components/WizardCommunicationCenter.js.map +1 -1
  238. package/dist/task-board/services/goalService.d.ts +65 -0
  239. package/dist/task-board/services/goalService.js +37 -0
  240. package/dist/task-board/services/goalService.js.map +1 -0
  241. package/dist/task-board/types.d.ts +68 -3
  242. package/dist/task-board/views/DependencyGraphView.js +121 -31
  243. package/dist/task-board/views/DependencyGraphView.js.map +1 -1
  244. package/package.json +2 -2
  245. package/dist/editor/sidebar/MobileWorkspacePopover.d.ts +0 -16
  246. package/dist/editor/sidebar/MobileWorkspacePopover.js +0 -35
  247. package/dist/editor/sidebar/MobileWorkspacePopover.js.map +0 -1
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, Link2, Plus, RefreshCw, Settings2, Shield, X, } from "lucide-react";
2
+ import { ChevronLeft, CopyPlus, CornerDownRight, GitBranch, LayoutTemplate, 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";
6
6
  import { Button } from "../../../components/ui/button";
7
+ import { CloseButton } from "../../../components/ui/close-button";
7
8
  import { DeleteIcon } from "../../../components/ui/delete-icon";
8
9
  import { Dialog, DialogContent, DialogFooter, } from "../../../components/ui/dialog";
9
10
  import { Input } from "../../../components/ui/input";
@@ -21,7 +22,7 @@ const DependencyGraphView = lazy(() => import("../../../task-board/views/Depende
21
22
  })));
22
23
  import { useEditContext } from "../../client/editContext";
23
24
  import { useSearchParams } from "../../client/navigation";
24
- import { updateAgentContext } from "../../services/agentService";
25
+ import { updateAgentContext, } from "../../services/agentService";
25
26
  import { getAiProfilesErrorMessage, loadAiProfiles, } from "../../services/aiService";
26
27
  import { localStorageService } from "../../services/localStorageService";
27
28
  import { ItemNameDialog, } from "../../ui/ItemNameDialogNew";
@@ -93,6 +94,9 @@ function normalizeTaskTemplate(task) {
93
94
  const rawAssigneeId = task.assigneeId?.trim() || null;
94
95
  const rawAgentProfileId = task.agentProfileId?.trim() || null;
95
96
  const rawParentTaskId = task.parentTaskId?.trim() || null;
97
+ const dependencyIds = Array.from(new Set((task.dependencyIds ?? [])
98
+ .map((dependencyId) => dependencyId?.trim())
99
+ .filter((dependencyId) => !!dependencyId)));
96
100
  const disabled = task.disabled === true;
97
101
  const taskType = String(task.taskType ?? "").toLowerCase() === "decisionpoint"
98
102
  ? "DecisionPoint"
@@ -114,6 +118,7 @@ function normalizeTaskTemplate(task) {
114
118
  assigneeId: canonicalAgentId,
115
119
  agentProfileId: canonicalAgentId,
116
120
  parentTaskId: rawParentTaskId,
121
+ dependencyIds,
117
122
  };
118
123
  }
119
124
  if (assigneeType === "user" || assigneeType === "Role") {
@@ -126,6 +131,7 @@ function normalizeTaskTemplate(task) {
126
131
  assigneeId: rawAssigneeId,
127
132
  agentProfileId: null,
128
133
  parentTaskId: rawParentTaskId,
134
+ dependencyIds,
129
135
  };
130
136
  }
131
137
  return {
@@ -137,6 +143,7 @@ function normalizeTaskTemplate(task) {
137
143
  assigneeId: rawAssigneeId,
138
144
  agentProfileId: null,
139
145
  parentTaskId: rawParentTaskId,
146
+ dependencyIds,
140
147
  };
141
148
  }
142
149
  function normalizeGraphOrientation(orientation) {
@@ -146,7 +153,6 @@ function normalizeProjectTemplate(template) {
146
153
  return {
147
154
  ...template,
148
155
  hideFromCreateDialog: template.hideFromCreateDialog === true,
149
- openInWizardMode: template.openInWizardMode === true,
150
156
  graphLayout: template.graphLayout
151
157
  ? {
152
158
  ...template.graphLayout,
@@ -154,6 +160,10 @@ function normalizeProjectTemplate(template) {
154
160
  }
155
161
  : null,
156
162
  taskTemplates: (template.taskTemplates ?? []).map(normalizeTaskTemplate),
163
+ goalTemplates: (template.goalTemplates ?? []).map((goal) => ({
164
+ ...goal,
165
+ disabled: goal.disabled === true,
166
+ })),
157
167
  };
158
168
  }
159
169
  function createEmptyTemplate() {
@@ -163,11 +173,11 @@ function createEmptyTemplate() {
163
173
  description: "",
164
174
  disabled: false,
165
175
  hideFromCreateDialog: false,
166
- openInWizardMode: false,
167
176
  isSystem: false,
168
177
  defaultCostLimit: null,
169
178
  graphLayout: null,
170
179
  taskTemplates: [],
180
+ goalTemplates: [],
171
181
  };
172
182
  }
173
183
  function createEmptyTaskTemplate(taskCount, title) {
@@ -187,6 +197,17 @@ function createEmptyTaskTemplate(taskCount, title) {
187
197
  dependencyIds: [],
188
198
  };
189
199
  }
200
+ function createEmptyGoalDefinition(goalCount, title) {
201
+ return {
202
+ id: crypto.randomUUID(),
203
+ title: title?.trim() || `Goal ${goalCount + 1}`,
204
+ description: "",
205
+ disabled: false,
206
+ sortOrder: goalCount * 100,
207
+ defaultScopeJson: null,
208
+ dataShape: null,
209
+ };
210
+ }
190
211
  function sortTemplates(templates) {
191
212
  return [...templates].sort((left, right) => left.name.localeCompare(right.name, undefined, { sensitivity: "base" }));
192
213
  }
@@ -194,10 +215,9 @@ function buildUpsertTemplateRequest(template) {
194
215
  return {
195
216
  projectTemplateId: template.id,
196
217
  name: template.name.trim(),
197
- description: template.description?.trim() || null,
218
+ description: template.description || null,
198
219
  disabled: template.disabled === true,
199
220
  hideFromCreateDialog: template.hideFromCreateDialog === true,
200
- openInWizardMode: template.openInWizardMode === true,
201
221
  defaultCostLimit: template.defaultCostLimit == null ||
202
222
  Number.isNaN(template.defaultCostLimit)
203
223
  ? null
@@ -215,7 +235,7 @@ function buildUpsertTemplateRequest(template) {
215
235
  return {
216
236
  ...normalizedTask,
217
237
  title: normalizedTask.title.trim(),
218
- description: normalizedTask.description?.trim() || null,
238
+ description: normalizedTask.description || null,
219
239
  disabled: normalizedTask.disabled === true,
220
240
  taskType: normalizedTask.taskType ?? "Task",
221
241
  decisionMode: normalizedTask.taskType === "DecisionPoint"
@@ -230,10 +250,35 @@ function buildUpsertTemplateRequest(template) {
230
250
  dependencyIds: Array.from(new Set(normalizedTask.dependencyIds || [])),
231
251
  };
232
252
  }),
253
+ goalTemplates: (template.goalTemplates ?? []).map((goal, index) => ({
254
+ id: goal.id,
255
+ title: goal.title.trim(),
256
+ description: goal.description || null,
257
+ disabled: goal.disabled === true,
258
+ sortOrder: goal.sortOrder || index * 100,
259
+ defaultScopeJson: goal.defaultScopeJson?.trim() || null,
260
+ dataShape: goal.dataShape?.trim() || null,
261
+ })),
233
262
  };
234
263
  }
235
264
  function mergeTemplateResponseWithRequest(serverTemplate, request) {
236
265
  const requestedTaskById = new Map((request.taskTemplates ?? []).map((task) => [task.id, task]));
266
+ const requestedGoalById = new Map((request.goalTemplates ?? []).map((goal) => [goal.id, goal]));
267
+ // Server re-reads goals after BeginEdit/EndEdit; if a just-written goal is
268
+ // briefly missing from the response, keep it from the request so the next
269
+ // autosave does not delete it.
270
+ const serverGoals = serverTemplate.goalTemplates ?? [];
271
+ const serverGoalIds = new Set(serverGoals.map((goal) => goal.id));
272
+ const mergedGoalTemplates = [
273
+ ...serverGoals.map((goal) => {
274
+ const requested = requestedGoalById.get(goal.id);
275
+ return {
276
+ ...goal,
277
+ description: requested?.description ?? goal.description,
278
+ };
279
+ }),
280
+ ...(request.goalTemplates ?? []).filter((goal) => !serverGoalIds.has(goal.id)),
281
+ ];
237
282
  const mergedGraphLayout = request.graphLayout === undefined
238
283
  ? serverTemplate.graphLayout
239
284
  : request.graphLayout === null
@@ -246,7 +291,9 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
246
291
  };
247
292
  return normalizeProjectTemplate({
248
293
  ...serverTemplate,
294
+ description: request.description ?? serverTemplate.description,
249
295
  graphLayout: mergedGraphLayout,
296
+ goalTemplates: mergedGoalTemplates,
250
297
  taskTemplates: (serverTemplate.taskTemplates ?? []).map((task) => {
251
298
  const requested = requestedTaskById.get(task.id);
252
299
  // Sitecore item-cache reads after BeginEdit/EndEdit can briefly omit
@@ -257,6 +304,7 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
257
304
  const requestedDeps = requested?.dependencyIds ?? [];
258
305
  return {
259
306
  ...task,
307
+ description: requested?.description ?? task.description,
260
308
  parentTaskId: task.parentTaskId ?? requested?.parentTaskId ?? null,
261
309
  dependencyIds: serverDeps.length === 0 && requestedDeps.length > 0
262
310
  ? Array.from(new Set(requestedDeps))
@@ -265,6 +313,61 @@ function mergeTemplateResponseWithRequest(serverTemplate, request) {
265
313
  }),
266
314
  });
267
315
  }
316
+ function getActiveDescriptionDraftField(selectedTaskId, selectedGoalId) {
317
+ if (typeof document === "undefined") {
318
+ return null;
319
+ }
320
+ const activeElement = document.activeElement;
321
+ if (!(activeElement instanceof HTMLElement)) {
322
+ return null;
323
+ }
324
+ switch (activeElement.dataset.testid) {
325
+ case "project-template-description-input":
326
+ return { kind: "template" };
327
+ case "project-template-task-description-input":
328
+ return { kind: "task", id: selectedTaskId };
329
+ case "project-template-goal-description-input":
330
+ return { kind: "goal", id: selectedGoalId };
331
+ default:
332
+ return null;
333
+ }
334
+ }
335
+ function preserveActiveDescriptionDraft(template, draft, activeField) {
336
+ if (!draft || template.id !== draft.id || !activeField) {
337
+ return template;
338
+ }
339
+ if (activeField.kind === "template") {
340
+ return {
341
+ ...template,
342
+ description: draft.description,
343
+ };
344
+ }
345
+ if (activeField.kind === "task" && activeField.id) {
346
+ const draftTask = draft.taskTemplates.find((task) => task.id === activeField.id);
347
+ if (!draftTask) {
348
+ return template;
349
+ }
350
+ return {
351
+ ...template,
352
+ taskTemplates: template.taskTemplates.map((task) => task.id === activeField.id
353
+ ? { ...task, description: draftTask.description }
354
+ : task),
355
+ };
356
+ }
357
+ if (activeField.kind === "goal" && activeField.id) {
358
+ const draftGoal = (draft.goalTemplates ?? []).find((goal) => goal.id === activeField.id);
359
+ if (!draftGoal) {
360
+ return template;
361
+ }
362
+ return {
363
+ ...template,
364
+ goalTemplates: (template.goalTemplates ?? []).map((goal) => goal.id === activeField.id
365
+ ? { ...goal, description: draftGoal.description }
366
+ : goal),
367
+ };
368
+ }
369
+ return template;
370
+ }
268
371
  function isValidGuid(value) {
269
372
  return (!!value &&
270
373
  /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value));
@@ -361,12 +464,28 @@ function canAddTemplateDependency(template, taskId, dependencyId) {
361
464
  }
362
465
  return task.parentTaskId !== dependencyId;
363
466
  }
364
- function buildProjectTemplateAgentContext(template, selectedTaskTemplateId) {
467
+ function buildProjectTemplateAgentContext(template, selectedTaskTemplateId, selectedGoalTemplateId = null) {
365
468
  const dependencyCount = template.taskTemplates.reduce((count, task) => count + (task.dependencyIds?.length ?? 0), 0);
366
469
  const agentAssignedTaskCount = template.taskTemplates.filter((task) => task.agentProfileId || (task.assigneeType === "Agent" && task.assigneeId)).length;
367
470
  const selectedTask = selectedTaskTemplateId
368
471
  ? (template.taskTemplates.find((task) => task.id === selectedTaskTemplateId) ?? null)
369
472
  : null;
473
+ const goalDefinitions = [...(template.goalTemplates ?? [])]
474
+ .sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
475
+ .map((goal) => ({
476
+ id: goal.id,
477
+ title: goal.title?.trim() || "Untitled goal",
478
+ description: goal.description?.trim() || null,
479
+ disabled: goal.disabled === true,
480
+ sortOrder: goal.sortOrder ?? 0,
481
+ defaultScopeJson: goal.defaultScopeJson?.trim() || null,
482
+ dataShape: goal.dataShape?.trim() || null,
483
+ }));
484
+ const selectedGoal = selectedGoalTemplateId
485
+ ? (goalDefinitions.find((goal) => goal.id === selectedGoalTemplateId) ??
486
+ null)
487
+ : null;
488
+ const enabledGoalCount = goalDefinitions.filter((goal) => goal.disabled !== true).length;
370
489
  return {
371
490
  activeWorkspace: "settings",
372
491
  additionalData: {
@@ -382,10 +501,22 @@ function buildProjectTemplateAgentContext(template, selectedTaskTemplateId) {
382
501
  selectedTaskTemplate: selectedTask
383
502
  ? normalizeTaskTemplate(selectedTask)
384
503
  : null,
504
+ selectedGoalTemplateId: selectedGoal ? selectedGoal.id : null,
505
+ selectedGoalTemplateTitle: selectedGoal?.title ?? null,
506
+ selectedGoalTemplate: selectedGoal,
507
+ projectTemplateGoalDefinitions: goalDefinitions,
508
+ projectTemplateGoalSummary: {
509
+ goalCount: goalDefinitions.length,
510
+ enabledGoalCount,
511
+ disabledGoalCount: goalDefinitions.length - enabledGoalCount,
512
+ },
385
513
  projectTemplateSummary: {
386
514
  taskCount: template.taskTemplates.length,
387
515
  dependencyCount,
388
516
  agentAssignedTaskCount,
517
+ goalCount: goalDefinitions.length,
518
+ enabledGoalCount,
519
+ disabledGoalCount: goalDefinitions.length - enabledGoalCount,
389
520
  defaultCostLimit: template.defaultCostLimit ?? null,
390
521
  disabled: template.disabled === true,
391
522
  },
@@ -414,6 +545,10 @@ export function ProjectTemplatesPanel() {
414
545
  const [newTaskTitle, setNewTaskTitle] = useState("");
415
546
  const [newTaskDependencySourceId, setNewTaskDependencySourceId] = useState(null);
416
547
  const [creatingTask, setCreatingTask] = useState(false);
548
+ const [selectedGoalId, setSelectedGoalId] = useState(null);
549
+ const [isCreateGoalDialogOpen, setIsCreateGoalDialogOpen] = useState(false);
550
+ const [newGoalTitle, setNewGoalTitle] = useState("");
551
+ const [creatingGoal, setCreatingGoal] = useState(false);
417
552
  const [isAddChildTaskDialogOpen, setIsAddChildTaskDialogOpen] = useState(false);
418
553
  const [newChildTaskTitle, setNewChildTaskTitle] = useState("");
419
554
  const [creatingChildTask, setCreatingChildTask] = useState(false);
@@ -429,6 +564,12 @@ export function ProjectTemplatesPanel() {
429
564
  const [editingAgentProfile, setEditingAgentProfile] = useState(null);
430
565
  const [isTaskEditorMaximized, setIsTaskEditorMaximized] = useState(false);
431
566
  const [taskEditorOverlayBounds, setTaskEditorOverlayBounds] = useState(null);
567
+ const [settingsMainContentBounds, setSettingsMainContentBounds] = useState(null);
568
+ const [agentPanelBounds, setAgentPanelBounds] = useState(null);
569
+ const [isAgentPanelCollapsed, setIsAgentPanelCollapsed] = useState(() => {
570
+ const stored = localStorageService.getItem(PROJECT_TEMPLATE_SPLITTER_STORAGE_KEY);
571
+ return stored?.lastCollapsed ?? true;
572
+ });
432
573
  const [forceCollapseAgentPanelKey, setForceCollapseAgentPanelKey] = useState(0);
433
574
  const [forceExpandAgentPanelKey, setForceExpandAgentPanelKey] = useState(0);
434
575
  const settingsMainContentRef = useRequiredSettingsMainContentRef();
@@ -441,6 +582,7 @@ export function ProjectTemplatesPanel() {
441
582
  const draftTemplateRef = useRef(null);
442
583
  const selectedTemplateIdRef = useRef(selectedTemplateId);
443
584
  const selectedTaskIdRef = useRef(selectedTaskId);
585
+ const selectedGoalIdRef = useRef(selectedGoalId);
444
586
  const selectedDependencyIdRef = useRef(selectedDependencyId);
445
587
  const isDirtyRef = useRef(isDirty);
446
588
  const savingRef = useRef(saving);
@@ -455,6 +597,7 @@ export function ProjectTemplatesPanel() {
455
597
  };
456
598
  const restoreAgentPanelAfterMaximize = () => {
457
599
  if (agentPanelWasExpandedBeforeMaximizeRef.current === true) {
600
+ setIsAgentPanelCollapsed(false);
458
601
  setForceExpandAgentPanelKey((value) => value + 1);
459
602
  }
460
603
  agentPanelWasExpandedBeforeMaximizeRef.current = null;
@@ -477,11 +620,114 @@ export function ProjectTemplatesPanel() {
477
620
  const agentPanelCollapsed = wasAgentPanelCollapsed();
478
621
  agentPanelWasExpandedBeforeMaximizeRef.current = !agentPanelCollapsed;
479
622
  if (!agentPanelCollapsed) {
623
+ setIsAgentPanelCollapsed(true);
480
624
  setForceCollapseAgentPanelKey((value) => value + 1);
481
625
  }
482
626
  setTaskEditorOverlayBounds(nextBounds);
483
627
  setIsTaskEditorMaximized(true);
484
628
  };
629
+ useEffect(() => {
630
+ const settingsMainContent = settingsMainContentRef.current;
631
+ const updateBounds = () => {
632
+ const nextBounds = measureOverlayBounds(settingsMainContentRef.current);
633
+ if (nextBounds) {
634
+ setSettingsMainContentBounds(nextBounds);
635
+ }
636
+ };
637
+ updateBounds();
638
+ if (typeof window === "undefined") {
639
+ return;
640
+ }
641
+ let frameId = null;
642
+ const scheduleUpdate = () => {
643
+ if (frameId != null) {
644
+ window.cancelAnimationFrame(frameId);
645
+ }
646
+ frameId = window.requestAnimationFrame(() => {
647
+ frameId = null;
648
+ updateBounds();
649
+ });
650
+ };
651
+ const resizeObserver = typeof ResizeObserver !== "undefined" && settingsMainContent
652
+ ? new ResizeObserver(scheduleUpdate)
653
+ : null;
654
+ if (resizeObserver && settingsMainContent) {
655
+ resizeObserver.observe(settingsMainContent);
656
+ }
657
+ window.addEventListener("resize", scheduleUpdate);
658
+ window.addEventListener("scroll", scheduleUpdate, true);
659
+ return () => {
660
+ if (frameId != null) {
661
+ window.cancelAnimationFrame(frameId);
662
+ }
663
+ resizeObserver?.disconnect();
664
+ window.removeEventListener("resize", scheduleUpdate);
665
+ window.removeEventListener("scroll", scheduleUpdate, true);
666
+ };
667
+ }, [settingsMainContentRef]);
668
+ useEffect(() => {
669
+ if (isMobile) {
670
+ setAgentPanelBounds(null);
671
+ return;
672
+ }
673
+ const updateBounds = () => {
674
+ const element = document.querySelector('[data-testid="splitter-panel-project-template-agent"]');
675
+ const nextBounds = measureOverlayBounds(element);
676
+ setAgentPanelBounds((currentBounds) => {
677
+ if (!nextBounds) {
678
+ return currentBounds === null ? currentBounds : null;
679
+ }
680
+ if (currentBounds &&
681
+ Math.abs(currentBounds.top - nextBounds.top) < 0.5 &&
682
+ Math.abs(currentBounds.left - nextBounds.left) < 0.5 &&
683
+ Math.abs(currentBounds.width - nextBounds.width) < 0.5 &&
684
+ Math.abs(currentBounds.height - nextBounds.height) < 0.5) {
685
+ return currentBounds;
686
+ }
687
+ return nextBounds;
688
+ });
689
+ };
690
+ updateBounds();
691
+ if (typeof window === "undefined") {
692
+ return;
693
+ }
694
+ let frameId = null;
695
+ const scheduleUpdate = () => {
696
+ if (frameId != null) {
697
+ window.cancelAnimationFrame(frameId);
698
+ }
699
+ frameId = window.requestAnimationFrame(() => {
700
+ frameId = null;
701
+ updateBounds();
702
+ });
703
+ };
704
+ const settingsMainContent = settingsMainContentRef.current;
705
+ const agentPanelElement = document.querySelector('[data-testid="splitter-panel-project-template-agent"]');
706
+ const resizeObserver = typeof ResizeObserver !== "undefined" && settingsMainContent
707
+ ? new ResizeObserver(scheduleUpdate)
708
+ : null;
709
+ if (resizeObserver && settingsMainContent) {
710
+ resizeObserver.observe(settingsMainContent);
711
+ }
712
+ if (resizeObserver && agentPanelElement) {
713
+ resizeObserver.observe(agentPanelElement);
714
+ }
715
+ window.addEventListener("resize", scheduleUpdate);
716
+ window.addEventListener("scroll", scheduleUpdate, true);
717
+ return () => {
718
+ if (frameId != null) {
719
+ window.cancelAnimationFrame(frameId);
720
+ }
721
+ resizeObserver?.disconnect();
722
+ window.removeEventListener("resize", scheduleUpdate);
723
+ window.removeEventListener("scroll", scheduleUpdate, true);
724
+ };
725
+ }, [
726
+ isAgentPanelCollapsed,
727
+ isMobile,
728
+ selectedTemplateId,
729
+ settingsMainContentRef,
730
+ ]);
485
731
  useEffect(() => {
486
732
  if (!isTaskEditorMaximized) {
487
733
  setTaskEditorOverlayBounds(null);
@@ -622,8 +868,14 @@ export function ProjectTemplatesPanel() {
622
868
  setMobileView("detail");
623
869
  return;
624
870
  }
871
+ setIsAgentPanelCollapsed(true);
625
872
  setForceCollapseAgentPanelKey((value) => value + 1);
626
873
  }, [isMobile]);
874
+ const handleShowTemplateAssistant = useCallback(() => {
875
+ setEditingAgentProfile(null);
876
+ setIsAgentPanelCollapsed(false);
877
+ setForceExpandAgentPanelKey((value) => value + 1);
878
+ }, []);
627
879
  useEffect(() => {
628
880
  if (!isMobile) {
629
881
  setMobileView("detail");
@@ -642,7 +894,8 @@ export function ProjectTemplatesPanel() {
642
894
  if (result.type !== "success") {
643
895
  throw new Error(result.summary || "Failed to load project templates");
644
896
  }
645
- const loadedTemplates = result.data ?? [];
897
+ const activeDescriptionDraftField = getActiveDescriptionDraftField(selectedTaskIdRef.current, selectedGoalIdRef.current);
898
+ const loadedTemplates = (result.data ?? []).map((template) => preserveActiveDescriptionDraft(template, draftTemplateRef.current, activeDescriptionDraftField));
646
899
  setTemplates(loadedTemplates);
647
900
  setState("success");
648
901
  const preferredTemplateExists = !!preferredTemplateId &&
@@ -712,6 +965,9 @@ export function ProjectTemplatesPanel() {
712
965
  }, [aiProfiles]);
713
966
  const selectedTask = useMemo(() => draftTemplate?.taskTemplates.find((task) => task.id === selectedTaskId) ??
714
967
  null, [draftTemplate, selectedTaskId]);
968
+ const templateAgentInitialMetadata = useMemo(() => draftTemplate
969
+ ? buildProjectTemplateAgentContext(draftTemplate, selectedTaskId, selectedGoalId)
970
+ : undefined, [draftTemplate, selectedGoalId, selectedTaskId]);
715
971
  const dependencyTasks = useMemo(() => {
716
972
  if (!draftTemplate || !selectedTask)
717
973
  return [];
@@ -781,9 +1037,9 @@ export function ProjectTemplatesPanel() {
781
1037
  setMobileView("detail");
782
1038
  }
783
1039
  }, [isMobile]);
784
- const syncProjectTemplateAgentContext = useCallback(async (agentId, template, selectedTaskTemplateId) => {
1040
+ const syncProjectTemplateAgentContext = useCallback(async (agentId, template, selectedTaskTemplateId, selectedGoalTemplateId) => {
785
1041
  try {
786
- await updateAgentContext(agentId, buildProjectTemplateAgentContext(template, selectedTaskTemplateId));
1042
+ await updateAgentContext(agentId, buildProjectTemplateAgentContext(template, selectedTaskTemplateId, selectedGoalTemplateId));
787
1043
  }
788
1044
  catch (error) {
789
1045
  setTemplateAgentError(error instanceof Error
@@ -836,8 +1092,9 @@ export function ProjectTemplatesPanel() {
836
1092
  const currentTemplate = draftTemplateRef.current;
837
1093
  if (!currentTemplate || currentTemplate.id !== selectedTemplateId)
838
1094
  return;
839
- void syncProjectTemplateAgentContext(templateAgentId, currentTemplate, selectedTaskId);
1095
+ void syncProjectTemplateAgentContext(templateAgentId, currentTemplate, selectedTaskId, selectedGoalId);
840
1096
  }, [
1097
+ selectedGoalId,
841
1098
  selectedTaskId,
842
1099
  templateAgentId,
843
1100
  templateAgentLoading,
@@ -868,6 +1125,14 @@ export function ProjectTemplatesPanel() {
868
1125
  taskTemplates: currentTemplate.taskTemplates.map((task) => task.id === selectedTaskId ? updater({ ...task }) : task),
869
1126
  }));
870
1127
  }, [applyDraftChange, selectedTaskId]);
1128
+ const updateSelectedGoal = useCallback((updater) => {
1129
+ if (!selectedGoalId)
1130
+ return;
1131
+ applyDraftChange((currentTemplate) => ({
1132
+ ...currentTemplate,
1133
+ goalTemplates: (currentTemplate.goalTemplates ?? []).map((goal) => goal.id === selectedGoalId ? updater({ ...goal }) : goal),
1134
+ }));
1135
+ }, [applyDraftChange, selectedGoalId]);
871
1136
  const handleDuplicateAssignedAgentProfile = useCallback(async () => {
872
1137
  if (!editContext || !selectedAgentProfileId)
873
1138
  return;
@@ -999,7 +1264,10 @@ export function ProjectTemplatesPanel() {
999
1264
  }
1000
1265
  if (templateAgentId && savedTemplate.id === selectedTemplateId) {
1001
1266
  const nextSelectedTaskId = getSelectedTaskIdForTemplate(savedTemplate, selectedTaskIdRef.current);
1002
- void syncProjectTemplateAgentContext(templateAgentId, savedTemplate, nextSelectedTaskId);
1267
+ const nextSelectedGoalId = savedTemplate.goalTemplates?.some((goal) => goal.id === selectedGoalId) === true
1268
+ ? selectedGoalId
1269
+ : null;
1270
+ void syncProjectTemplateAgentContext(templateAgentId, savedTemplate, nextSelectedTaskId, nextSelectedGoalId);
1003
1271
  }
1004
1272
  return true;
1005
1273
  }
@@ -1008,7 +1276,12 @@ export function ProjectTemplatesPanel() {
1008
1276
  setSaving(false);
1009
1277
  }
1010
1278
  }
1011
- }, [selectedTemplateId, syncProjectTemplateAgentContext, templateAgentId]);
1279
+ }, [
1280
+ selectedGoalId,
1281
+ selectedTemplateId,
1282
+ syncProjectTemplateAgentContext,
1283
+ templateAgentId,
1284
+ ]);
1012
1285
  const applyDraftChangeAndPersist = useCallback((updater) => {
1013
1286
  let nextTemplate = null;
1014
1287
  let nextSignature = null;
@@ -1133,6 +1406,9 @@ export function ProjectTemplatesPanel() {
1133
1406
  useEffect(() => {
1134
1407
  selectedTaskIdRef.current = selectedTaskId;
1135
1408
  }, [selectedTaskId]);
1409
+ useEffect(() => {
1410
+ selectedGoalIdRef.current = selectedGoalId;
1411
+ }, [selectedGoalId]);
1136
1412
  useEffect(() => {
1137
1413
  selectedDependencyIdRef.current = selectedDependencyId;
1138
1414
  }, [selectedDependencyId]);
@@ -1243,6 +1519,7 @@ export function ProjectTemplatesPanel() {
1243
1519
  setSelectedTemplateId(nextTemplate.id);
1244
1520
  setDraftTemplate(cloneTemplate(nextTemplate));
1245
1521
  setSelectedTaskId(null);
1522
+ setSelectedGoalId(null);
1246
1523
  setIsDirty(true);
1247
1524
  setSaveError(null);
1248
1525
  lastPersistedSignatureRef.current = null;
@@ -1348,7 +1625,7 @@ export function ProjectTemplatesPanel() {
1348
1625
  setTemplateAgentId(result.data.agentId);
1349
1626
  const currentTemplate = draftTemplateRef.current;
1350
1627
  if (currentTemplate?.id === selectedTemplateId) {
1351
- await syncProjectTemplateAgentContext(result.data.agentId, currentTemplate, selectedTaskIdRef.current);
1628
+ await syncProjectTemplateAgentContext(result.data.agentId, currentTemplate, selectedTaskIdRef.current, selectedGoalId);
1352
1629
  }
1353
1630
  }
1354
1631
  catch (error) {
@@ -1361,7 +1638,12 @@ export function ProjectTemplatesPanel() {
1361
1638
  finally {
1362
1639
  setTemplateAgentResetting(false);
1363
1640
  }
1364
- }, [flushPendingSave, selectedTemplateId, syncProjectTemplateAgentContext]);
1641
+ }, [
1642
+ flushPendingSave,
1643
+ selectedGoalId,
1644
+ selectedTemplateId,
1645
+ syncProjectTemplateAgentContext,
1646
+ ]);
1365
1647
  const handleOpenCreateTaskDialog = useCallback(async () => {
1366
1648
  if (!draftTemplate)
1367
1649
  return;
@@ -1449,6 +1731,56 @@ export function ProjectTemplatesPanel() {
1449
1731
  setCreatingTask(false);
1450
1732
  }
1451
1733
  }, [draftTemplate, newTaskDependencySourceId, newTaskTitle, persistTemplate]);
1734
+ const handleConfirmCreateGoal = useCallback(async () => {
1735
+ if (!draftTemplate)
1736
+ return;
1737
+ const trimmedTitle = newGoalTitle.trim();
1738
+ if (!trimmedTitle) {
1739
+ toast.error("Goal title is required");
1740
+ return;
1741
+ }
1742
+ if (!draftTemplate.name.trim()) {
1743
+ const message = "Project template name is required before it can be saved";
1744
+ setSaveError(message);
1745
+ toast.error(message);
1746
+ return;
1747
+ }
1748
+ if (autosaveTimeoutRef.current !== null) {
1749
+ window.clearTimeout(autosaveTimeoutRef.current);
1750
+ autosaveTimeoutRef.current = null;
1751
+ }
1752
+ const nextGoal = createEmptyGoalDefinition((draftTemplate.goalTemplates ?? []).length, trimmedTitle);
1753
+ const nextTemplate = cloneTemplate(draftTemplate);
1754
+ nextTemplate.goalTemplates = [
1755
+ ...(nextTemplate.goalTemplates ?? []),
1756
+ nextGoal,
1757
+ ];
1758
+ const request = buildUpsertTemplateRequest(nextTemplate);
1759
+ const signature = JSON.stringify(request);
1760
+ latestDraftSignatureRef.current = signature;
1761
+ setDraftTemplate(cloneTemplate(nextTemplate));
1762
+ setTemplates((existingTemplates) => sortTemplates([
1763
+ ...existingTemplates.filter((template) => template.id !== nextTemplate.id),
1764
+ cloneTemplate(nextTemplate),
1765
+ ]));
1766
+ setSelectedGoalId(nextGoal.id);
1767
+ setIsDirty(true);
1768
+ setSaveError(null);
1769
+ setCreatingGoal(true);
1770
+ try {
1771
+ const saved = await persistTemplate(request, signature, {
1772
+ showErrorToast: true,
1773
+ });
1774
+ if (saved) {
1775
+ setIsCreateGoalDialogOpen(false);
1776
+ setNewGoalTitle("");
1777
+ toast.success("Goal definition created");
1778
+ }
1779
+ }
1780
+ finally {
1781
+ setCreatingGoal(false);
1782
+ }
1783
+ }, [draftTemplate, newGoalTitle, persistTemplate]);
1452
1784
  const handleOpenAddChildTaskDialog = useCallback(async () => {
1453
1785
  if (!draftTemplate || !selectedTaskId)
1454
1786
  return;
@@ -1485,7 +1817,7 @@ export function ProjectTemplatesPanel() {
1485
1817
  ...existingTemplates.filter((template) => template.id !== nextTemplate.id),
1486
1818
  cloneTemplate(nextTemplate),
1487
1819
  ]));
1488
- // Keep the parent task selected so the new child appears in "Child tasks" immediately.
1820
+ // Keep the parent task selected so the new subtask appears immediately.
1489
1821
  setIsDirty(true);
1490
1822
  setSaveError(null);
1491
1823
  setCreatingChildTask(true);
@@ -1496,7 +1828,7 @@ export function ProjectTemplatesPanel() {
1496
1828
  if (saved) {
1497
1829
  setIsAddChildTaskDialogOpen(false);
1498
1830
  setNewChildTaskTitle("");
1499
- toast.success("Child task template created");
1831
+ toast.success("Subtask template created");
1500
1832
  }
1501
1833
  }
1502
1834
  finally {
@@ -1531,6 +1863,12 @@ export function ProjectTemplatesPanel() {
1531
1863
  setSelectedDependencyId(null);
1532
1864
  setSelectedTaskId(taskId);
1533
1865
  }, []);
1866
+ const handleCloseTaskDetailsPane = useCallback(() => {
1867
+ selectedTaskIdRef.current = null;
1868
+ selectedDependencyIdRef.current = null;
1869
+ setSelectedTaskId(null);
1870
+ setSelectedDependencyId(null);
1871
+ }, []);
1534
1872
  const handleSelectDependencyFromGraph = useCallback((taskId, dependencyId) => {
1535
1873
  selectedDependencyIdRef.current = dependencyId;
1536
1874
  setSelectedTaskId(taskId);
@@ -1661,6 +1999,43 @@ export function ProjectTemplatesPanel() {
1661
1999
  }
1662
2000
  runDelete();
1663
2001
  }, [applyDraftChange, editContext]);
2002
+ const removeGoalDefinitionById = useCallback((goalId) => {
2003
+ const template = draftTemplateRef.current;
2004
+ const goals = template?.goalTemplates ?? [];
2005
+ if (!goals.some((goal) => goal.id === goalId))
2006
+ return;
2007
+ const goalTitle = goals.find((goal) => goal.id === goalId)?.title ?? "Untitled goal";
2008
+ const runDelete = () => {
2009
+ const current = draftTemplateRef.current;
2010
+ const currentGoals = current?.goalTemplates ?? [];
2011
+ if (!currentGoals.some((goal) => goal.id === goalId))
2012
+ return;
2013
+ const remainingGoals = currentGoals.filter((goal) => goal.id !== goalId);
2014
+ applyDraftChange((currentTemplate) => ({
2015
+ ...currentTemplate,
2016
+ goalTemplates: (currentTemplate.goalTemplates ?? []).filter((goal) => goal.id !== goalId),
2017
+ }));
2018
+ setSelectedGoalId((prev) => {
2019
+ if (prev === goalId) {
2020
+ return remainingGoals[0]?.id ?? null;
2021
+ }
2022
+ return remainingGoals.some((goal) => goal.id === prev)
2023
+ ? prev
2024
+ : (remainingGoals[0]?.id ?? null);
2025
+ });
2026
+ };
2027
+ if (editContext?.confirm) {
2028
+ editContext.confirm({
2029
+ header: "Remove goal definition",
2030
+ message: `Are you sure you want to remove "${goalTitle}"?`,
2031
+ acceptLabel: "Remove",
2032
+ showCancel: true,
2033
+ accept: runDelete,
2034
+ });
2035
+ return;
2036
+ }
2037
+ runDelete();
2038
+ }, [applyDraftChange, editContext]);
1664
2039
  const handleDeleteSelectedTask = useCallback(() => {
1665
2040
  if (!selectedTaskId)
1666
2041
  return;
@@ -1712,30 +2087,41 @@ export function ProjectTemplatesPanel() {
1712
2087
  const breadcrumbTaskCount = draftTemplate?.taskTemplates.length ?? 0;
1713
2088
  const breadcrumbItems = useMemo(() => breadcrumbDraftName
1714
2089
  ? [
1715
- {
1716
- title: "Workflow Project Templates",
1717
- subtitle: "Create project templates",
1718
- onClick: () => {
1719
- void handleNavigateToOverview();
1720
- },
1721
- },
1722
2090
  {
1723
2091
  title: breadcrumbDraftName,
1724
2092
  subtitle: `${breadcrumbTaskCount} task templates`,
2093
+ backLink: {
2094
+ label: "Back to project templates overview",
2095
+ onClick: () => {
2096
+ void handleNavigateToOverview();
2097
+ },
2098
+ },
1725
2099
  },
1726
2100
  ]
1727
2101
  : null, [breadcrumbDraftName, breadcrumbTaskCount, handleNavigateToOverview]);
1728
2102
  const desktopHeaderActions = useMemo(() => {
1729
2103
  if (isMobile)
1730
2104
  return null;
2105
+ const showCreate = !draftTemplate;
1731
2106
  const showDelete = draftTemplate && !draftTemplate.isSystem;
1732
- 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 template"] }), showDelete ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(DeleteIcon, { size: "lg" }), deleting ? "Deleting..." : "Delete"] })) : null] }));
2107
+ const agentPanelHeaderOffset = draftTemplate &&
2108
+ !isTaskEditorMaximized &&
2109
+ !isAgentPanelCollapsed &&
2110
+ agentPanelBounds
2111
+ ? Math.round(agentPanelBounds.width + 8)
2112
+ : 0;
2113
+ return (_jsxs("div", { className: "mt-2 flex items-center gap-2", style: agentPanelHeaderOffset > 0
2114
+ ? { marginRight: agentPanelHeaderOffset }
2115
+ : undefined, children: [headerStatusBadge, showCreate ? (_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 template"] })) : null, showDelete ? (_jsxs(Button, { variant: "outline", size: "sm", onClick: () => handleDeleteTemplate(), disabled: deleting, "data-testid": "project-template-delete-button", children: [_jsx(DeleteIcon, { size: "lg" }), deleting ? "Deleting..." : "Delete"] })) : null] }));
1733
2116
  }, [
2117
+ agentPanelBounds,
1734
2118
  deleting,
1735
2119
  draftTemplate,
1736
2120
  handleCreateTemplate,
1737
2121
  handleDeleteTemplate,
1738
2122
  headerStatusBadge,
2123
+ isAgentPanelCollapsed,
2124
+ isTaskEditorMaximized,
1739
2125
  isMobile,
1740
2126
  ]);
1741
2127
  useEffect(() => {
@@ -1773,7 +2159,7 @@ export function ProjectTemplatesPanel() {
1773
2159
  }));
1774
2160
  return nextLayout;
1775
2161
  } }) }) }));
1776
- 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: "border-border-default bg-neutral-grey-5 text-neutral-grey-50 rounded-lg border border-dashed p-6 text-center text-xs", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-border-default shrink-0 border-b 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-neutral-grey-100 text-xs font-medium", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), selectedTask.taskType === "DecisionPoint" ? (_jsx(Badge, { variant: "outline", className: "border-highlight-100 bg-highlight-10 text-2xs text-highlight-100", children: "Decision Point" })) : null, selectedTask.disabled ? (_jsx(Badge, { variant: "outline", className: "text-2xs", children: "Disabled" })) : null] }), _jsx("div", { className: "text-neutral-grey-50 text-xs", children: "Configure task details, assignment, and dependencies." })] }), _jsxs(Button, { variant: "outline", size: "sm", onClick: handleDeleteSelectedTask, "data-testid": "project-template-remove-task-button", children: [_jsx(DeleteIcon, { size: "lg" }), "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) => ({
2162
+ 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: "border-border-default bg-neutral-grey-5 text-neutral-grey-50 rounded-lg border border-dashed p-6 text-center text-xs", children: "Select a task node to edit its details." }) })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "border-border-default shrink-0 border-b bg-white px-4 pt-4 pb-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", "data-testid": "project-template-selected-task-title", children: selectedTask.title || "Untitled Task" }), selectedTask.taskType === "DecisionPoint" ? (_jsx(Badge, { variant: "outline", className: "border-highlight-100 bg-highlight-10 text-2xs text-highlight-100", children: "Decision Point" })) : null, selectedTask.disabled ? (_jsx(Badge, { variant: "outline", className: "text-2xs", children: "Disabled" })) : null] }), _jsx("div", { className: "text-neutral-grey-50 text-xs", children: "Configure task details, assignment, and dependencies." })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [_jsxs(Button, { variant: "outline", size: "sm", onClick: handleDeleteSelectedTask, "data-testid": "project-template-remove-task-button", children: [_jsx(DeleteIcon, { size: "lg" }), "Remove Task"] }), _jsx(CloseButton, { onClick: handleCloseTaskDetailsPane, label: "Close task details", "data-testid": "project-template-close-task-details-button" })] })] }) }), _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) => ({
1777
2163
  ...currentTask,
1778
2164
  title: event.target.value,
1779
2165
  })), 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) => ({
@@ -1802,7 +2188,7 @@ export function ProjectTemplatesPanel() {
1802
2188
  agentProfileId: next?.assigneeType === "Agent"
1803
2189
  ? next.assigneeId
1804
2190
  : null,
1805
- })), placeholder: "Assign user or agent", buttonClassName: "h-[27px] 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-[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-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.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-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.5 }), _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
2191
+ })), 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.5 }), "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.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-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.5 }), _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
1806
2192
  ? "Add more task templates to create dependencies."
1807
2193
  : "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
1808
2194
  ? "border-feedback-orange bg-feedback-orange-light ring-feedback-orange ring-1"
@@ -1818,23 +2204,28 @@ export function ProjectTemplatesPanel() {
1818
2204
  event.preventDefault();
1819
2205
  event.stopPropagation();
1820
2206
  handleRemoveDependency(task.id);
1821
- }, "data-testid": `project-template-dependency-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Remove dependency on ${task.title}`, onClick: () => handleRemoveDependency(task.id), "data-testid": `project-template-remove-dependency-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] }), _jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border p-3", "data-testid": "project-template-child-tasks-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(CornerDownRight, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1.5 }), "Child tasks"] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: () => void handleOpenAddChildTaskDialog(), disabled: creatingChildTask, "aria-label": "Add child task", "data-testid": "project-template-add-child-task-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "Tasks that run after this one (they depend on this task)." }), childTaskTemplates.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "No child tasks yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: childTaskTemplates.map((task) => (_jsxs("li", { className: "border-border-default flex items-center justify-between gap-2 rounded-md border bg-white px-3 py-2 text-xs", "data-testid": `project-template-child-task-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Unlink child task ${task.title}`, onClick: () => handleUnlinkChildTask(task.id), "data-testid": `project-template-unlink-child-task-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] })] })] }) })] })) }));
2207
+ }, "data-testid": `project-template-dependency-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Remove dependency on ${task.title}`, onClick: () => handleRemoveDependency(task.id), "data-testid": `project-template-remove-dependency-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] }), _jsxs("div", { className: "border-border-default bg-neutral-grey-5 rounded-lg border p-3", "data-testid": "project-template-child-tasks-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(CornerDownRight, { className: "text-neutral-grey-50 h-4 w-4", strokeWidth: 1.5 }), "Subtasks"] }), _jsx(Button, { type: "button", size: "sm", variant: "outline", className: "h-7 gap-1 px-2", onClick: () => void handleOpenAddChildTaskDialog(), disabled: creatingChildTask, "aria-label": "Add subtask", "data-testid": "project-template-add-child-task-button", children: _jsx(Plus, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }), _jsx("p", { className: "text-neutral-grey-50 mb-2 text-[11px] leading-snug", children: "Subtasks must be completed before this task is done." }), childTaskTemplates.length === 0 ? (_jsx("div", { className: "text-neutral-grey-50 text-xs", children: "No subtasks yet. Use + to add one." })) : (_jsx("ul", { className: "space-y-1.5", children: childTaskTemplates.map((task) => (_jsxs("li", { className: "border-border-default flex items-center justify-between gap-2 rounded-md border bg-white px-3 py-2 text-xs", "data-testid": `project-template-child-task-row-${task.id}`, children: [_jsx("span", { className: "text-neutral-grey-100 min-w-0 truncate font-medium", children: task.title || "Untitled Task" }), _jsx("button", { type: "button", className: "text-neutral-grey-50 hover:bg-neutral-grey-5 hover:text-neutral-grey-100 shrink-0 rounded p-0.5", "aria-label": `Unlink subtask ${task.title}`, onClick: () => handleUnlinkChildTask(task.id), "data-testid": `project-template-unlink-child-task-${task.id}`, children: _jsx(X, { className: "h-4 w-4", strokeWidth: 1.5 }) })] }, task.id))) }))] })] })] }) })] })) }));
1822
2208
  if (isMobile) {
1823
2209
  return (_jsxs("div", { className: "border-border-default flex shrink-0 flex-col border-b", children: [_jsx("div", { className: "border-border-default h-[300px] shrink-0 overflow-hidden border-b", children: graphView }), taskPane] }));
1824
2210
  }
1825
- return (_jsx("div", { className: "border-border-default min-h-[360px] flex-1 overflow-hidden border-b", children: _jsx(Splitter, { direction: "vertical", localStorageKey: "settings-project-template-graph-task-splitter-v1", className: "h-full", panels: [
2211
+ return (_jsx("div", { className: "border-border-default min-h-[360px] flex-1 overflow-hidden border-b", children: _jsx(Splitter, { direction: "horizontal", localStorageKey: "settings-project-template-graph-task-splitter-v2", className: "h-full", panels: [
1826
2212
  {
1827
2213
  name: "project-template-graph",
1828
- defaultSize: 400,
1829
- className: "min-h-0",
1830
- content: graphView,
1831
- },
1832
- {
1833
- name: "project-template-task-details",
1834
2214
  defaultSize: "auto",
1835
2215
  className: "min-h-0",
1836
- content: taskPane,
2216
+ content: graphView,
1837
2217
  },
2218
+ ...(selectedTask
2219
+ ? [
2220
+ {
2221
+ name: "project-template-task-details",
2222
+ defaultSize: 560,
2223
+ minSize: 360,
2224
+ className: "min-h-0",
2225
+ content: taskPane,
2226
+ },
2227
+ ]
2228
+ : []),
1838
2229
  ] }) }));
1839
2230
  };
1840
2231
  const detailContent = (_jsxs("div", { className: "bg-neutral-grey-5/40 flex h-full flex-col", "data-testid": "project-template-detail-pane", children: [isMobile && draftTemplate && !draftTemplate.isSystem ? (_jsxs("div", { className: "border-border-default flex min-w-0 items-center gap-3 border-b bg-white px-5 py-2", "data-testid": "project-template-detail-pane-header", children: [_jsx("div", { className: "min-w-0 flex-1", children: templateSelector }), _jsx("div", { className: "flex shrink-0 items-center gap-1.5 self-center", children: _jsx(Button, { variant: "outline", size: "icon", className: "h-9 w-9 shrink-0", onClick: () => handleDeleteTemplate(), disabled: deleting, "aria-label": deleting ? "Deleting template" : "Delete template", title: deleting ? "Deleting…" : "Delete template", "data-testid": "project-template-delete-button", children: deleting ? (_jsx(RefreshCw, { className: "h-4 w-4 animate-spin", strokeWidth: 1.5 })) : (_jsx(DeleteIcon, { size: "lg" })) }) })] })) : null, draftTemplate ? ((() => {
@@ -1851,6 +2242,12 @@ export function ProjectTemplatesPanel() {
1851
2242
  content: null,
1852
2243
  testId: "project-template-tab-task-editor",
1853
2244
  },
2245
+ {
2246
+ id: "project-template-tab-goals",
2247
+ label: "Goals",
2248
+ content: null,
2249
+ testId: "project-template-tab-goals",
2250
+ },
1854
2251
  ];
1855
2252
  const basicSettingsContent = (_jsxs("div", { className: "grid gap-4 overflow-y-auto p-4 md:grid-cols-2", "data-testid": "project-template-basic-settings-panel", children: [_jsxs("div", { className: "grid gap-1.5 md:col-span-2", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-name-input", children: "Template name" }), _jsx(Input, { id: "project-template-name-input", value: draftTemplate.name, onChange: (event) => applyDraftChange((currentTemplate) => ({
1856
2253
  ...currentTemplate,
@@ -1869,20 +2266,81 @@ export function ProjectTemplatesPanel() {
1869
2266
  })), className: "data-[state=checked]:bg-feedback-orange data-[state=checked]:shadow-inner", "aria-label": "Disable this project template", "data-testid": "project-template-disabled-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", children: "Hide from create dialog" }), _jsx("div", { className: "text-neutral-grey-50 mt-0.5 text-xs", children: "Keeps the template active, but removes it from the create project dialog." })] }), _jsx(Switch, { checked: draftTemplate.hideFromCreateDialog === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
1870
2267
  ...currentTemplate,
1871
2268
  hideFromCreateDialog: checked,
1872
- })), "aria-label": "Hide this project template from the create dialog", "data-testid": "project-template-hide-from-create-dialog-switch" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4 md:col-span-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", children: "Open in wizard mode" }), _jsx("div", { className: "text-neutral-grey-50 mt-0.5 text-xs", children: "New projects created from this template start in taskboard wizard mode." })] }), _jsx(Switch, { checked: draftTemplate.openInWizardMode === true, onCheckedChange: (checked) => applyDraftChange((currentTemplate) => ({
1873
- ...currentTemplate,
1874
- openInWizardMode: checked,
1875
- })), "aria-label": "Open new projects from this template in wizard mode", "data-testid": "project-template-open-in-wizard-mode-switch" })] })] }));
2269
+ })), "aria-label": "Hide this project template from the create dialog", "data-testid": "project-template-hide-from-create-dialog-switch" })] })] }));
1876
2270
  const taskEditorContent = (_jsx("div", { className: "flex h-full min-h-0 flex-1 flex-col overflow-hidden", children: renderTemplateTaskEditorMain() }));
1877
- return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain md:overflow-hidden", isTaskEditorMaximized ? "overflow-hidden p-0" : "p-5"), 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: "border-feedback-red bg-feedback-red-light text-feedback-red rounded border px-4 py-3 text-xs", children: saveError })) }), _jsxs("section", { className: cn("border-border-default flex min-h-0 flex-1 flex-col rounded-lg border bg-white md:overflow-hidden", isTaskEditorMaximized &&
1878
- "overflow-hidden rounded-none shadow-xl"), "data-testid": "project-template-task-editor-shell", children: [_jsxs("div", { className: "border-border-default flex shrink-0 items-center justify-between gap-3 border-b 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, 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"
1879
- ? ""
1880
- : "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"
2271
+ const goalDefinitions = draftTemplate.goalTemplates ?? [];
2272
+ const selectedGoal = goalDefinitions.find((goal) => goal.id === selectedGoalId) ?? null;
2273
+ const goalsContent = (_jsx("div", { className: "flex h-full min-h-0 flex-1 flex-col gap-3 overflow-y-auto p-4", "data-testid": "project-template-goals-section", children: goalDefinitions.length === 0 ? (_jsx("div", { className: "border-border-default text-neutral-grey-50 rounded-md border border-dashed p-6 text-center text-xs", children: "No goal definitions yet. Use \u201CAdd Goal\u201D to create one \u2014 projects created from this template can pick from these goals." })) : (_jsxs("div", { className: "grid gap-3 md:grid-cols-[220px_1fr]", children: [_jsx("div", { className: "flex flex-col gap-1", children: [...goalDefinitions]
2274
+ .sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
2275
+ .map((goal) => (_jsxs("div", { "data-testid": `project-template-goal-row-${goal.id}`, className: cn("flex items-center justify-between gap-2 rounded-md px-3 py-2 text-xs", goal.id === selectedGoalId
2276
+ ? "bg-neutral-grey-5"
2277
+ : "hover:bg-neutral-grey-5 bg-transparent"), children: [_jsxs("button", { type: "button", className: "min-w-0 flex-1 truncate text-left", onClick: () => setSelectedGoalId(goal.id), children: [goal.title || "Untitled goal", goal.disabled ? " (disabled)" : ""] }), _jsx("button", { type: "button", "aria-label": `Remove ${goal.title || "goal"}`, "data-testid": `project-template-remove-goal-${goal.id}`, className: "text-neutral-grey-50 hover:text-feedback-red shrink-0", onClick: () => removeGoalDefinitionById(goal.id), children: _jsx(Trash2, { className: "h-3.5 w-3.5", strokeWidth: 1.5 }) })] }, goal.id))) }), selectedGoal ? (_jsxs("div", { className: "border-border-default flex flex-col gap-3 rounded-md border bg-white p-4", children: [_jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-title-input", children: "Title" }), _jsx(Input, { id: "project-template-goal-title-input", "data-testid": "project-template-goal-title-input", className: "text-xs md:text-xs", value: selectedGoal.title, onChange: (event) => updateSelectedGoal((goal) => ({
2278
+ ...goal,
2279
+ title: event.target.value,
2280
+ })), placeholder: "Goal title" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-description-input", children: "Description" }), _jsx(Textarea, { id: "project-template-goal-description-input", "data-testid": "project-template-goal-description-input", className: "text-xs", rows: 3, value: selectedGoal.description ?? "", onChange: (event) => updateSelectedGoal((goal) => ({
2281
+ ...goal,
2282
+ description: event.target.value,
2283
+ })), placeholder: "What this goal covers" })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-sort-order-input", children: "Sort order" }), _jsx(Input, { id: "project-template-goal-sort-order-input", type: "number", className: "text-xs md:text-xs", value: selectedGoal.sortOrder ?? 0, onChange: (event) => updateSelectedGoal((goal) => ({
2284
+ ...goal,
2285
+ sortOrder: event.target.value.trim() === ""
2286
+ ? 0
2287
+ : Number(event.target.value),
2288
+ })) })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-default-scope-input", children: "Default scope (JSON, optional)" }), _jsx(Textarea, { id: "project-template-goal-default-scope-input", className: "font-mono text-xs", rows: 2, value: selectedGoal.defaultScopeJson ?? "", onChange: (event) => updateSelectedGoal((goal) => ({
2289
+ ...goal,
2290
+ defaultScopeJson: event.target.value,
2291
+ })), placeholder: '{"rootItemId":"...","pagesOnly":true}' })] }), _jsxs("div", { className: "grid gap-1.5", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-goal-data-shape-input", children: "Data shape hint (optional)" }), _jsx(Input, { id: "project-template-goal-data-shape-input", className: "text-xs md:text-xs", value: selectedGoal.dataShape ?? "", onChange: (event) => updateSelectedGoal((goal) => ({
2292
+ ...goal,
2293
+ dataShape: event.target.value,
2294
+ })), placeholder: "e.g. { recommendations: string[] }" })] }), _jsxs("div", { className: "flex items-center justify-between gap-4", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-neutral-grey-100 text-xs font-medium", children: "Disabled" }), _jsx("div", { className: "text-neutral-grey-50 mt-0.5 text-xs", children: "Keeps the definition but hides it from the runtime goal catalog." })] }), _jsx(Switch, { checked: selectedGoal.disabled === true, onCheckedChange: (checked) => updateSelectedGoal((goal) => ({
2295
+ ...goal,
2296
+ disabled: checked,
2297
+ })), "aria-label": "Disable this goal definition", "data-testid": "project-template-goal-disabled-switch" })] })] })) : (_jsx("div", { className: "border-border-default text-neutral-grey-50 flex items-center justify-center rounded-md border border-dashed p-6 text-center text-xs", children: "Select a goal to edit its details." }))] })) }));
2298
+ const detailAction = 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"] })) : activeDetailTab === "goals" ? (_jsxs(Button, { size: "sm", variant: "outline", onClick: () => {
2299
+ setNewGoalTitle("");
2300
+ setIsCreateGoalDialogOpen(true);
2301
+ }, disabled: creatingGoal, "data-testid": "project-template-add-goal-button", children: [_jsx(Plus, { className: "h-4 w-4", strokeWidth: 1.5 }), "Add Goal"] })) : null;
2302
+ return (_jsxs("div", { className: cn("flex min-h-0 flex-1 flex-col overflow-y-auto overscroll-y-contain md:overflow-hidden", isTaskEditorMaximized && "overflow-hidden"), children: [saveError ? (_jsx("div", { className: "flex shrink-0 flex-col pb-3 md:max-h-[50vh] md:min-h-0 md:overflow-y-auto md:overscroll-y-contain", children: _jsx("div", { className: "border-feedback-red bg-feedback-red-light text-feedback-red rounded border px-4 py-3 text-xs", children: saveError }) })) : null, _jsxs("section", { className: cn("border-border-default flex min-h-0 flex-1 flex-col rounded-lg border bg-white md:overflow-hidden", isTaskEditorMaximized &&
2303
+ "overflow-hidden rounded-none shadow-xl"), "data-testid": "project-template-task-editor-shell", children: [_jsxs("div", { className: "border-border-default flex h-[53px] shrink-0 items-center justify-between gap-3 border-b px-4 pt-3", children: [_jsx("div", { className: "min-w-0 flex-1", children: _jsx(SimpleTabs, { tabs: detailTabs, activeTab: activeDetailTab === "basic"
2304
+ ? 0
2305
+ : activeDetailTab === "tasks"
2306
+ ? 1
2307
+ : 2, setActiveTab: (index) => setActiveDetailTab(index === 0
2308
+ ? "basic"
2309
+ : index === 1
2310
+ ? "tasks"
2311
+ : "goals"), hideContent: true, className: "w-full translate-y-0.5 justify-start gap-6" }) }), detailAction ? (_jsx("div", { className: "mb-2 flex shrink-0 items-center", children: detailAction })) : null] }), _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden", children: activeDetailTab === "basic"
1881
2312
  ? basicSettingsContent
1882
- : taskEditorContent })] })] }));
2313
+ : activeDetailTab === "tasks"
2314
+ ? taskEditorContent
2315
+ : goalsContent })] })] }));
1883
2316
  })()) : (_jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center p-5", children: _jsxs("div", { className: "border-border-default max-w-sm rounded-lg border border-dashed bg-white p-8 text-center", children: [_jsx(GitBranch, { className: "text-neutral-grey-50 mx-auto mb-3 h-10 w-10", strokeWidth: 1.2 }), _jsx("h3", { className: "text-neutral-grey-100 text-xs font-medium", children: "Select a project template" }), _jsx("p", { className: "text-neutral-grey-50 mt-1 text-xs", children: "Choose a template from the dropdown or create a new one to start editing." })] }) }))] }));
1884
2317
  const overviewContent = (_jsx("div", { className: "flex h-full min-h-0 flex-col px-10 pt-0 pb-10", "data-testid": "project-template-overview", children: _jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-hidden rounded-lg bg-white", children: _jsx(ProjectTemplateSelectorList, { rootTestId: "project-template-overview-list", templates: templates, selectedTemplateId: selectedTemplateId, error: error, deleting: deleting, loading: state === "loading", onSelectTemplate: handleSelectTemplate, onDeleteTemplate: handleDeleteTemplate }) }) }));
1885
- const agentPanelContent = (_jsx(ProjectTemplateAgentPanel, { templateName: draftTemplate?.name ?? null, agentId: templateAgentId, loading: templateAgentLoading, resetting: templateAgentResetting, error: templateAgentError, onStartOver: () => void handleResetTemplateAgent(), onClose: handleHideTemplateAssistant, headerStart: isMobile ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "gap-1 px-2", onClick: handleMobileBackFromAgent, "data-testid": "project-template-mobile-back-from-agent", children: _jsx(ChevronLeft, { className: "h-5 w-5", strokeWidth: 1.5 }) })) : undefined }));
2318
+ const agentFullHeightBounds = useMemo(() => !isMobile && !isTaskEditorMaximized && settingsMainContentBounds
2319
+ ? {
2320
+ top: settingsMainContentBounds.top,
2321
+ right: settingsMainContentBounds.left + settingsMainContentBounds.width,
2322
+ height: settingsMainContentBounds.height,
2323
+ }
2324
+ : undefined, [isMobile, isTaskEditorMaximized, settingsMainContentBounds]);
2325
+ const assistantTopToggleStyle = useMemo(() => !isMobile &&
2326
+ !isTaskEditorMaximized &&
2327
+ isAgentPanelCollapsed &&
2328
+ settingsMainContentBounds
2329
+ ? {
2330
+ position: "fixed",
2331
+ top: settingsMainContentBounds.top + 8,
2332
+ left: settingsMainContentBounds.left +
2333
+ settingsMainContentBounds.width -
2334
+ 88,
2335
+ zIndex: 45,
2336
+ }
2337
+ : undefined, [
2338
+ isAgentPanelCollapsed,
2339
+ isMobile,
2340
+ isTaskEditorMaximized,
2341
+ settingsMainContentBounds,
2342
+ ]);
2343
+ const agentPanelContent = (_jsx(ProjectTemplateAgentPanel, { templateName: draftTemplate?.name ?? null, agentId: templateAgentId, loading: templateAgentLoading, resetting: templateAgentResetting, error: templateAgentError, initialMetadata: templateAgentInitialMetadata, fullHeightBounds: agentFullHeightBounds, onStartOver: () => void handleResetTemplateAgent(), onClose: handleHideTemplateAssistant, headerStart: isMobile ? (_jsx(Button, { type: "button", variant: "ghost", size: "sm", className: "gap-1 px-2", onClick: handleMobileBackFromAgent, "data-testid": "project-template-mobile-back-from-agent", children: _jsx(ChevronLeft, { className: "h-5 w-5", strokeWidth: 1.5 }) })) : undefined }));
1886
2344
  const rightPanelContent = editingAgentProfile ? (_jsx(AgentProfileEditorPanel, { agent: editingAgentProfile, onClose: handleCloseEditingAgentProfile, actions: _jsxs(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void handleDuplicateAssignedAgentProfile(), disabled: !selectedAgentProfileId ||
1887
2345
  !editContext ||
1888
2346
  duplicatingAgentProfile ||
@@ -1899,7 +2357,7 @@ export function ProjectTemplatesPanel() {
1899
2357
  name: "project-template-agent",
1900
2358
  defaultSize: 460,
1901
2359
  content: rightPanelContent,
1902
- className: "overflow-hidden",
2360
+ className: "overflow-hidden bg-white",
1903
2361
  collapsible: true,
1904
2362
  hidden: isMobile && mobileView !== "agent",
1905
2363
  },
@@ -1910,7 +2368,9 @@ export function ProjectTemplatesPanel() {
1910
2368
  if (!draftTemplate) {
1911
2369
  return overviewContent;
1912
2370
  }
1913
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: cn("h-full", !isTaskEditorMaximized && "px-10 pt-0 pb-10"), children: _jsx("div", { className: cn("h-full", isTaskEditorMaximized && "fixed overflow-hidden bg-white shadow-xl"), style: projectTemplateEditorStyle, "data-testid": "project-template-editor", onKeyDownCapture: handleProjectTemplateEditorKeyDownCapture, children: _jsx(Splitter, { panels: panels, localStorageKey: PROJECT_TEMPLATE_SPLITTER_STORAGE_KEY, direction: "horizontal", className: "h-full", forceCollapseLastPanelKey: forceCollapseLastPanelKey, forceExpandLastPanelKey: forceExpandLastPanelKey }) }) }), _jsx(Dialog, { open: isCreateTaskDialogOpen, onOpenChange: (open) => {
2371
+ return (_jsxs(_Fragment, { children: [assistantTopToggleStyle ? (_jsx(Button, { type: "button", variant: "outline", size: "icon", className: "h-8 w-8 rounded-md bg-white shadow-sm hover:bg-white", style: assistantTopToggleStyle, onClick: handleShowTemplateAssistant, "aria-label": "Show template assistant", title: "Show template assistant", "data-testid": "project-template-assistant-expand-button", children: _jsx(PanelRightOpen, { className: "h-5 w-5", strokeWidth: 1 }) })) : null, _jsx("div", { className: cn("h-full", !isTaskEditorMaximized && "px-10 pt-0 pb-5"), children: _jsx("div", { className: cn("h-full", isTaskEditorMaximized && "fixed overflow-hidden bg-white shadow-xl"), style: projectTemplateEditorStyle, "data-testid": "project-template-editor", onKeyDownCapture: handleProjectTemplateEditorKeyDownCapture, children: _jsx(Splitter, { panels: panels, localStorageKey: PROJECT_TEMPLATE_SPLITTER_STORAGE_KEY, direction: "horizontal", className: "h-full !overflow-visible", expandLabel: _jsx(PanelRightOpen, { className: "h-5 w-5", strokeWidth: 1 }), expandButtonLabel: "Show template assistant", expandButtonTestId: isTaskEditorMaximized
2372
+ ? "project-template-assistant-expand-button"
2373
+ : undefined, expandButtonClassName: cn("border-border-default absolute right-4 z-50 h-8 w-8 rounded-md bg-white p-0 text-neutral-grey-100 shadow-sm backdrop-blur-sm hover:bg-white hover:text-neutral-grey-100 md:p-0", isTaskEditorMaximized ? "top-4" : "hidden"), forceCollapseLastPanelKey: forceCollapseLastPanelKey, forceExpandLastPanelKey: forceExpandLastPanelKey, onLastPanelCollapsedChange: setIsAgentPanelCollapsed }) }) }), _jsx(Dialog, { open: isCreateTaskDialogOpen, onOpenChange: (open) => {
1914
2374
  setIsCreateTaskDialogOpen(open);
1915
2375
  if (!open) {
1916
2376
  setNewTaskDependencySourceId(null);
@@ -1928,7 +2388,12 @@ export function ProjectTemplatesPanel() {
1928
2388
  ? "Creating..."
1929
2389
  : newTaskDependencySourceId
1930
2390
  ? "Create Dependent Task"
1931
- : "Create Task" })] })] }) }), _jsx(Dialog, { open: isAddChildTaskDialogOpen, onOpenChange: setIsAddChildTaskDialogOpen, children: _jsxs(DialogContent, { className: "max-w-md", "data-testid": "project-template-create-child-task-dialog", children: [_jsx(StyledDialogTitle, { icon: _jsx(Plus, { strokeWidth: 1.5 }), title: "Add Child Task", subtitle: "Creates a new task that depends on the current task." }), _jsxs("div", { className: "grid gap-2 p-6", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-new-child-task-title", children: "Task title" }), _jsx(Input, { id: "project-template-new-child-task-title", value: newChildTaskTitle, onChange: (event) => setNewChildTaskTitle(event.target.value), placeholder: "e.g. Review content", className: "text-xs md:text-xs", autoFocus: true, onKeyDown: (event) => {
2391
+ : "Create Task" })] })] }) }), _jsx(Dialog, { open: isCreateGoalDialogOpen, onOpenChange: setIsCreateGoalDialogOpen, children: _jsxs(DialogContent, { className: "max-w-md", "data-testid": "project-template-create-goal-dialog", children: [_jsx(StyledDialogTitle, { icon: _jsx(Plus, { strokeWidth: 1.5 }), title: "Add Goal Definition", subtitle: "Create the goal and save it immediately." }), _jsxs("div", { className: "grid gap-2 p-6", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-new-goal-title", children: "Goal title" }), _jsx(Input, { id: "project-template-new-goal-title", value: newGoalTitle, onChange: (event) => setNewGoalTitle(event.target.value), placeholder: "e.g. Review all pages", className: "text-xs md:text-xs", autoFocus: true, onKeyDown: (event) => {
2392
+ if (event.key === "Enter" && !event.shiftKey) {
2393
+ event.preventDefault();
2394
+ void handleConfirmCreateGoal();
2395
+ }
2396
+ } })] }), _jsxs(DialogFooter, { className: "px-6 pt-0 pb-6", children: [_jsx(Button, { variant: "outline", onClick: () => setIsCreateGoalDialogOpen(false), disabled: creatingGoal, "data-testid": "project-template-create-goal-cancel-button", children: "Cancel" }), _jsx(Button, { onClick: () => void handleConfirmCreateGoal(), disabled: creatingGoal || !newGoalTitle.trim(), "data-testid": "project-template-create-goal-submit-button", children: creatingGoal ? "Creating..." : "Create Goal" })] })] }) }), _jsx(Dialog, { open: isAddChildTaskDialogOpen, onOpenChange: setIsAddChildTaskDialogOpen, children: _jsxs(DialogContent, { className: "max-w-md", "data-testid": "project-template-create-child-task-dialog", children: [_jsx(StyledDialogTitle, { icon: _jsx(Plus, { strokeWidth: 1.5 }), title: "Add Child Task", subtitle: "Creates a new task that depends on the current task." }), _jsxs("div", { className: "grid gap-2 p-6", children: [_jsx(Label, { className: "text-xs", htmlFor: "project-template-new-child-task-title", children: "Task title" }), _jsx(Input, { id: "project-template-new-child-task-title", value: newChildTaskTitle, onChange: (event) => setNewChildTaskTitle(event.target.value), placeholder: "e.g. Review content", className: "text-xs md:text-xs", autoFocus: true, onKeyDown: (event) => {
1932
2397
  if (event.key === "Enter" && !event.shiftKey) {
1933
2398
  event.preventDefault();
1934
2399
  void handleConfirmCreateChildTask();