@parhelia/core 0.1.12390 → 0.1.12397

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 (79) hide show
  1. package/dist/editor/Editor.js +32 -17
  2. package/dist/editor/Editor.js.map +1 -1
  3. package/dist/editor/PictureCropper.js +9 -4
  4. package/dist/editor/PictureCropper.js.map +1 -1
  5. package/dist/editor/PictureEditor.js +12 -13
  6. package/dist/editor/PictureEditor.js.map +1 -1
  7. package/dist/editor/SetupWizard.js +20 -2
  8. package/dist/editor/SetupWizard.js.map +1 -1
  9. package/dist/editor/ai/AgentTerminal.js +14 -3
  10. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  11. package/dist/editor/ai/dialogs/agentDialogTypes.d.ts +1 -1
  12. package/dist/editor/client/editContext.d.ts +4 -0
  13. package/dist/editor/client/editContext.js.map +1 -1
  14. package/dist/editor/page-editor-chrome/useInlineAICompletion.js +283 -298
  15. package/dist/editor/page-editor-chrome/useInlineAICompletion.js.map +1 -1
  16. package/dist/editor/pictureRawValue.d.ts +3 -0
  17. package/dist/editor/pictureRawValue.js +30 -0
  18. package/dist/editor/pictureRawValue.js.map +1 -0
  19. package/dist/editor/services/templateBuilderService.d.ts +7 -0
  20. package/dist/editor/services/templateBuilderService.js +7 -1
  21. package/dist/editor/services/templateBuilderService.js.map +1 -1
  22. package/dist/editor/settings/About.js +25 -19
  23. package/dist/editor/settings/About.js.map +1 -1
  24. package/dist/editor/settings/panels/AgentProfileEditorPanel.d.ts +14 -0
  25. package/dist/editor/settings/panels/AgentProfileEditorPanel.js +7 -0
  26. package/dist/editor/settings/panels/AgentProfileEditorPanel.js.map +1 -0
  27. package/dist/editor/settings/panels/AgentsPanel.js +2 -2
  28. package/dist/editor/settings/panels/AgentsPanel.js.map +1 -1
  29. package/dist/editor/settings/panels/ProjectTemplatesPanel.js +146 -8
  30. package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
  31. package/dist/editor/setup-wizard/steps/CompleteStep.d.ts +2 -1
  32. package/dist/editor/setup-wizard/steps/CompleteStep.js +2 -1
  33. package/dist/editor/setup-wizard/steps/CompleteStep.js.map +1 -1
  34. package/dist/editor/setup-wizard/steps/LicenseActivationStep.d.ts +9 -0
  35. package/dist/editor/setup-wizard/steps/LicenseActivationStep.js +160 -0
  36. package/dist/editor/setup-wizard/steps/LicenseActivationStep.js.map +1 -0
  37. package/dist/editor/setup-wizard/steps/LicenseEmailStep.d.ts +10 -0
  38. package/dist/editor/setup-wizard/steps/LicenseEmailStep.js +101 -0
  39. package/dist/editor/setup-wizard/steps/LicenseEmailStep.js.map +1 -0
  40. package/dist/editor/template-wizard/TemplateStructureInlineEditor.js +422 -65
  41. package/dist/editor/template-wizard/TemplateStructureInlineEditor.js.map +1 -1
  42. package/dist/licensing/EmailEntry.js +1 -1
  43. package/dist/licensing/EmailEntry.js.map +1 -1
  44. package/dist/licensing/LicenseActivationForm.js +1 -1
  45. package/dist/licensing/LicenseActivationForm.js.map +1 -1
  46. package/dist/licensing/LicenseCodeEntry.js +2 -2
  47. package/dist/licensing/LicenseCodeEntry.js.map +1 -1
  48. package/dist/licensing/LicenseContext.js +18 -9
  49. package/dist/licensing/LicenseContext.js.map +1 -1
  50. package/dist/licensing/LicenseOverlay.js +2 -1
  51. package/dist/licensing/LicenseOverlay.js.map +1 -1
  52. package/dist/licensing/licenseService.d.ts +10 -0
  53. package/dist/licensing/licenseService.js +28 -0
  54. package/dist/licensing/licenseService.js.map +1 -1
  55. package/dist/revision.d.ts +2 -2
  56. package/dist/revision.js +2 -2
  57. package/dist/task-board/TaskBoardWorkspace.js +3 -2
  58. package/dist/task-board/TaskBoardWorkspace.js.map +1 -1
  59. package/dist/task-board/components/ProjectDashboard.d.ts +4 -0
  60. package/dist/task-board/components/ProjectDashboard.js +1 -1
  61. package/dist/task-board/components/ProjectDashboard.js.map +1 -1
  62. package/dist/task-board/components/ProjectListContent.d.ts +1 -1
  63. package/dist/task-board/components/ProjectListContent.js +4 -1
  64. package/dist/task-board/components/ProjectListContent.js.map +1 -1
  65. package/dist/task-board/components/ProjectOverviewContent.d.ts +17 -0
  66. package/dist/task-board/components/ProjectOverviewContent.js +134 -0
  67. package/dist/task-board/components/ProjectOverviewContent.js.map +1 -0
  68. package/dist/task-board/components/ProjectSelector.d.ts +1 -1
  69. package/dist/task-board/components/ProjectSelector.js +1 -1
  70. package/dist/task-board/components/ProjectSelector.js.map +1 -1
  71. package/dist/task-board/components/TaskDetailPanel.js +59 -9
  72. package/dist/task-board/components/TaskDetailPanel.js.map +1 -1
  73. package/dist/task-board/services/taskService.d.ts +4 -1
  74. package/dist/task-board/services/taskService.js +3 -0
  75. package/dist/task-board/services/taskService.js.map +1 -1
  76. package/dist/task-board/taskBoardNavStore.d.ts +3 -1
  77. package/dist/task-board/taskBoardNavStore.js.map +1 -1
  78. package/dist/task-board/types.d.ts +30 -0
  79. package/package.json +1 -1
@@ -2,10 +2,13 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { Bot, Check, ChevronDown, ChevronRight, GripVertical, Plus, Search, Settings2, Trash2, X, } from "lucide-react";
5
+ import { Button } from "../../components/ui/button";
6
+ import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
5
7
  import { AgentTerminal } from "../ai/AgentTerminal";
8
+ import DialogButtons from "../ui/DialogButtons";
6
9
  import { useEditContext } from "../client/editContext";
7
10
  import TreeListSelector from "../ui/TreeListSelector";
8
- import { parseTemplateBuilderSuggestionText, TEMPLATE_BUILDER_AGENT_PROFILE_ID, TEMPLATE_BUILDER_AGENT_PROFILE_NAME, TEMPLATE_BUILDER_SUGGESTION_SCHEMA_DESCRIPTION, templateBuilderCreate, templateBuilderFieldTypes, templateBuilderGet, templateBuilderUpdate, } from "../services/templateBuilderService";
11
+ import { parseTemplateBuilderSuggestionText, TEMPLATE_BUILDER_AGENT_PROFILE_ID, TEMPLATE_BUILDER_AGENT_PROFILE_NAME, TEMPLATE_BUILDER_SUGGESTION_SCHEMA_DESCRIPTION, templateBuilderCreate, templateBuilderFieldTypes, templateBuilderGet, templateBuilderSkills, templateBuilderUpdate, } from "../services/templateBuilderService";
9
12
  import { loadAiProfiles } from "../services/aiService";
10
13
  import { normalizeGuid } from "../utils";
11
14
  const TEMPLATE_TEMPLATE_ID = "AB86861A-6030-46C5-B394-E8F99E8B87DB";
@@ -69,6 +72,234 @@ const toWizardSection = (section) => ({
69
72
  name: section?.name || "",
70
73
  fields: (section?.fields || []).map((field) => toWizardField(field)),
71
74
  });
75
+ const cloneWizardField = (field) => ({
76
+ ...field,
77
+ });
78
+ const cloneWizardSection = (section) => ({
79
+ ...section,
80
+ fields: section.fields.map(cloneWizardField),
81
+ });
82
+ const sameBaseTemplateChangeTarget = (left, right) => (!!left.templateId &&
83
+ !!right.templateId &&
84
+ normalizeGuid(left.templateId) === normalizeGuid(right.templateId)) ||
85
+ normalizeName(left.templateName) === normalizeName(right.templateName) ||
86
+ (!!left.templatePath &&
87
+ !!right.templatePath &&
88
+ normalizeName(left.templatePath) === normalizeName(right.templatePath));
89
+ const findSectionIndex = (sectionList, targetSectionLocalId, targetSectionName) => sectionList.findIndex((sectionItem) => (!!targetSectionLocalId && sectionItem.localId === targetSectionLocalId) ||
90
+ (!!targetSectionName &&
91
+ normalizeName(sectionItem.name) === normalizeName(targetSectionName)));
92
+ const findFieldIndex = (fieldList, targetFieldLocalId, targetFieldName) => fieldList.findIndex((fieldItem) => (!!targetFieldLocalId && fieldItem.localId === targetFieldLocalId) ||
93
+ (!!targetFieldName && normalizeName(fieldItem.name) === normalizeName(targetFieldName)));
94
+ function applyPendingSuggestionsToSections(baseSections, pendingChanges) {
95
+ const mergedSections = baseSections.map(cloneWizardSection);
96
+ for (const change of pendingChanges) {
97
+ if (change.kind === "section") {
98
+ if (change.action === "add") {
99
+ mergedSections.push(cloneWizardSection(change.section));
100
+ continue;
101
+ }
102
+ const sectionIndex = findSectionIndex(mergedSections, change.targetSectionLocalId, change.targetSectionName);
103
+ if (sectionIndex < 0)
104
+ continue;
105
+ if (change.action === "remove") {
106
+ mergedSections.splice(sectionIndex, 1);
107
+ continue;
108
+ }
109
+ const sectionToUpdate = mergedSections[sectionIndex];
110
+ if (!sectionToUpdate)
111
+ continue;
112
+ mergedSections[sectionIndex] = {
113
+ ...sectionToUpdate,
114
+ name: change.section.name,
115
+ };
116
+ continue;
117
+ }
118
+ if (change.kind !== "field")
119
+ continue;
120
+ const sectionIndex = findSectionIndex(mergedSections, change.sectionLocalId, change.targetSectionName);
121
+ if (sectionIndex < 0)
122
+ continue;
123
+ const targetSection = mergedSections[sectionIndex];
124
+ if (!targetSection)
125
+ continue;
126
+ if (change.action === "add") {
127
+ targetSection.fields.push(cloneWizardField(change.field));
128
+ continue;
129
+ }
130
+ const fieldIndex = findFieldIndex(targetSection.fields, change.targetFieldLocalId, change.targetFieldName);
131
+ if (fieldIndex < 0)
132
+ continue;
133
+ if (change.action === "remove") {
134
+ targetSection.fields.splice(fieldIndex, 1);
135
+ continue;
136
+ }
137
+ const fieldToUpdate = targetSection.fields[fieldIndex];
138
+ if (!fieldToUpdate)
139
+ continue;
140
+ targetSection.fields[fieldIndex] = cloneWizardField(change.field);
141
+ }
142
+ return mergedSections;
143
+ }
144
+ function mergePendingSuggestionChanges(existingChanges, incomingChanges) {
145
+ const merged = [...existingChanges];
146
+ for (const change of incomingChanges) {
147
+ if (change.kind === "baseTemplate") {
148
+ const inverseIndex = merged.findIndex((entry) => entry.kind === "baseTemplate" &&
149
+ entry.action !== change.action &&
150
+ sameBaseTemplateChangeTarget(entry, change));
151
+ if (inverseIndex >= 0) {
152
+ merged.splice(inverseIndex, 1);
153
+ continue;
154
+ }
155
+ merged.push(change);
156
+ continue;
157
+ }
158
+ if (change.kind === "section" && change.action === "add") {
159
+ const duplicateSectionAddIndex = merged.findIndex((entry) => entry.kind === "section" &&
160
+ entry.action === "add" &&
161
+ normalizeName(entry.section.name) === normalizeName(change.section.name));
162
+ if (duplicateSectionAddIndex >= 0) {
163
+ const existingEntry = merged[duplicateSectionAddIndex];
164
+ if (existingEntry &&
165
+ existingEntry.kind === "section" &&
166
+ existingEntry.action === "add") {
167
+ merged[duplicateSectionAddIndex] = {
168
+ ...existingEntry,
169
+ reason: change.reason ?? existingEntry.reason,
170
+ section: {
171
+ ...existingEntry.section,
172
+ name: change.section.name,
173
+ fields: change.section.fields.map(cloneWizardField),
174
+ },
175
+ };
176
+ continue;
177
+ }
178
+ }
179
+ merged.push(change);
180
+ continue;
181
+ }
182
+ if (change.kind === "section" && change.action !== "add") {
183
+ const pendingSectionAddIndex = merged.findIndex((entry) => entry.kind === "section" &&
184
+ entry.action === "add" &&
185
+ entry.section.localId === change.targetSectionLocalId);
186
+ if (pendingSectionAddIndex >= 0) {
187
+ const pendingSectionEntry = merged[pendingSectionAddIndex];
188
+ if (pendingSectionEntry &&
189
+ pendingSectionEntry.kind === "section" &&
190
+ pendingSectionEntry.action === "add") {
191
+ if (change.action === "remove") {
192
+ const removedSectionLocalId = pendingSectionEntry.section.localId;
193
+ merged.splice(pendingSectionAddIndex, 1);
194
+ for (let index = merged.length - 1; index >= 0; index--) {
195
+ const entry = merged[index];
196
+ if (!entry)
197
+ continue;
198
+ if (entry.kind === "field" &&
199
+ entry.sectionLocalId === removedSectionLocalId) {
200
+ merged.splice(index, 1);
201
+ }
202
+ }
203
+ continue;
204
+ }
205
+ const updatedPendingSection = {
206
+ ...pendingSectionEntry,
207
+ section: {
208
+ ...pendingSectionEntry.section,
209
+ name: change.section.name,
210
+ },
211
+ };
212
+ merged[pendingSectionAddIndex] = updatedPendingSection;
213
+ continue;
214
+ }
215
+ }
216
+ merged.push(change);
217
+ continue;
218
+ }
219
+ if (change.kind === "field") {
220
+ const pendingSectionAddIndex = merged.findIndex((entry) => entry.kind === "section" &&
221
+ entry.action === "add" &&
222
+ entry.section.localId === change.sectionLocalId);
223
+ if (pendingSectionAddIndex >= 0) {
224
+ const pendingSectionAdd = merged[pendingSectionAddIndex];
225
+ if (!pendingSectionAdd ||
226
+ pendingSectionAdd.kind !== "section" ||
227
+ pendingSectionAdd.action !== "add") {
228
+ // Fall through to default handling
229
+ }
230
+ else {
231
+ const pendingFieldIndex = change.action === "add"
232
+ ? -1
233
+ : findFieldIndex(pendingSectionAdd.section.fields, change.targetFieldLocalId, change.targetFieldName);
234
+ if (change.action === "add") {
235
+ const duplicateFieldIndex = findFieldIndex(pendingSectionAdd.section.fields, undefined, change.field.name);
236
+ const nextFields = [...pendingSectionAdd.section.fields];
237
+ if (duplicateFieldIndex >= 0) {
238
+ nextFields[duplicateFieldIndex] = cloneWizardField(change.field);
239
+ }
240
+ else {
241
+ nextFields.push(cloneWizardField(change.field));
242
+ }
243
+ const updated = {
244
+ ...pendingSectionAdd,
245
+ section: {
246
+ ...pendingSectionAdd.section,
247
+ fields: nextFields,
248
+ },
249
+ };
250
+ merged[pendingSectionAddIndex] = updated;
251
+ continue;
252
+ }
253
+ if (pendingFieldIndex >= 0) {
254
+ const nextFields = [...pendingSectionAdd.section.fields];
255
+ if (change.action === "remove") {
256
+ nextFields.splice(pendingFieldIndex, 1);
257
+ }
258
+ else {
259
+ nextFields[pendingFieldIndex] = cloneWizardField(change.field);
260
+ }
261
+ const updated = {
262
+ ...pendingSectionAdd,
263
+ section: {
264
+ ...pendingSectionAdd.section,
265
+ fields: nextFields,
266
+ },
267
+ };
268
+ merged[pendingSectionAddIndex] = updated;
269
+ continue;
270
+ }
271
+ }
272
+ }
273
+ if (change.action !== "add") {
274
+ const pendingFieldAddIndex = merged.findIndex((entry) => entry.kind === "field" &&
275
+ entry.action === "add" &&
276
+ entry.sectionLocalId === change.sectionLocalId &&
277
+ (findFieldIndex([entry.field], change.targetFieldLocalId, change.targetFieldName) >= 0 ||
278
+ normalizeName(entry.field.name) === normalizeName(change.field.name)));
279
+ if (pendingFieldAddIndex >= 0) {
280
+ const pendingFieldEntry = merged[pendingFieldAddIndex];
281
+ if (pendingFieldEntry && pendingFieldEntry.kind === "field") {
282
+ if (change.action === "remove") {
283
+ merged.splice(pendingFieldAddIndex, 1);
284
+ }
285
+ else {
286
+ const updated = {
287
+ ...pendingFieldEntry,
288
+ field: cloneWizardField(change.field),
289
+ };
290
+ merged[pendingFieldAddIndex] = updated;
291
+ }
292
+ continue;
293
+ }
294
+ }
295
+ }
296
+ merged.push(change);
297
+ continue;
298
+ }
299
+ merged.push(change);
300
+ }
301
+ return merged;
302
+ }
72
303
  function toRequestSections(sections) {
73
304
  return sections
74
305
  .filter((section) => section.name.trim())
@@ -100,7 +331,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
100
331
  const [isLoading, setIsLoading] = useState(true);
101
332
  const [isSaving, setIsSaving] = useState(false);
102
333
  const [fieldTypeGroups, setFieldTypeGroups] = useState([{ name: "General", types: defaultFieldTypeOptions }]);
103
- const [templateName, setTemplateName] = useState(initialName || "New Template");
334
+ const [templateName, setTemplateName] = useState(() => initialName || item?.name || "New Template");
104
335
  const [baseTemplates, setBaseTemplates] = useState([]);
105
336
  const [selectedTemplateNodesInTree, setSelectedTemplateNodesInTree] = useState([]);
106
337
  const [fieldSearchQuery, setFieldSearchQuery] = useState("");
@@ -120,12 +351,16 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
120
351
  const [dragOverFieldEndSectionIdx, setDragOverFieldEndSectionIdx] = useState(null);
121
352
  const [focusFieldDraftSectionIndex, setFocusFieldDraftSectionIndex] = useState(null);
122
353
  const [aiProfiles, setAiProfiles] = useState([]);
354
+ const [templateBuilderConfiguredSkills, setTemplateBuilderConfiguredSkills] = useState([]);
123
355
  const [pendingSuggestions, setPendingSuggestions] = useState([]);
124
356
  const [latestSuggestionSummary, setLatestSuggestionSummary] = useState(null);
125
357
  const [suggestionParseError, setSuggestionParseError] = useState(null);
126
358
  const [suggestionStatus, setSuggestionStatus] = useState(null);
359
+ const [templatePickerOpen, setTemplatePickerOpen] = useState(false);
360
+ const [templatePickerPortalContainer, setTemplatePickerPortalContainer] = useState(null);
127
361
  const newFieldNameInputRefs = useRef({});
128
362
  const processedSuggestionMessageIdsRef = useRef(new Set());
363
+ const templatePickerTriggerRef = useRef(null);
129
364
  const flatFieldTypeOptions = fieldTypeGroups.flatMap((group) => group.types || []);
130
365
  const createEmptyFieldWithDefaultType = () => ({
131
366
  ...createEmptyField(),
@@ -136,6 +371,33 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
136
371
  name: "",
137
372
  fields: [createEmptyFieldWithDefaultType()],
138
373
  });
374
+ const effectiveSections = useMemo(() => applyPendingSuggestionsToSections(sections, pendingSuggestions), [pendingSuggestions, sections]);
375
+ const effectiveBaseTemplates = useMemo(() => {
376
+ const merged = [...baseTemplates];
377
+ for (const change of pendingSuggestions) {
378
+ if (change.kind !== "baseTemplate")
379
+ continue;
380
+ const existingIndex = merged.findIndex((template) => sameBaseTemplateChangeTarget({
381
+ templateId: template.id,
382
+ templateName: template.name,
383
+ templatePath: template.path,
384
+ }, change));
385
+ if (change.action === "remove") {
386
+ if (existingIndex >= 0) {
387
+ merged.splice(existingIndex, 1);
388
+ }
389
+ continue;
390
+ }
391
+ if (existingIndex < 0) {
392
+ merged.push({
393
+ id: change.templateId || createLocalId("base-template"),
394
+ name: change.templateName,
395
+ path: change.templatePath,
396
+ });
397
+ }
398
+ }
399
+ return merged;
400
+ }, [baseTemplates, pendingSuggestions]);
139
401
  const [templateBuilderAgent] = useState(() => ({
140
402
  id: createGuid(),
141
403
  name: "Template Builder",
@@ -510,6 +772,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
510
772
  setSections([createEmptySectionWithDefaultType()]);
511
773
  return;
512
774
  }
775
+ setTemplateName(item.name?.trim() || initialName || "New Template");
513
776
  const result = await templateBuilderGet({ template: item.descriptor });
514
777
  if (result.type !== "success" || !result.data) {
515
778
  editContextRef.current?.showErrorToast({
@@ -579,7 +842,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
579
842
  item,
580
843
  ]);
581
844
  const save = async () => {
582
- if (isCreateMode && !templateName.trim()) {
845
+ if (!templateName.trim()) {
583
846
  editContext?.showErrorToast({
584
847
  summary: "Template name is required",
585
848
  });
@@ -674,6 +937,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
674
937
  }
675
938
  const result = await templateBuilderUpdate({
676
939
  template: item.descriptor,
940
+ name: templateName.trim(),
677
941
  baseTemplateIds,
678
942
  sections: toRequestSections(sections),
679
943
  createStandardValues: hasStandardValues,
@@ -738,16 +1002,13 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
738
1002
  };
739
1003
  useEffect(() => {
740
1004
  let cancelled = false;
741
- loadAiProfiles()
742
- .then((loadedProfiles) => {
1005
+ Promise.allSettled([loadAiProfiles(), templateBuilderSkills()]).then((results) => {
743
1006
  if (cancelled)
744
1007
  return;
745
- setAiProfiles(loadedProfiles);
746
- })
747
- .catch(() => {
748
- if (!cancelled) {
749
- setAiProfiles([]);
750
- }
1008
+ const loadedProfiles = results[0];
1009
+ setAiProfiles(loadedProfiles.status === "fulfilled" ? loadedProfiles.value : []);
1010
+ const configuredSkills = results[1];
1011
+ setTemplateBuilderConfiguredSkills(configuredSkills.status === "fulfilled" ? configuredSkills.value : []);
751
1012
  });
752
1013
  return () => {
753
1014
  cancelled = true;
@@ -758,13 +1019,13 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
758
1019
  templateName: templateName.trim() || "New Template",
759
1020
  template: item?.descriptor,
760
1021
  parent: parentItem?.descriptor,
761
- baseTemplates: baseTemplates.map((template) => ({
1022
+ baseTemplates: effectiveBaseTemplates.map((template) => ({
762
1023
  id: template.id,
763
1024
  name: template.name,
764
1025
  path: template.path,
765
1026
  icon: template.icon,
766
1027
  })),
767
- sections: sections.map((sectionItem) => ({
1028
+ sections: effectiveSections.map((sectionItem) => ({
768
1029
  name: sectionItem.name,
769
1030
  fields: sectionItem.fields.map((field) => ({
770
1031
  name: field.name,
@@ -778,7 +1039,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
778
1039
  unversioned: field.unversioned,
779
1040
  })),
780
1041
  })),
781
- }), [baseTemplates, isCreateMode, item, parentItem, sections, templateName]);
1042
+ }), [effectiveBaseTemplates, effectiveSections, isCreateMode, item, parentItem, templateName]);
782
1043
  const currentTemplateId = useMemo(() => (item?.id ? normalizeGuid(item.id) : ""), [item?.id]);
783
1044
  const templateBuilderAgentMetadata = useMemo(() => ({
784
1045
  mode: "read-only",
@@ -791,21 +1052,45 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
791
1052
  },
792
1053
  }), [currentTemplateBuilderState]);
793
1054
  const effectiveAiProfiles = useMemo(() => {
1055
+ const mergeTemplateBuilderSkills = (profile) => {
1056
+ if (normalizeGuid(profile.id) !== normalizeGuid(TEMPLATE_BUILDER_AGENT_PROFILE_ID)) {
1057
+ return profile;
1058
+ }
1059
+ const mergedSkills = [
1060
+ ...(profile.allowedSkills || []),
1061
+ ...templateBuilderConfiguredSkills,
1062
+ ].reduce((acc, skill) => {
1063
+ if (!skill?.id || !skill?.name)
1064
+ return acc;
1065
+ const exists = acc.some((entry) => normalizeGuid(entry.id) === normalizeGuid(skill.id));
1066
+ if (!exists) {
1067
+ acc.push(skill);
1068
+ }
1069
+ return acc;
1070
+ }, []);
1071
+ if (mergedSkills.length === 0) {
1072
+ return profile;
1073
+ }
1074
+ return {
1075
+ ...profile,
1076
+ allowedSkills: mergedSkills,
1077
+ };
1078
+ };
794
1079
  if (aiProfiles.some((profile) => normalizeGuid(profile.id) === normalizeGuid(TEMPLATE_BUILDER_AGENT_PROFILE_ID))) {
795
- return aiProfiles;
1080
+ return aiProfiles.map(mergeTemplateBuilderSkills);
796
1081
  }
797
1082
  return [
798
- {
1083
+ mergeTemplateBuilderSkills({
799
1084
  id: TEMPLATE_BUILDER_AGENT_PROFILE_ID,
800
1085
  name: TEMPLATE_BUILDER_AGENT_PROFILE_NAME,
801
1086
  defaultModelId: "",
802
1087
  models: [],
803
1088
  prompts: [],
804
1089
  hiddenFromOverview: true,
805
- },
1090
+ }),
806
1091
  ...aiProfiles,
807
1092
  ];
808
- }, [aiProfiles]);
1093
+ }, [aiProfiles, templateBuilderConfiguredSkills]);
809
1094
  const hydrateFieldFromPatch = useCallback((patch, fallback) => ({
810
1095
  localId: createLocalId("field"),
811
1096
  name: patch.name ?? fallback?.name ?? "",
@@ -824,6 +1109,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
824
1109
  }), [flatFieldTypeOptions]);
825
1110
  const convertSuggestionToPendingChanges = useCallback((suggestion) => {
826
1111
  const nextChanges = [];
1112
+ const workingSections = effectiveSections.map(cloneWizardSection);
827
1113
  for (const baseTemplateChange of suggestion.baseTemplates || []) {
828
1114
  nextChanges.push({
829
1115
  id: createLocalId("base-template-suggestion"),
@@ -837,23 +1123,26 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
837
1123
  }
838
1124
  for (const sectionChange of suggestion.sections || []) {
839
1125
  if (sectionChange.action === "add") {
1126
+ const nextSection = {
1127
+ ...toWizardSection(sectionChange.section),
1128
+ fields: (sectionChange.section.fields || []).map((field) => hydrateFieldFromPatch(field)),
1129
+ };
840
1130
  nextChanges.push({
841
1131
  id: createLocalId("section-suggestion"),
842
1132
  kind: "section",
843
1133
  action: "add",
844
- section: {
845
- ...toWizardSection(sectionChange.section),
846
- fields: (sectionChange.section.fields || []).map((field) => hydrateFieldFromPatch(field)),
847
- },
1134
+ section: nextSection,
848
1135
  reason: sectionChange.reason,
849
1136
  });
1137
+ workingSections.push(cloneWizardSection(nextSection));
850
1138
  continue;
851
1139
  }
852
- const matchedSection = sections.find((sectionItem) => normalizeName(sectionItem.name) ===
1140
+ const matchedSection = workingSections.find((sectionItem) => normalizeName(sectionItem.name) ===
853
1141
  normalizeName(sectionChange.targetSectionName));
854
1142
  if (!matchedSection)
855
1143
  continue;
856
1144
  if (sectionChange.action === "update") {
1145
+ matchedSection.name = sectionChange.section.name ?? matchedSection.name;
857
1146
  nextChanges.push({
858
1147
  id: createLocalId("section-suggestion"),
859
1148
  kind: "section",
@@ -869,6 +1158,10 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
869
1158
  });
870
1159
  continue;
871
1160
  }
1161
+ const matchedSectionIndex = workingSections.findIndex((sectionItem) => sectionItem.localId === matchedSection.localId);
1162
+ if (matchedSectionIndex >= 0) {
1163
+ workingSections.splice(matchedSectionIndex, 1);
1164
+ }
872
1165
  nextChanges.push({
873
1166
  id: createLocalId("section-suggestion"),
874
1167
  kind: "section",
@@ -880,38 +1173,66 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
880
1173
  });
881
1174
  }
882
1175
  for (const fieldChange of suggestion.fields || []) {
883
- const matchedSection = sections.find((sectionItem) => normalizeName(sectionItem.name) === normalizeName(fieldChange.targetSectionName));
884
- if (!matchedSection)
885
- continue;
1176
+ let matchedSection = workingSections.find((sectionItem) => normalizeName(sectionItem.name) === normalizeName(fieldChange.targetSectionName));
886
1177
  if (fieldChange.action === "add") {
1178
+ if (!matchedSection) {
1179
+ const syntheticSection = {
1180
+ localId: createLocalId("section"),
1181
+ name: fieldChange.targetSectionName,
1182
+ fields: [],
1183
+ };
1184
+ const workingSyntheticSection = cloneWizardSection(syntheticSection);
1185
+ nextChanges.push({
1186
+ id: createLocalId("section-suggestion"),
1187
+ kind: "section",
1188
+ action: "add",
1189
+ section: syntheticSection,
1190
+ reason: fieldChange.reason,
1191
+ });
1192
+ workingSections.push(workingSyntheticSection);
1193
+ matchedSection = workingSyntheticSection;
1194
+ }
1195
+ const nextField = hydrateFieldFromPatch(fieldChange.field);
1196
+ matchedSection.fields.push(cloneWizardField(nextField));
887
1197
  nextChanges.push({
888
1198
  id: createLocalId("field-suggestion"),
889
1199
  kind: "field",
890
1200
  action: "add",
891
1201
  sectionLocalId: matchedSection.localId,
892
1202
  targetSectionName: matchedSection.name,
893
- field: hydrateFieldFromPatch(fieldChange.field),
1203
+ field: nextField,
894
1204
  reason: fieldChange.reason,
895
1205
  });
896
1206
  continue;
897
1207
  }
1208
+ if (!matchedSection)
1209
+ continue;
898
1210
  const matchedField = matchedSection.fields.find((fieldItem) => normalizeName(fieldItem.name) === normalizeName(fieldChange.targetFieldName));
899
1211
  if (!matchedField)
900
1212
  continue;
901
1213
  if (fieldChange.action === "update") {
1214
+ const updatedField = hydrateFieldFromPatch(fieldChange.field, matchedField);
1215
+ const matchedFieldIndex = matchedSection.fields.findIndex((fieldItem) => fieldItem.localId === matchedField.localId);
1216
+ if (matchedFieldIndex >= 0) {
1217
+ matchedSection.fields[matchedFieldIndex] = cloneWizardField(updatedField);
1218
+ }
902
1219
  nextChanges.push({
903
1220
  id: createLocalId("field-suggestion"),
904
1221
  kind: "field",
905
1222
  action: "update",
906
1223
  sectionLocalId: matchedSection.localId,
907
1224
  targetSectionName: matchedSection.name,
908
- field: hydrateFieldFromPatch(fieldChange.field, matchedField),
1225
+ field: updatedField,
909
1226
  targetFieldLocalId: matchedField.localId,
910
1227
  targetFieldName: matchedField.name,
911
1228
  reason: fieldChange.reason,
912
1229
  });
913
1230
  continue;
914
1231
  }
1232
+ const matchedFieldIndex = matchedSection.fields.findIndex((fieldItem) => fieldItem.localId === matchedField.localId);
1233
+ if (matchedFieldIndex >= 0) {
1234
+ matchedSection.fields.splice(matchedFieldIndex, 1);
1235
+ }
915
1236
  nextChanges.push({
916
1237
  id: createLocalId("field-suggestion"),
917
1238
  kind: "field",
@@ -925,7 +1246,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
925
1246
  });
926
1247
  }
927
1248
  return nextChanges;
928
- }, [hydrateFieldFromPatch, sections]);
1249
+ }, [effectiveSections, hydrateFieldFromPatch]);
929
1250
  const handleAgentMessage = useCallback((message) => {
930
1251
  if (!message.id ||
931
1252
  !message.isCompleted ||
@@ -945,7 +1266,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
945
1266
  const changes = convertSuggestionToPendingChanges(suggestion);
946
1267
  if (changes.length === 0)
947
1268
  return;
948
- setPendingSuggestions((prev) => [...prev, ...changes]);
1269
+ setPendingSuggestions((prev) => mergePendingSuggestionChanges(prev, changes));
949
1270
  setLatestSuggestionSummary(suggestion.summary || null);
950
1271
  setSuggestionStatus(`${changes.length} AI suggestion${changes.length === 1 ? "" : "s"} ready for review.`);
951
1272
  setSuggestionParseError(null);
@@ -1108,14 +1429,14 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1108
1429
  };
1109
1430
  const renderToggle = (checked, onClick) => (_jsx("button", { type: "button", role: "switch", "aria-checked": checked, className: `relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition ${checked ? "bg-blue-600" : "bg-gray-300"}`, onClick: onClick, children: _jsx("span", { className: `inline-block h-4 w-4 transform rounded-full bg-white transition ${checked ? "translate-x-4" : "translate-x-0.5"}` }) }));
1110
1431
  const renderTypeSelect = (value, onChange) => (_jsx("select", { className: cls.select, value: value, onChange: (e) => onChange(e.target.value), children: fieldTypeGroups.map((group) => (_jsx("optgroup", { label: group.name, children: (group.types || []).map((t) => (_jsx("option", { value: t, children: t }, `${group.name}-${t}`))) }, group.name))) }));
1111
- const renderSuggestionActions = (change) => (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", className: "rounded border border-violet-200 bg-white px-2 py-0.5 text-[10px] font-semibold text-violet-700 transition hover:bg-violet-50", onClick: (event) => {
1432
+ const renderSuggestionActions = (change) => (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("button", { type: "button", className: "rounded border border-violet-200 bg-white px-2 py-0.5 text-xs font-semibold text-violet-700 transition hover:bg-violet-50", onClick: (event) => {
1112
1433
  event.stopPropagation();
1113
1434
  void approveSuggestion(change.id);
1114
- }, children: "Approve" }), _jsx("button", { type: "button", className: "rounded border border-gray-200 bg-white px-2 py-0.5 text-[10px] font-semibold text-gray-600 transition hover:bg-gray-50", onClick: (event) => {
1435
+ }, children: "Approve" }), _jsx("button", { type: "button", className: "rounded border border-gray-200 bg-white px-2 py-0.5 text-xs font-semibold text-gray-600 transition hover:bg-gray-50", onClick: (event) => {
1115
1436
  event.stopPropagation();
1116
1437
  clearSuggestion(change.id);
1117
1438
  }, children: "Reject" })] }));
1118
- const renderFooter = () => (_jsxs("div", { className: "mt-auto flex items-center justify-between border-t border-gray-200 px-4 pt-4 pb-1", children: [_jsxs("label", { className: "inline-flex items-center gap-2 text-[11px] text-gray-500 font-medium", children: ["Standard Values", renderToggle(hasStandardValues, () => setHasStandardValues((v) => !v))] }), _jsxs("div", { className: "flex items-center gap-2", children: [onClose && (_jsxs("button", { className: "inline-flex items-center gap-2 rounded border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 transition hover:bg-gray-50", onClick: onClose, disabled: isSaving, children: [_jsx(X, { className: "h-4 w-4" }), "Cancel"] })), _jsxs("button", { className: "inline-flex items-center gap-2 rounded bg-blue-600 px-6 py-2.5 text-sm font-semibold text-white shadow-md transition-all hover:bg-blue-700 hover:shadow-lg active:scale-95 disabled:opacity-50", onClick: save, disabled: isSaving, children: [_jsx(Check, { className: "h-4 w-4" }), isSaving ? "Confirming..." : "Confirm"] })] })] }));
1439
+ const renderFooter = () => (_jsxs(DialogButtons, { className: "mt-auto items-center justify-between border-t bg-gray-50/80 px-4 py-4 backdrop-blur-sm", children: [_jsxs("label", { className: "inline-flex items-center gap-2 text-xs font-medium text-gray-500", children: ["Standard Values", renderToggle(hasStandardValues, () => setHasStandardValues((v) => !v))] }), _jsxs("div", { className: "flex items-center gap-2", children: [onClose && (_jsx(Button, { variant: "ghost", onClick: onClose, disabled: isSaving, children: "Cancel" })), _jsx(Button, { onClick: save, disabled: isSaving, className: "min-w-[140px] shadow-sm", children: isSaving ? (isCreateMode ? "Creating..." : "Updating...") : isCreateMode ? "Create" : "Update" })] })] }));
1119
1440
  /* ────────────────────────────────────────────────────────────
1120
1441
  * Studio Layout
1121
1442
  * Three-column: left = inheritance tree, center = field list,
@@ -1141,27 +1462,63 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1141
1462
  const section = selectedFieldRef?.section;
1142
1463
  const si = selectedFieldRef?.si;
1143
1464
  const fi = selectedFieldRef?.fi;
1144
- return (_jsxs("div", { className: "flex h-full min-h-0 flex-col gap-0 overflow-hidden rounded-lg border border-gray-200 bg-white text-gray-900", children: [isCreateMode && (_jsx("div", { className: "border-b border-gray-100 bg-gray-50/40 px-4 py-3", children: _jsxs("div", { className: "max-w-md", children: [_jsx("div", { className: "mb-1 text-[10px] font-bold uppercase tracking-wider text-gray-400", children: "Template name" }), _jsx("input", { className: cls.input, value: templateName, onChange: (e) => setTemplateName(e.target.value), placeholder: "New Template" })] }) })), _jsxs("div", { className: "grid min-h-0 flex-1 grid-cols-1 gap-0 lg:grid-cols-[240px_1fr_280px_420px]", children: [_jsx("div", { className: "flex flex-col gap-0 overflow-y-auto border-r border-gray-100 bg-gray-50/30", children: _jsxs("div", { className: "flex-1 overflow-y-auto p-3", children: [_jsx("div", { className: "mb-1.5 text-[10px] font-bold uppercase tracking-widest text-gray-400", children: "Template tree" }), _jsx("div", { className: "h-[240px] rounded border border-gray-200 bg-white shadow-inner", children: _jsx(TreeListSelector, { language: activeLanguage, rootItemIds: [TEMPLATES_ROOT_ID], selectedItemIds: selectedTemplateNodesInTree.map((x) => x.id), onSelectionChange: (nodes) => {
1145
- const selected = nodes
1146
- .filter((n) => normalizeGuid(n.templateId) === normalizeGuid(TEMPLATE_TEMPLATE_ID))
1147
- .map((n) => ({ id: n.id, name: n.name, path: n.path, icon: n.icon, idPath: n.idPath }));
1148
- setSelectedTemplateNodesInTree(selected);
1149
- }, onDoubleClick: (node) => {
1150
- if (normalizeGuid(node.templateId) === normalizeGuid(TEMPLATE_TEMPLATE_ID)) {
1151
- addBaseTemplates([{ id: node.id, name: node.name, path: node.path, icon: node.icon, idPath: node.idPath }]);
1152
- }
1153
- }, onItemSelected: async (node) => {
1154
- const sel = await editContext.itemsRepository.getItem({ id: node.id, language: activeLanguage, version: 0 });
1155
- if (sel && normalizeGuid(sel.templateId) === normalizeGuid(TEMPLATE_TEMPLATE_ID)) {
1156
- addBaseTemplates([{ id: sel.id, name: sel.name, path: sel.path, icon: sel.icon, idPath: sel.idPath }]);
1157
- }
1158
- } }) }), _jsxs("div", { className: "mt-3", children: [_jsx("div", { className: "mb-1.5 text-[10px] font-bold uppercase tracking-widest text-gray-400", children: "Inherited templates" }), baseTemplates.length === 0 ? (_jsx("div", { className: "text-[10px] text-gray-400 italic", children: "None" })) : (_jsxs("div", { className: "space-y-1", children: [baseTemplates.map((t) => {
1159
- const templateSuggestions = getBaseTemplateSuggestions(t);
1160
- const hasRemoveSuggestion = templateSuggestions.some((entry) => entry.action === "remove");
1161
- return (_jsxs("div", { className: `space-y-1 rounded border px-2 py-1 text-[11px] ${hasRemoveSuggestion
1162
- ? "border-violet-200 bg-violet-50/80 text-violet-900"
1163
- : "border-gray-200 bg-white text-gray-700"}`, children: [_jsxs("div", { className: "group flex items-center gap-1", children: [t.icon && _jsx("img", { src: t.icon, className: "h-3 w-3 shrink-0" }), _jsx("span", { className: `flex-1 truncate ${hasRemoveSuggestion ? "line-through" : ""}`, children: t.name }), _jsx("button", { className: "text-gray-400 transition hover:text-red-500", onClick: () => removeBaseTemplates([t]), children: _jsx(X, { className: "h-2.5 w-2.5" }) })] }), templateSuggestions.map((entry) => (_jsxs("div", { className: "flex items-center justify-between gap-2 rounded border border-violet-200 bg-white/80 px-2 py-1 text-[10px] text-violet-700", children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: ["AI suggests ", entry.action === "remove" ? "removing" : "adding", " this base template", entry.reason ? ` · ${entry.reason}` : ""] }), renderSuggestionActions(entry)] }, entry.id)))] }, t.id));
1164
- }), pendingBaseTemplateAdditions.map((entry) => (_jsx("div", { className: "rounded border border-dashed border-violet-300 bg-violet-50 px-2 py-1 text-[11px] text-violet-800", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-semibold", children: entry.templateName }), _jsxs("div", { className: "truncate text-[10px] text-violet-600", children: ["AI suggestion", entry.reason ? ` · ${entry.reason}` : ""] })] }), renderSuggestionActions(entry)] }) }, entry.id)))] }))] })] }) }), _jsxs("div", { className: "flex flex-col overflow-y-auto bg-white", children: [_jsx("div", { className: "border-b border-gray-100 bg-gray-50/30 px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2 rounded border border-gray-200 bg-white px-2 py-1.5", children: [_jsx(Search, { className: "h-3.5 w-3.5 text-gray-400" }), _jsx("input", { className: "w-full bg-transparent text-xs text-gray-800 outline-none placeholder:text-gray-400", placeholder: "Search fields or sections...", value: fieldSearchQuery, onChange: (e) => setFieldSearchQuery(e.target.value) })] }) }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [sections.map((sectionItem, si_idx) => {
1465
+ return (_jsxs("div", { className: "flex h-full min-h-0 flex-col gap-0 overflow-hidden rounded-lg border border-gray-200 bg-white text-gray-900", children: [_jsxs("div", { className: "grid min-h-0 flex-1 grid-cols-1 gap-0 lg:grid-cols-[240px_1fr_280px_420px]", children: [_jsx("div", { className: "flex flex-col gap-0 overflow-y-auto border-r border-gray-100 bg-gray-50/30", children: _jsx("div", { className: "flex-1 overflow-y-auto p-3", children: _jsxs("div", { className: "flex min-h-full flex-col", children: [(isCreateMode || item) && (_jsxs("div", { className: "mb-3 border-b border-gray-100 pb-3", children: [_jsx("div", { className: "mb-1 text-xs font-bold uppercase tracking-wider text-gray-400", children: "Template name" }), _jsx("input", { className: cls.input, value: templateName, onChange: (e) => setTemplateName(e.target.value), placeholder: "New Template" })] })), _jsx("div", { className: "mb-1.5 text-xs font-bold uppercase tracking-widest text-gray-400", children: "Base templates" }), _jsxs("div", { className: "space-y-1", children: [baseTemplates.length === 0 && pendingBaseTemplateAdditions.length === 0 && (_jsx("div", { className: "text-xs text-gray-400 italic", children: "None" })), baseTemplates.map((t) => {
1466
+ const templateSuggestions = getBaseTemplateSuggestions(t);
1467
+ const hasRemoveSuggestion = templateSuggestions.some((entry) => entry.action === "remove");
1468
+ return (_jsxs("div", { className: `space-y-1 rounded border px-2 py-1 text-xs ${hasRemoveSuggestion
1469
+ ? "border-violet-200 bg-violet-50/80 text-violet-900"
1470
+ : "border-gray-200 bg-white text-gray-700"}`, children: [_jsxs("div", { className: "group flex items-center gap-1", children: [t.icon && _jsx("img", { src: t.icon, className: "h-3 w-3 shrink-0" }), _jsx("span", { className: `flex-1 truncate ${hasRemoveSuggestion ? "line-through" : ""}`, children: t.name }), _jsx("button", { className: "text-gray-400 transition hover:text-red-500", onClick: () => removeBaseTemplates([t]), children: _jsx(X, { className: "h-2.5 w-2.5" }) })] }), templateSuggestions.map((entry) => (_jsxs("div", { className: "flex items-center justify-between gap-2 rounded border border-violet-200 bg-white/80 px-2 py-1 text-xs text-violet-700", children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: ["AI suggests ", entry.action === "remove" ? "removing" : "adding", " this base template", entry.reason ? ` · ${entry.reason}` : ""] }), renderSuggestionActions(entry)] }, entry.id)))] }, t.id));
1471
+ }), pendingBaseTemplateAdditions.map((entry) => (_jsx("div", { className: "rounded border border-dashed border-violet-300 bg-violet-50 px-2 py-1 text-xs text-violet-800", children: _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "truncate font-semibold", children: entry.templateName }), _jsxs("div", { className: "truncate text-xs text-violet-600", children: ["AI suggestion", entry.reason ? ` · ${entry.reason}` : ""] })] }), renderSuggestionActions(entry)] }) }, entry.id))), _jsx("div", { className: "flex justify-end pt-1", children: _jsxs(Popover, { open: templatePickerOpen, onOpenChange: (nextOpen) => {
1472
+ if (nextOpen && templatePickerTriggerRef.current) {
1473
+ const dialogContent = templatePickerTriggerRef.current.closest('[data-slot="dialog-content"]');
1474
+ setTemplatePickerPortalContainer(dialogContent);
1475
+ }
1476
+ setTemplatePickerOpen(nextOpen);
1477
+ }, enableIframeClickDetection: false, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx(Button, { ref: templatePickerTriggerRef, variant: "default", size: "iconSm", className: "h-7 w-7 rounded-md shadow-sm", title: "Add inherited template", "aria-label": "Add inherited template", children: _jsx(Plus, { className: "h-4 w-4" }) }) }), _jsxs(PopoverContent, { className: "w-[420px] p-0", side: "top", align: "start", container: templatePickerPortalContainer, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: [_jsxs("div", { className: "border-b border-gray-100 px-3 py-2", children: [_jsx("div", { className: "text-xs font-semibold text-gray-700", children: "Select template" }), _jsx("div", { className: "text-xs text-gray-500", children: "Choose a template to add to inherited templates." })] }), _jsx("div", { className: "h-[320px] overflow-hidden rounded-b-md bg-white", children: _jsx(TreeListSelector, { language: activeLanguage, rootItemIds: [TEMPLATES_ROOT_ID], selectedItemIds: selectedTemplateNodesInTree.map((x) => x.id), onSelectionChange: (nodes) => {
1478
+ const selected = nodes
1479
+ .filter((n) => normalizeGuid(n.templateId) ===
1480
+ normalizeGuid(TEMPLATE_TEMPLATE_ID))
1481
+ .map((n) => ({
1482
+ id: n.id,
1483
+ name: n.name,
1484
+ path: n.path,
1485
+ icon: n.icon,
1486
+ idPath: n.idPath,
1487
+ }));
1488
+ setSelectedTemplateNodesInTree(selected);
1489
+ }, onDoubleClick: (node) => {
1490
+ if (normalizeGuid(node.templateId) === normalizeGuid(TEMPLATE_TEMPLATE_ID)) {
1491
+ addBaseTemplates([
1492
+ {
1493
+ id: node.id,
1494
+ name: node.name,
1495
+ path: node.path,
1496
+ icon: node.icon,
1497
+ idPath: node.idPath,
1498
+ },
1499
+ ]);
1500
+ setTemplatePickerOpen(false);
1501
+ }
1502
+ }, onItemSelected: async (node) => {
1503
+ const sel = await editContext.itemsRepository.getItem({
1504
+ id: node.id,
1505
+ language: activeLanguage,
1506
+ version: 0,
1507
+ });
1508
+ if (sel &&
1509
+ normalizeGuid(sel.templateId) === normalizeGuid(TEMPLATE_TEMPLATE_ID)) {
1510
+ addBaseTemplates([
1511
+ {
1512
+ id: sel.id,
1513
+ name: sel.name,
1514
+ path: sel.path,
1515
+ icon: sel.icon,
1516
+ idPath: sel.idPath,
1517
+ },
1518
+ ]);
1519
+ setTemplatePickerOpen(false);
1520
+ }
1521
+ } }) })] })] }) })] })] }) }) }), _jsxs("div", { className: "flex flex-col overflow-y-auto bg-white", children: [_jsx("div", { className: "border-b border-gray-100 bg-gray-50/30 px-3 py-2", children: _jsxs("div", { className: "flex items-center gap-2 rounded border border-gray-200 bg-white px-2 py-1.5", children: [_jsx(Search, { className: "h-3.5 w-3.5 text-gray-400" }), _jsx("input", { className: "w-full bg-transparent text-sm text-gray-800 outline-none placeholder:text-gray-400", placeholder: "Search fields or sections...", value: fieldSearchQuery, onChange: (e) => setFieldSearchQuery(e.target.value) })] }) }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [sections.map((sectionItem, si_idx) => {
1165
1522
  const isSectionDragging = draggedSectionIdx === si_idx;
1166
1523
  const isSectionDragOver = dragOverSectionIdx === si_idx;
1167
1524
  const sectionSuggestions = getSectionSuggestions(sectionItem.localId);
@@ -1227,7 +1584,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1227
1584
  toggleSectionCollapsed(si_idx);
1228
1585
  }, children: isCollapsed ? (_jsx(ChevronRight, { className: "h-3.5 w-3.5" })) : (_jsx(ChevronDown, { className: "h-3.5 w-3.5" })) }), _jsx("input", { className: `flex-1 rounded-md border bg-white px-3 py-1.5 text-sm font-semibold shadow-sm outline-none placeholder:text-gray-400 focus:border-blue-400 focus:ring-2 focus:ring-blue-100 ${sectionSuggestions.length > 0
1229
1586
  ? "border-violet-200 text-violet-900"
1230
- : "border-gray-200 text-gray-900"}`, value: sectionItem.name || "", placeholder: `Section ${si_idx + 1}`, onChange: (e) => updateSectionName(si_idx, e.target.value), onClick: (e) => e.stopPropagation() }), _jsx("span", { className: "text-[10px] text-gray-400", children: sectionItem.fields.length }), _jsxs("div", { className: "relative h-5 w-12 shrink-0", children: [_jsx("div", { className: `absolute inset-0 flex items-center justify-center transition-all duration-150 ${sectionDeleteConfirmIdx === si_idx
1587
+ : "border-gray-200 text-gray-900"}`, value: sectionItem.name || "", placeholder: `Section ${si_idx + 1}`, onChange: (e) => updateSectionName(si_idx, e.target.value), onClick: (e) => e.stopPropagation() }), _jsx("span", { className: "text-xs text-gray-400", children: sectionItem.fields.length }), _jsxs("div", { className: "relative h-5 w-12 shrink-0", children: [_jsx("div", { className: `absolute inset-0 flex items-center justify-center transition-all duration-150 ${sectionDeleteConfirmIdx === si_idx
1231
1588
  ? "scale-90 opacity-0 pointer-events-none"
1232
1589
  : "scale-100 opacity-100"}`, children: _jsx("button", { className: "text-gray-300 transition hover:text-red-500", onClick: (e) => {
1233
1590
  e.stopPropagation();
@@ -1241,7 +1598,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1241
1598
  }, title: "Confirm section delete", "aria-label": "Confirm section delete", children: _jsx(Check, { className: "h-3.5 w-3.5" }) }), _jsx("button", { className: "text-red-500 transition hover:text-red-600", onClick: (e) => {
1242
1599
  e.stopPropagation();
1243
1600
  setSectionDeleteConfirmIdx(null);
1244
- }, title: "Cancel section delete", "aria-label": "Cancel section delete", children: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] })] }), sectionSuggestions.length > 0 && (_jsx("div", { className: "mx-3 mb-2 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[11px] text-violet-800", children: sectionSuggestions.map((entry) => (_jsxs("div", { className: "flex items-center justify-between gap-3 py-1", children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: [entry.action === "remove"
1601
+ }, title: "Cancel section delete", "aria-label": "Cancel section delete", children: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] })] }), sectionSuggestions.length > 0 && (_jsx("div", { className: "mx-3 mb-2 rounded border border-violet-200 bg-violet-50 px-3 py-2 text-xs text-violet-800", children: sectionSuggestions.map((entry) => (_jsxs("div", { className: "flex items-center justify-between gap-3 py-1", children: [_jsxs("span", { className: "min-w-0 flex-1 truncate", children: [entry.action === "remove"
1245
1602
  ? "AI suggests removing this section"
1246
1603
  : `AI suggests renaming this section to "${entry.section.name}"`, entry.reason ? ` · ${entry.reason}` : ""] }), renderSuggestionActions(entry)] }, entry.id))) })), !isCollapsed && (_jsxs("div", { className: "pb-2", children: [_jsxs("div", { className: "space-y-1 px-3", children: [visibleFields.map(({ fld, fi_idx }) => {
1247
1604
  const isSelected = selectedFieldKey?.si === si_idx && selectedFieldKey?.fi === fi_idx;
@@ -1297,11 +1654,11 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1297
1654
  : isSelected
1298
1655
  ? "text-blue-700"
1299
1656
  : "text-gray-700"} ${hasFieldRemovalSuggestion ? "line-through" : ""}`, children: fieldUpdateSuggestion?.field.name ||
1300
- fld.name || (_jsx("span", { className: "font-normal italic text-gray-400", children: "Unnamed" })) }), _jsxs("div", { className: "text-[11px] text-gray-500", children: [fld.type, fld.source ? ` · ${fld.source}` : ""] }), fieldSuggestions.map((entry) => (_jsxs("div", { className: "mt-1 flex items-center justify-between gap-2 text-[10px] text-violet-700", children: [_jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.action === "remove"
1657
+ fld.name || (_jsx("span", { className: "font-normal italic text-gray-400", children: "Unnamed" })) }), _jsxs("div", { className: "text-xs text-gray-500", children: [fld.type, fld.source ? ` · ${fld.source}` : ""] }), fieldSuggestions.map((entry) => (_jsxs("div", { className: "mt-1 flex items-center justify-between gap-2 text-xs text-violet-700", children: [_jsx("span", { className: "min-w-0 flex-1 truncate", children: entry.action === "remove"
1301
1658
  ? "AI suggests removing this field"
1302
- : `AI suggests updating this field${entry.reason ? ` · ${entry.reason}` : ""}` }), renderSuggestionActions(entry)] }, entry.id)))] }), _jsxs("div", { className: "flex items-center gap-2", children: [fld.shared && _jsx("span", { className: "rounded border border-blue-100 bg-blue-50 px-1.5 py-0.5 text-[10px] font-bold text-blue-600", children: "S" }), fld.unversioned && _jsx("span", { className: "rounded border border-amber-100 bg-amber-50 px-1.5 py-0.5 text-[10px] font-bold text-amber-600", children: "U" })] }), _jsx("button", { className: "text-gray-300 transition hover:text-red-500", onClick: (e) => { e.stopPropagation(); removeField(si_idx, fi_idx); }, children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }, fld.localId));
1303
- }), visibleFields.length === 0 && normalizedFieldSearchQuery ? (_jsx("div", { className: "ml-8 px-3 py-2 text-[11px] text-gray-400 italic", children: "No matching fields" })) : null] }), !isSearching &&
1304
- pendingFieldAdditions.map((entry) => (_jsx("div", { className: "mt-2 mr-3 ml-11 rounded border border-dashed border-violet-300 bg-violet-50 px-3 py-2 text-[11px] text-violet-800", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate font-semibold", children: entry.field.name || "Suggested field" }), _jsxs("div", { className: "truncate text-[10px] text-violet-600", children: [entry.field.type, entry.reason ? ` · ${entry.reason}` : ""] })] }), renderSuggestionActions(entry)] }) }, entry.id))), !isSearching && draggedFieldRef ? (_jsx("div", { className: `mt-2 mr-3 ml-11 rounded border border-dashed px-2 py-1.5 text-[10px] transition ${dragOverFieldEndSectionIdx === si_idx
1659
+ : `AI suggests updating this field${entry.reason ? ` · ${entry.reason}` : ""}` }), renderSuggestionActions(entry)] }, entry.id)))] }), _jsxs("div", { className: "flex items-center gap-2", children: [fld.shared && _jsx("span", { className: "rounded border border-blue-100 bg-blue-50 px-1.5 py-0.5 text-xs font-bold text-blue-600", children: "S" }), fld.unversioned && _jsx("span", { className: "rounded border border-amber-100 bg-amber-50 px-1.5 py-0.5 text-xs font-bold text-amber-600", children: "U" })] }), _jsx("button", { className: "text-gray-300 transition hover:text-red-500", onClick: (e) => { e.stopPropagation(); removeField(si_idx, fi_idx); }, children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) })] }, fld.localId));
1660
+ }), visibleFields.length === 0 && normalizedFieldSearchQuery ? (_jsx("div", { className: "ml-8 px-3 py-2 text-xs text-gray-400 italic", children: "No matching fields" })) : null] }), !isSearching &&
1661
+ pendingFieldAdditions.map((entry) => (_jsx("div", { className: "mt-2 mr-3 ml-11 rounded border border-dashed border-violet-300 bg-violet-50 px-3 py-2 text-xs text-violet-800", children: _jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate font-semibold", children: entry.field.name || "Suggested field" }), _jsxs("div", { className: "truncate text-xs text-violet-600", children: [entry.field.type, entry.reason ? ` · ${entry.reason}` : ""] })] }), renderSuggestionActions(entry)] }) }, entry.id))), !isSearching && draggedFieldRef ? (_jsx("div", { className: `mt-2 mr-3 ml-11 rounded border border-dashed px-2 py-1.5 text-xs transition ${dragOverFieldEndSectionIdx === si_idx
1305
1662
  ? "border-blue-300 bg-blue-50 text-blue-600"
1306
1663
  : "border-gray-200 bg-white text-gray-400"}`, onDragOver: (e) => {
1307
1664
  e.preventDefault();
@@ -1313,10 +1670,10 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1313
1670
  setDraggedFieldRef(null);
1314
1671
  setDragOverFieldRef(null);
1315
1672
  setDragOverFieldEndSectionIdx(null);
1316
- }, children: "Drop field here to place at end" })) : !isSearching ? (_jsxs("div", { className: "mt-2 mr-3 ml-11 flex items-center gap-2", children: [_jsx("input", { ref: (el) => { newFieldNameInputRefs.current[si_idx] = el; }, className: "flex-1 rounded border border-gray-200 bg-white px-2 py-1.5 text-xs text-gray-800 outline-none placeholder:text-gray-400 focus:border-blue-400", placeholder: "Add field...", value: getFieldDraft(si_idx).name, onChange: (e) => updateFieldDraft(si_idx, { name: e.target.value }), onKeyDown: (e) => { if (e.key === "Enter")
1317
- appendFieldToSection(si_idx); } }), _jsx("button", { className: "rounded bg-blue-600 p-1.5 text-white transition hover:bg-blue-700 shadow-sm", onClick: () => appendFieldToSection(si_idx), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })) : null] }))] }, sectionItem.localId));
1673
+ }, children: "Drop field here to place at end" })) : !isSearching ? (_jsxs("div", { className: "mt-2 mr-3 ml-11 flex items-center gap-2", children: [_jsx("input", { ref: (el) => { newFieldNameInputRefs.current[si_idx] = el; }, className: "flex-1 rounded border border-gray-200 bg-white px-2 py-1.5 text-sm text-gray-800 outline-none placeholder:text-gray-400 focus:border-blue-400", placeholder: "Add field...", value: getFieldDraft(si_idx).name, onChange: (e) => updateFieldDraft(si_idx, { name: e.target.value }), onKeyDown: (e) => { if (e.key === "Enter")
1674
+ appendFieldToSection(si_idx); } }), _jsx("button", { className: "rounded bg-theme-secondary p-1.5 text-white transition hover:bg-theme-secondary/90 shadow-sm", onClick: () => appendFieldToSection(si_idx), children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })) : null] }))] }, sectionItem.localId));
1318
1675
  }), !isSearching &&
1319
- pendingSectionAdditions.map((entry) => (_jsx("div", { className: "mx-3 mt-2 rounded border border-dashed border-violet-300 bg-violet-50 px-3 py-3 text-violet-900", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-semibold", children: entry.section.name || "Suggested section" }), _jsxs("div", { className: "text-[11px] text-violet-700", children: ["AI section suggestion", entry.reason ? ` · ${entry.reason}` : ""] }), entry.section.fields.length > 0 && (_jsx("div", { className: "mt-2 space-y-1", children: entry.section.fields.map((field) => (_jsxs("div", { className: "rounded border border-violet-200 bg-white/70 px-2 py-1 text-[10px] text-violet-700", children: [field.name || "Suggested field", " \u00B7 ", field.type] }, field.localId))) }))] }), renderSuggestionActions(entry)] }) }, entry.id))), !isSearching && draggedSectionIdx !== null ? (_jsx("div", { className: `mx-3 mt-2 mb-3 rounded border border-dashed px-2 py-1.5 text-[10px] transition ${isDragOverSectionEnd
1676
+ pendingSectionAdditions.map((entry) => (_jsx("div", { className: "mx-3 mt-2 rounded border border-dashed border-violet-300 bg-violet-50 px-3 py-3 text-violet-900", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "truncate text-sm font-semibold", children: entry.section.name || "Suggested section" }), _jsxs("div", { className: "text-xs text-violet-700", children: ["AI section suggestion", entry.reason ? ` · ${entry.reason}` : ""] }), entry.section.fields.length > 0 && (_jsx("div", { className: "mt-2 space-y-1", children: entry.section.fields.map((field) => (_jsxs("div", { className: "rounded border border-violet-200 bg-white/70 px-2 py-1 text-xs text-violet-700", children: [field.name || "Suggested field", " \u00B7 ", field.type] }, field.localId))) }))] }), renderSuggestionActions(entry)] }) }, entry.id))), !isSearching && draggedSectionIdx !== null ? (_jsx("div", { className: `mx-3 mt-2 mb-3 rounded border border-dashed px-2 py-1.5 text-xs transition ${isDragOverSectionEnd
1320
1677
  ? "border-blue-300 bg-blue-50 text-blue-600"
1321
1678
  : "border-gray-200 bg-white text-gray-400"}`, onDragOver: (e) => {
1322
1679
  e.preventDefault();
@@ -1330,7 +1687,7 @@ export function TemplateStructureInlineEditor({ item, parentItem, initialName, i
1330
1687
  setDraggedSectionIdx(null);
1331
1688
  setDragOverSectionIdx(null);
1332
1689
  setIsDragOverSectionEnd(false);
1333
- }, children: "Drop section here to place at end" })) : !isSearching ? (_jsxs("div", { className: "mx-3 mt-2 mb-3 flex items-center gap-2", children: [_jsx("input", { className: "flex-1 rounded border border-gray-200 bg-white px-2 py-1 text-xs text-gray-800 outline-none placeholder:text-gray-400 focus:border-blue-400", placeholder: "New section...", value: newSectionName, onChange: (e) => setNewSectionName(e.target.value), onKeyDown: (e) => { if (e.key === "Enter")
1334
- appendSection(); } }), _jsx("button", { className: "rounded bg-blue-600 p-1 text-white transition hover:bg-blue-700 shadow-sm", onClick: appendSection, children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })) : null] })] }), _jsxs("div", { className: "flex flex-col overflow-y-auto border-l border-gray-100 bg-gray-50/20", children: [_jsx("div", { className: "border-b border-gray-100 px-4 py-2 bg-gray-50/30", children: _jsxs("div", { className: "flex items-center gap-2 text-xs font-bold text-gray-500 uppercase tracking-wider", children: [_jsx(Settings2, { className: "h-3.5 w-3.5" }), " Properties"] }) }), field && section && si !== undefined && fi !== undefined ? (_jsxs("div", { className: "space-y-4 p-4", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[10px] font-bold uppercase tracking-wider text-gray-400", children: "Name" }), _jsx("input", { className: cls.input, value: field.name, onChange: (e) => updateField(si, fi, { name: e.target.value }) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[10px] font-bold uppercase tracking-wider text-gray-400", children: "Type" }), renderTypeSelect(field.type, (v) => updateField(si, fi, { type: v }))] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[10px] font-bold uppercase tracking-wider text-gray-400", children: "Source" }), _jsx("input", { className: cls.input, placeholder: "Optional", value: field.source, onChange: (e) => updateField(si, fi, { source: e.target.value }) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[10px] font-bold uppercase tracking-wider text-gray-400", children: "Short description" }), _jsx("input", { className: cls.input, placeholder: "Optional", value: field.shortDescription, onChange: (e) => updateField(si, fi, { shortDescription: e.target.value }) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-[10px] font-bold uppercase tracking-wider text-gray-400", children: "Default value" }), _jsx("input", { className: cls.input, placeholder: "Optional", value: field.defaultValue, onChange: (e) => updateField(si, fi, { defaultValue: e.target.value }) })] }), _jsxs("div", { className: "space-y-3 border-t border-gray-100 pt-3", children: [_jsxs("label", { className: "flex items-center justify-between text-xs text-gray-600 font-medium", children: [_jsx("span", { children: "Shared" }), renderToggle(field.shared, () => updateField(si, fi, { shared: !field.shared }))] }), _jsxs("label", { className: "flex items-center justify-between text-xs text-gray-600 font-medium", children: [_jsx("span", { children: "Unversioned" }), renderToggle(field.unversioned, () => updateField(si, fi, { unversioned: !field.unversioned }))] })] }), _jsxs("button", { className: "mt-2 flex w-full items-center justify-center gap-1.5 rounded-md border border-red-200 bg-red-50 py-2 text-xs font-semibold text-red-600 transition hover:bg-red-100", onClick: () => { removeField(si, fi); setSelectedFieldKey(null); }, children: [_jsx(Trash2, { className: "h-3.5 w-3.5" }), " Remove field"] })] })) : (_jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-2 p-6 text-gray-300", children: [_jsx(Settings2, { className: "h-8 w-8" }), _jsx("p", { className: "text-xs font-medium", children: "Select a field to inspect" })] }))] }), _jsxs("div", { className: "flex min-h-0 flex-col border-l border-gray-100 bg-white", children: [_jsx("div", { className: "border-b border-gray-100 bg-gray-50/30 px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-2 text-xs font-bold uppercase tracking-wider text-gray-500", children: [_jsx(Bot, { className: "h-3.5 w-3.5" }), " Template Builder AI"] }) }), _jsxs("div", { className: "border-b border-gray-100 px-4 py-3", children: [latestSuggestionSummary && (_jsxs("div", { className: "rounded border border-violet-200 bg-violet-50 px-3 py-2 text-[11px] text-violet-800", children: [_jsx("span", { className: "font-semibold", children: "Latest suggestion:" }), " ", latestSuggestionSummary] })), suggestionStatus && (_jsx("div", { className: "mt-2 text-[11px] text-gray-500", children: suggestionStatus })), suggestionParseError && (_jsxs("div", { className: "mt-2 rounded border border-red-200 bg-red-50 px-3 py-2 text-[11px] text-red-700", children: ["Failed to parse AI response: ", suggestionParseError] })), pendingSuggestions.length > 0 && (_jsxs("div", { className: "mt-2 text-[11px] text-gray-600", children: [pendingSuggestions.length, " pending suggestion", pendingSuggestions.length === 1 ? "" : "s", " highlighted in purple."] }))] }), _jsx("div", { className: "min-h-0 flex-1", children: _jsx(AgentTerminal, { agentStub: templateBuilderAgent, profiles: effectiveAiProfiles, compact: true, simpleMode: true, hideContext: true, defaultCollapseJson: true, initialMetadata: templateBuilderAgentMetadata, onMessage: handleAgentMessage, className: "h-full" }) })] })] }), renderFooter()] }));
1690
+ }, children: "Drop section here to place at end" })) : !isSearching ? (_jsxs("div", { className: "mx-3 mt-2 mb-3 flex items-center gap-2", children: [_jsx("input", { className: "flex-1 rounded border border-gray-200 bg-white px-2 py-1 text-sm text-gray-800 outline-none placeholder:text-gray-400 focus:border-blue-400", placeholder: "New section...", value: newSectionName, onChange: (e) => setNewSectionName(e.target.value), onKeyDown: (e) => { if (e.key === "Enter")
1691
+ appendSection(); } }), _jsx("button", { className: "rounded bg-theme-secondary p-1 text-white transition hover:bg-theme-secondary/90 shadow-sm", onClick: appendSection, children: _jsx(Plus, { className: "h-3.5 w-3.5" }) })] })) : null] })] }), _jsxs("div", { className: "flex flex-col overflow-y-auto border-l border-gray-100 bg-gray-50/20", children: [_jsx("div", { className: "border-b border-gray-100 px-4 py-2 bg-gray-50/30", children: _jsxs("div", { className: "flex items-center gap-2 text-xs font-bold text-gray-500 uppercase tracking-wider", children: [_jsx(Settings2, { className: "h-3.5 w-3.5" }), " Properties"] }) }), field && section && si !== undefined && fi !== undefined ? (_jsxs("div", { className: "space-y-4 p-4", children: [_jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-bold uppercase tracking-wider text-gray-400", children: "Name" }), _jsx("input", { className: cls.input, value: field.name, onChange: (e) => updateField(si, fi, { name: e.target.value }) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-bold uppercase tracking-wider text-gray-400", children: "Type" }), renderTypeSelect(field.type, (v) => updateField(si, fi, { type: v }))] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-bold uppercase tracking-wider text-gray-400", children: "Source" }), _jsx("input", { className: cls.input, placeholder: "Optional", value: field.source, onChange: (e) => updateField(si, fi, { source: e.target.value }) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-bold uppercase tracking-wider text-gray-400", children: "Short description" }), _jsx("input", { className: cls.input, placeholder: "Optional", value: field.shortDescription, onChange: (e) => updateField(si, fi, { shortDescription: e.target.value }) })] }), _jsxs("div", { children: [_jsx("div", { className: "mb-1 text-xs font-bold uppercase tracking-wider text-gray-400", children: "Default value" }), _jsx("input", { className: cls.input, placeholder: "Optional", value: field.defaultValue, onChange: (e) => updateField(si, fi, { defaultValue: e.target.value }) })] }), _jsxs("div", { className: "space-y-3 border-t border-gray-100 pt-3", children: [_jsxs("label", { className: "flex items-center justify-between text-xs text-gray-600 font-medium", children: [_jsx("span", { children: "Shared" }), renderToggle(field.shared, () => updateField(si, fi, { shared: !field.shared }))] }), _jsxs("label", { className: "flex items-center justify-between text-xs text-gray-600 font-medium", children: [_jsx("span", { children: "Unversioned" }), renderToggle(field.unversioned, () => updateField(si, fi, { unversioned: !field.unversioned }))] })] }), _jsxs("button", { className: "mt-2 flex w-full items-center justify-center gap-1.5 rounded-md border border-red-200 bg-red-50 py-2 text-xs font-semibold text-red-600 transition hover:bg-red-100", onClick: () => { removeField(si, fi); setSelectedFieldKey(null); }, children: [_jsx(Trash2, { className: "h-3.5 w-3.5" }), " Remove field"] })] })) : (_jsxs("div", { className: "flex flex-1 flex-col items-center justify-center gap-2 p-6 text-gray-300", children: [_jsx(Settings2, { className: "h-8 w-8" }), _jsx("p", { className: "text-xs font-medium", children: "Select a field to inspect" })] }))] }), _jsxs("div", { className: "flex min-h-0 flex-col border-l border-gray-100 bg-white", children: [_jsx("div", { className: "border-b border-gray-100 bg-gray-50/30 px-4 py-2", children: _jsxs("div", { className: "flex items-center gap-2 text-xs font-bold uppercase tracking-wider text-gray-500", children: [_jsx(Bot, { className: "h-3.5 w-3.5" }), " Template Builder AI"] }) }), _jsxs("div", { className: "border-b border-gray-100 px-4 py-3", children: [latestSuggestionSummary && (_jsxs("div", { className: "rounded border border-violet-200 bg-violet-50 px-3 py-2 text-xs text-violet-800", children: [_jsx("span", { className: "font-semibold", children: "Latest suggestion:" }), " ", latestSuggestionSummary] })), suggestionStatus && (_jsx("div", { className: "mt-2 text-xs text-gray-500", children: suggestionStatus })), suggestionParseError && (_jsxs("div", { className: "mt-2 rounded border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700", children: ["Failed to parse AI response: ", suggestionParseError] })), pendingSuggestions.length > 0 && (_jsxs("div", { className: "mt-2 text-xs text-gray-600", children: [pendingSuggestions.length, " pending suggestion", pendingSuggestions.length === 1 ? "" : "s", " highlighted in purple."] }))] }), _jsx("div", { className: "min-h-0 flex-1", children: _jsx(AgentTerminal, { agentStub: templateBuilderAgent, profiles: effectiveAiProfiles, compact: true, simpleMode: true, hideContext: true, defaultCollapseJson: true, initialMetadata: templateBuilderAgentMetadata, onMessage: handleAgentMessage, className: "h-full" }) })] })] }), renderFooter()] }));
1335
1692
  }
1336
1693
  //# sourceMappingURL=TemplateStructureInlineEditor.js.map